001: package org.drools.repository;
002:
003: import java.util.ArrayList;
004: import java.util.List;
005:
006: import javax.jcr.ItemNotFoundException;
007: import javax.jcr.Node;
008: import javax.jcr.PathNotFoundException;
009: import javax.jcr.Property;
010: import javax.jcr.RepositoryException;
011: import javax.jcr.UnsupportedRepositoryOperationException;
012: import javax.jcr.Value;
013: import javax.jcr.ValueFormatException;
014: import javax.jcr.lock.LockException;
015: import javax.jcr.nodetype.ConstraintViolationException;
016: import javax.jcr.version.VersionException;
017:
018: /**
019: * This contains logic for categorisable items
020: * (not all versionably items are categorisable).
021: *
022: * @author michael neale
023: *
024: */
025: public abstract class CategorisableItem extends VersionableItem {
026:
027: public CategorisableItem(RulesRepository rulesRepository, Node node) {
028: super (rulesRepository, node);
029: }
030:
031: /**
032: * Adds the specified tag to this object's node. Tags are stored as nodes in a tag area of
033: * the repository. If the specified tag does not already have a corresponding node, a node is
034: * created for it.
035: *
036: * Please note that this is mainly intended for rule related assets, not packages
037: * (although it could be used).
038: *
039: * @param tag the tag to add to the rule. rules can have multiple tags
040: * @throws RulesRepositoryException
041: */
042: public void addCategory(String tag) throws RulesRepositoryException {
043: try {
044: //make sure this object's node is the head version
045: checkIsUpdateable();
046:
047: CategoryItem tagItem = this .rulesRepository
048: .loadCategory(tag);
049:
050: //now set the tag property of the rule
051: Property tagReferenceProperty;
052: int i = 0;
053: Value[] newTagValues = null;
054: try {
055: tagReferenceProperty = this .node
056: .getProperty(CATEGORY_PROPERTY_NAME);
057: Value[] oldTagValues = tagReferenceProperty.getValues();
058:
059: //first, make sure this tag wasn't already there. while we're at it, lets copy the array
060: newTagValues = new Value[oldTagValues.length + 1];
061: for (i = 0; i < oldTagValues.length; i++) {
062: if (oldTagValues[i].getString().equals(tag)) {
063: log.info("tag '" + tag
064: + "' already existed for rule node: "
065: + this .node.getName());
066: return;
067: }
068: newTagValues[i] = oldTagValues[i];
069: }
070: } catch (PathNotFoundException e) {
071: //the property doesn't exist yet, so create it in the finally block
072: newTagValues = new Value[1];
073: } finally {
074: if (newTagValues != null) {
075: newTagValues[i] = this .node.getSession()
076: .getValueFactory().createValue(
077: tagItem.getNode());
078: updateCategories(newTagValues);
079: } else {
080: log
081: .error("reached expected path of execution when adding tag '"
082: + tag
083: + "' to ruleNode: "
084: + this .node.getName());
085: }
086: }
087: } catch (Exception e) {
088: log.error("Caught exception", e);
089: throw new RulesRepositoryException(e);
090: }
091: }
092:
093: private void updateCategories(Value[] newTagValues)
094: throws UnsupportedRepositoryOperationException,
095: LockException, RepositoryException, ValueFormatException,
096: VersionException, ConstraintViolationException {
097: this .node.checkout();
098: this .node.setProperty(CATEGORY_PROPERTY_NAME, newTagValues);
099: }
100:
101: /**
102: * This method sets the categories in one hit, making the
103: * ASSUMPTION that the categories were previously set up !
104: * (via CategoryItem of course !).
105: */
106: public void updateCategoryList(String[] categories) {
107: this .checkIsUpdateable();
108: try {
109: Value[] newCats = new Value[categories.length];
110: for (int i = 0; i < categories.length; i++) {
111: CategoryItem item = this .rulesRepository
112: .loadCategory(categories[i]);
113:
114: newCats[i] = this .node.getSession().getValueFactory()
115: .createValue(item.getNode());
116:
117: }
118: updateCategories(newCats);
119: } catch (RepositoryException e) {
120: throw new RulesRepositoryException(e);
121: }
122: }
123:
124: /**
125: * Gets a list of CategoryItem objects for this assets node.
126: *
127: * @return a list of TagItem objects for each tag on the rule. If there are no tags, an empty list.
128: * @throws RulesRepositoryException
129: */
130: public List getCategories() throws RulesRepositoryException {
131: try {
132: Node ruleNode = getVersionContentNode();
133:
134: List returnList = new ArrayList();
135: try {
136: Property tagReferenceProperty = ruleNode
137: .getProperty(CATEGORY_PROPERTY_NAME);
138: Value[] tagValues = tagReferenceProperty.getValues();
139: for (int i = 0; i < tagValues.length; i++) {
140: try {
141: Node tagNode = this .node
142: .getSession()
143: .getNodeByUUID(tagValues[i].getString());
144: CategoryItem tagItem = new CategoryItem(
145: this .rulesRepository, tagNode);
146: returnList.add(tagItem);
147: } catch (ItemNotFoundException e) {
148: //ignore
149: log
150: .debug("Was unable to load a category by UUID - must have been removed.");
151: }
152: }
153: } catch (PathNotFoundException e) {
154: //the property doesn't even exist yet, so just return nothing
155: }
156: return returnList;
157: } catch (RepositoryException e) {
158: log.error("Error loading cateories", e);
159: throw new RulesRepositoryException(e);
160: }
161: }
162:
163: /**
164: * Removes the specified tag from this object's rule node.
165: *
166: * @param tag the tag to remove from the rule
167: * @throws RulesRepositoryException
168: */
169: public void removeCategory(String tag)
170: throws RulesRepositoryException {
171: try {
172: //make sure this object's node is the head version
173: if (this .node.getPrimaryNodeType().getName().equals(
174: "nt:version")) {
175: String message = "Error. Tags can only be removed from the head version of a rule node";
176: log.error(message);
177: throw new RulesRepositoryException(message);
178: }
179:
180: //now set the tag property of the rule
181: Property tagReferenceProperty;
182: int i = 0;
183: int j = 0;
184: Value[] newTagValues = null;
185: try {
186: tagReferenceProperty = this .node
187: .getProperty(CATEGORY_PROPERTY_NAME);
188: Value[] oldTagValues = tagReferenceProperty.getValues();
189:
190: //see if the tag was even there
191: boolean wasThere = false;
192: for (i = 0; i < oldTagValues.length; i++) {
193: Node tagNode = this .node.getSession()
194: .getNodeByUUID(oldTagValues[i].getString());
195: if (tagNode.getName().equals(tag)) {
196: wasThere = true;
197: }
198: }
199:
200: if (wasThere) {
201: //copy the array, minus the specified tag
202: newTagValues = new Value[oldTagValues.length + 1];
203: for (i = 0; i < oldTagValues.length; i++) {
204: Node tagNode = this .node.getSession()
205: .getNodeByUUID(
206: oldTagValues[i].getString());
207: if (!tagNode.getName().equals(tag)) {
208: newTagValues[j] = oldTagValues[i];
209: j++;
210: }
211: }
212: } else {
213: return;
214: }
215: } catch (PathNotFoundException e) {
216: //the property doesn't exist yet
217: return;
218: } finally {
219: if (newTagValues != null) {
220: checkout();
221: this .node.setProperty(CATEGORY_PROPERTY_NAME,
222: newTagValues);
223: } else {
224: log
225: .error("reached expected path of execution when removing tag '"
226: + tag
227: + "' from ruleNode: "
228: + this .node.getName());
229: }
230: }
231: } catch (Exception e) {
232: log.error("Caught exception", e);
233: throw new RulesRepositoryException(e);
234: }
235: }
236:
237: }
|