001: /*
002: * Copyright 2005-2006 The Kuali Foundation.
003: *
004: *
005: * Licensed under the Educational Community License, Version 1.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.opensource.org/licenses/ecl1.php
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package edu.iu.uis.eden.routetemplate;
018:
019: import java.util.ArrayList;
020: import java.util.Collections;
021: import java.util.List;
022: import java.util.Map;
023:
024: import javax.xml.xpath.XPathExpressionException;
025:
026: import org.apache.commons.lang.ObjectUtils;
027: import org.apache.log4j.Logger;
028:
029: import edu.iu.uis.eden.routeheader.DocumentContent;
030:
031: /**
032: * Generic base class that implements common functionality to simplify implementing
033: * a WorkflowAttribute. This includes simplified template methods, as well as a generic
034: * attribute content model.
035: *
036: * <p>Control flow (for isMatch):</p>
037: *
038: * <ol>
039: * <li>{@link #isMatch(DocumentContent, List)}
040: * <ol>
041: * <li>{@link #isMatch(List, List)}
042: * <ol>
043: * <li>{@link #isMatch(Map, List)}</li>
044: * </ol>
045: * </li>
046: * </ol>
047: * </li>
048: * </ol>
049: *
050: * The default matching algorithm will match:
051: * <blockquote><i>if any single attribute's properties are a match for all rule extension values</i></blockquote>
052: * This implementation does not (yet!) implement a generic internal map of properties, so it is up to subclasses
053: * to expose specific named getters/setters to set data on an attribute of this ancestry.
054: *
055: * @author Aaron Hamid (arh14 at cornell dot edu)
056: */
057: public abstract class GenericWorkflowAttribute extends
058: AbstractWorkflowAttribute {
059: protected final Logger log = Logger.getLogger(getClass());
060: protected final String attributeName;
061: protected final GenericAttributeContent content;
062:
063: public GenericWorkflowAttribute() {
064: this (null); // can't do getClass().getName() so we'll have to pass null...shame
065: }
066:
067: public GenericWorkflowAttribute(String uniqueName) {
068: if (uniqueName != null) {
069: this .attributeName = uniqueName;
070: } else {
071: this .attributeName = getClass().getName();
072: }
073: content = new GenericAttributeContent(attributeName);
074: }
075:
076: /**
077: * Template method for subclasses to override to expose attribute state
078: * @return map exposing attribute state
079: */
080: public abstract Map<String, String> getProperties();
081:
082: /**
083: * Simply defers to GenericAttributeContent to generate suitable XML content in a standard fashion
084: */
085: public String getDocContent() {
086: String dc = content.generateContent(getProperties());
087: //log.info("Generating doc content: " + dc, new Exception("Dummy exception"));
088: return dc;
089: }
090:
091: public boolean isMatch(DocumentContent docContent,
092: List<RuleExtension> ruleExtensions) {
093: log.info("isMatch: " + docContent + " " + ruleExtensions);
094: try {
095: // could be multiple attributes on the incoming doc content!
096: List<Map<String, String>> propertiesList = content
097: .parseContent(docContent.getAttributeContent());
098:
099: return isMatch(propertiesList, ruleExtensions);
100: } catch (XPathExpressionException xpee) {
101: String message = "Error parsing attribute '"
102: + attributeName + "' content: "
103: + docContent.getDocContent();
104: log.error(message, xpee);
105: throw new RuntimeException(xpee);
106: }
107: }
108:
109: /**
110: * Returns true if any single incoming attribute's properties are a match for all rule extension values
111: * @param propertiesList the list of incoming attributes' properties
112: * @param ruleExtensions the rule extensions
113: * @return true if any single attribute's properties are a match for all rule extension values
114: */
115: protected boolean isMatch(List<Map<String, String>> propertiesList,
116: List<RuleExtension> ruleExtensions) {
117: for (Map<String, String> properties : propertiesList) {
118: return isMatch(properties, ruleExtensions);
119: }
120: return false;
121: }
122:
123: /**
124: * Returns true if all key/value pairs defined by the specified rule extensions are present in the incoming attribute's
125: * properties
126: * @param properties incoming attribute's properties
127: * @param ruleExtensions list of rule extensions
128: * @return true if all key/value pairs defined by the specified rule extensions are present in the incoming attribute's
129: */
130: protected boolean isMatch(Map<String, String> properties,
131: List<RuleExtension> ruleExtensions) {
132: for (RuleExtension ruleExtension : ruleExtensions) {
133: for (RuleExtensionValue ruleExtensionValue : ruleExtension
134: .getExtensionValues()) {
135: if (!ObjectUtils.equals(ruleExtensionValue.getValue(),
136: properties.get(ruleExtensionValue.getKey()))) {
137: return false;
138: }
139: }
140: }
141: return true;
142: }
143:
144: /**
145: * These guys should probably be implemented to set the parameters on an internal member property map this attribute
146: * should use to contain all properties set on it, like StandardGenericXmlAttribute.
147: * @see #getProperties()
148: * TODO: implement me!
149: */
150: public List validateRoutingData(Map paramMap) {
151: return Collections.EMPTY_LIST;
152: }
153:
154: public List validateRuleData(Map paramMap) {
155: return Collections.EMPTY_LIST;
156: }
157:
158: //public List validateClientRouting....
159:
160: /**
161: * I think the job of this method is to marshal the current state of the attribute into a representative list of rule extension
162: * values. On that assumption, this method should simply create a list of RuleExtensionValues based on the the property map
163: * this attribute uses to hold property values.
164: *
165: * TODO: this is not fully implemented! e.g. generic property map like StandardGenericXmlAttribute
166: */
167: public List<RuleExtensionValue> getRuleExtensionValues() {
168: log.info("getRuleExtensionValues");
169: List<RuleExtensionValue> exts = new ArrayList<RuleExtensionValue>();
170: Map<String, String> props = getProperties();
171: for (Map.Entry<String, String> entry : props.entrySet()) {
172: RuleExtensionValue ruleVal = new RuleExtensionValue();
173: ruleVal.setKey(entry.getKey());
174: ruleVal.setValue(entry.getValue());
175: exts.add(ruleVal);
176: }
177: return exts;
178: }
179: }
|