View Javadoc
1   /**
2    * Copyright 2005-2016 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krms.impl.ui;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
20  import org.kuali.rice.core.api.util.ConcreteKeyValue;
21  import org.kuali.rice.core.api.util.KeyValue;
22  import org.kuali.rice.krad.uif.control.UifKeyValuesFinderBase;
23  import org.kuali.rice.krad.uif.view.ViewModel;
24  import org.kuali.rice.krad.web.form.MaintenanceDocumentForm;
25  import org.kuali.rice.krms.api.KrmsApiServiceLocator;
26  import org.kuali.rice.krms.api.repository.RuleManagementService;
27  import org.kuali.rice.krms.api.repository.context.ContextDefinition;
28  import org.kuali.rice.krms.api.repository.function.FunctionDefinition;
29  import org.kuali.rice.krms.api.repository.operator.CustomOperator;
30  import org.kuali.rice.krms.api.repository.type.KrmsTypeDefinition;
31  import org.kuali.rice.krms.api.repository.type.KrmsTypeRepositoryService;
32  import org.kuali.rice.krms.api.repository.typerelation.RelationshipType;
33  import org.kuali.rice.krms.api.repository.typerelation.TypeTypeRelation;
34  import org.kuali.rice.krms.framework.engine.expression.ComparisonOperator;
35  import org.kuali.rice.krms.impl.util.KrmsImplConstants;
36  import org.kuali.rice.krms.impl.util.KrmsServiceLocatorInternal;
37  
38  import javax.xml.namespace.QName;
39  import java.util.ArrayList;
40  import java.util.Collections;
41  import java.util.List;
42  
43  /**
44   * ValueFinder for the operators available while editing a proposition.
45   *
46   * <p>Fetches the KeyValues for the operators available for use in propositions within the current context.</p>
47   *
48   * @author Kuali Rice Team (rice.collab@kuali.org)
49   */
50  public class PropositionOpCodeValuesFinder extends UifKeyValuesFinderBase {
51  
52      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(PropositionOpCodeValuesFinder.class);
53  
54      private static final List<KeyValue> LABELS;
55  
56      static {
57          final List<KeyValue> labels = new ArrayList<KeyValue>( ComparisonOperator.values().length );
58          for (ComparisonOperator operator : ComparisonOperator.values()) {
59              labels.add(new ConcreteKeyValue(operator.getCode(), operator.getCode()));
60          }
61  
62          LABELS = Collections.unmodifiableList(labels);
63      }
64  
65      /**
66       * @see UifKeyValuesFinderBase#getKeyValues(org.kuali.rice.krad.uif.view.ViewModel)
67       */
68      @Override
69      public List<KeyValue> getKeyValues(ViewModel model) {
70  
71          List<KeyValue> keyValues = new ArrayList<KeyValue>(LABELS);
72  
73          MaintenanceDocumentForm maintenanceForm = (MaintenanceDocumentForm) model;
74          AgendaEditor agendaEditor =
75                  (AgendaEditor) maintenanceForm.getDocument().getNewMaintainableObject().getDataObject();
76  
77          // context should never be null as otherwise rule editing would not be allowed
78          ContextDefinition context = getRuleManagementService().getContext(agendaEditor.getAgenda().getContextId());
79  
80          keyValues.addAll(getCustomOperatorsKeyValuesForContextType(context.getTypeId()));
81  
82          return keyValues;
83      }
84  
85      /**
86       * Gets the {@link KeyValue}s for the {@link CustomOperator}s allowed to be used by the given context type.
87       *
88       * @param contextTypeId the context's type id
89       * @return the KeyValue list for the allowed custom operator types
90       */
91      private List<KeyValue> getCustomOperatorsKeyValuesForContextType(String contextTypeId) {
92          List<KeyValue> keyValues = new ArrayList<KeyValue>();
93  
94          if (contextTypeId == null) {
95              return keyValues;
96          }
97  
98          // Runtime checking for the CustomOperator service interface needs to be done
99          List<TypeTypeRelation> typeRelations =
100                 getTypeRepositoryService().findTypeTypeRelationsByFromType(contextTypeId);
101 
102         for (TypeTypeRelation typeRelation : typeRelations) {
103             if (typeRelation.getRelationshipType().equals(RelationshipType.USAGE_ALLOWED)) {
104                 KrmsTypeDefinition krmsType = getTypeRepositoryService().getTypeById(typeRelation.getToTypeId());
105 
106                 Object service = getTypeServiceImplementation(krmsType);
107 
108                 if (service != null && service instanceof CustomOperator) {
109                     // Bingo, we have a custom operator to add to the list
110                     keyValues.add(getKeyValueForCustomOperator(krmsType, (CustomOperator)service));
111                 }
112             }
113         }
114 
115         return keyValues;
116     }
117 
118     /**
119      * Gets the KeyValue for the given custom operator and corresponding KRMS type.
120      *
121      * <p>A special convention is used for the key values: {@code customOperator:<nameSpace>:<serviceName>}</p>
122      * <p>Values are the function name, which is what will be displayed in the operator dropdown.</p>
123      *
124      * @param krmsType the krms type for the given customOperator
125      * @param customOperator the custom operator, assumed to be not null
126      * @return a KeyValue
127      */
128     private ConcreteKeyValue getKeyValueForCustomOperator(KrmsTypeDefinition krmsType, CustomOperator customOperator) {
129         FunctionDefinition operatorFunctionDefinition =
130                 customOperator.getOperatorFunctionDefinition();
131         String key = KrmsImplConstants.CUSTOM_OPERATOR_PREFIX
132                 + krmsType.getNamespace() +
133                 ":" + krmsType.getServiceName();
134 
135         return new ConcreteKeyValue(key, operatorFunctionDefinition.getName());
136     }
137 
138     /**
139      * Returns the service for the given KRMS type, or null if none can be found.
140      *
141      * @param krmsType the type to return the service for
142      * @return the service or null if none can be found
143      */
144     private Object getTypeServiceImplementation(KrmsTypeDefinition krmsType) {
145         Object service = null;
146 
147         if (krmsType != null && !StringUtils.isEmpty(krmsType.getServiceName())) {
148             QName serviceQName = new QName(krmsType.getNamespace(), krmsType.getServiceName());
149             service = GlobalResourceLoader.getService(serviceQName);
150         }
151 
152         return service;
153     }
154 
155     /**
156      * lazy initialization holder class idiom, see Effective Java 2nd Ed. item # 71, J. Bloch
157      */
158     private static class TypeRepositoryServiceHolder {
159         static final KrmsTypeRepositoryService typeRepositoryService =
160                 KrmsApiServiceLocator.getKrmsTypeRepositoryService();
161     }
162 
163     // getter for lazy init service
164     private KrmsTypeRepositoryService getTypeRepositoryService() {
165         return TypeRepositoryServiceHolder.typeRepositoryService;
166     }
167 
168     /**
169      * lazy initialization holder class idiom, see Effective Java 2nd Ed. item # 71, J. Bloch
170      */
171     private static class RuleManagementServiceHolder {
172         static final RuleManagementService ruleManagementService = KrmsServiceLocatorInternal.getService(
173                 "ruleManagementService");
174     }
175 
176     // getter for lazy init service
177     private RuleManagementService getRuleManagementService() {
178         return RuleManagementServiceHolder.ruleManagementService;
179     }
180 
181 }