001: /***************************************************************
002: * This file is part of the [fleXive](R) project.
003: *
004: * Copyright (c) 1999-2007
005: * UCS - unique computing solutions gmbh (http://www.ucs.at)
006: * All rights reserved
007: *
008: * The [fleXive](R) project is free software; you can redistribute
009: * it and/or modify it under the terms of the GNU General Public
010: * License as published by the Free Software Foundation;
011: * either version 2 of the License, or (at your option) any
012: * later version.
013: *
014: * The GNU General Public License can be found at
015: * http://www.gnu.org/copyleft/gpl.html.
016: * A copy is found in the textfile GPL.txt and important notices to the
017: * license from the author are found in LICENSE.txt distributed with
018: * these libraries.
019: *
020: * This library is distributed in the hope that it will be useful,
021: * but WITHOUT ANY WARRANTY; without even the implied warranty of
022: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
023: * GNU General Public License for more details.
024: *
025: * For further information about UCS - unique computing solutions gmbh,
026: * please see the company website: http://www.ucs.at
027: *
028: * For further information about [fleXive](R), please see the
029: * project website: http://www.flexive.org
030: *
031: *
032: * This copyright notice MUST APPEAR in all copies of the file!
033: ***************************************************************/package com.flexive.war.javascript.tree;
034:
035: import com.flexive.shared.CacheAdmin;
036: import com.flexive.shared.EJBLookup;
037: import com.flexive.shared.exceptions.FxApplicationException;
038: import com.flexive.shared.exceptions.FxInvalidParameterException;
039: import com.flexive.shared.exceptions.FxNotFoundException;
040: import com.flexive.shared.structure.*;
041: import org.apache.commons.lang.StringUtils;
042:
043: import java.io.Serializable;
044: import java.util.regex.Matcher;
045: import java.util.regex.Pattern;
046:
047: /**
048: * Content tree edit actions invoked via JSON/RPC.
049: *
050: * @author Gerhard Glos (gerhard.glos@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
051: * @version $Rev: 240 $
052: */
053:
054: public class StructureTreeEditor implements Serializable {
055: private static final long serialVersionUID = -2853036616736591794L;
056: private static Pattern aliasPattern = Pattern
057: .compile("[a-zA-Z][a-zA-Z_0-9]*");
058:
059: public void deleteAssignment(long id) throws FxApplicationException {
060: EJBLookup.getAssignmentEngine().removeAssignment(id, true,
061: false);
062: }
063:
064: public void deleteType(long id) throws FxApplicationException {
065: EJBLookup.getTypeEngine().remove(id);
066: }
067:
068: /**
069: * Reuse a property assignment
070: *
071: * @param orgAssignmentId id of the assignment to reuse
072: * @param newName new name (can be empty, will be used for label if set)
073: * @param xPath XPath
074: * @param type FxType
075: * @return FxPropertyAssignmentEdit
076: * @throws FxNotFoundException on errors
077: * @throws FxInvalidParameterException on errors
078: */
079: private FxPropertyAssignmentEdit createReusedPropertyAssignment(
080: long orgAssignmentId, String newName, String xPath,
081: FxType type) throws FxNotFoundException,
082: FxInvalidParameterException {
083: FxPropertyAssignment assignment = (FxPropertyAssignment) CacheAdmin
084: .getEnvironment().getAssignment(orgAssignmentId);
085: FxPropertyAssignmentEdit prop;
086: if (!StringUtils.isEmpty(newName)) {
087: prop = FxPropertyAssignmentEdit.createNew(assignment, type,
088: newName == null ? assignment.getAlias() : newName,
089: xPath);
090: prop.getLabel().setDefaultTranslation(
091: StringUtils.capitalize(newName));
092: } else
093: prop = FxPropertyAssignmentEdit.createNew(assignment, type,
094: assignment.getAlias(), xPath);
095: return prop;
096: }
097:
098: /**
099: * Creates a derived assignment from a given assignment and pastes it into the
100: * the parent group or type. A new alias can also be specified.
101: *
102: * @param assId the id from which the assignment will be derived
103: * @param childNodeType the nodeType from which the assignment will be derivedt (i.e. StructureTreeWriter.DOC_TYPE_GROUP, StructureTreeWriter.DOC_TYPE_ASSIGNMENT)
104: * @param parentId the id of the parent group or type.
105: * @param parentNodeType the node type of the parent (i.e. StructureTreeWriter.DOC_TYPE_GROUP, StructureTreeWriter.DOC_TYPE_TYPE).
106: * @param newName the new alias. if ==null the old will be taken.
107: * @return the id of the newly created assignment
108: * @throws com.flexive.shared.exceptions.FxApplicationException
109: * on errors
110: */
111: public long pasteAssignmentInto(long assId, String childNodeType,
112: long parentId, String parentNodeType, String newName)
113: throws FxApplicationException {
114: String parentXPath = "/";
115: FxType parentType = null;
116: long assignmentId = -1;
117:
118: if (StructureTreeWriter.DOC_TYPE_GROUP.equals(parentNodeType)) {
119: FxGroupAssignment ga = (FxGroupAssignment) CacheAdmin
120: .getEnvironment().getAssignment(parentId);
121: parentType = ga.getAssignedType();
122: parentXPath = ga.getXPath();
123: } else if (StructureTreeWriter.DOC_TYPE_TYPE
124: .equals(parentNodeType)
125: || StructureTreeWriter.DOC_TYPE_TYPE_RELATION
126: .equals(parentNodeType)) {
127: parentType = CacheAdmin.getEnvironment().getType(parentId);
128: }
129:
130: if (StructureTreeWriter.DOC_TYPE_ASSIGNMENT
131: .equals(childNodeType)) {
132: assignmentId = EJBLookup.getAssignmentEngine().save(
133: createReusedPropertyAssignment(assId, newName,
134: parentXPath, parentType), false);
135: } else if (StructureTreeWriter.DOC_TYPE_GROUP
136: .equals(childNodeType)) {
137: FxGroupAssignment assignment = (FxGroupAssignment) CacheAdmin
138: .getEnvironment().getAssignment(assId);
139: assignmentId = EJBLookup.getAssignmentEngine()
140: .save(
141: FxGroupAssignmentEdit.createNew(assignment,
142: parentType,
143: newName == null ? assignment
144: .getAlias() : newName,
145: parentXPath), true);
146: }
147: return assignmentId;
148: }
149:
150: /**
151: * Creates a derived assignment from a given assignment and pastes it at
152: * a relative position above or below (indicated by steps) a destination assignment.
153: * A new alias can also be specified.
154: *
155: * @param srcId the id from which the assignment will be derived
156: * @param srcNodeType the nodeType from which the assignment will be derived (i.e. StructureTreeWriter.DOC_TYPE_GROUP, StructureTreeWriter.DOC_TYPE_ASSIGNMENT)
157: * @param destId the id of the destination assignment, where the assignment will be pasted at a relative position
158: * @param destNodeType the node type of the destination assignment
159: * @param newName the new alias. if ==null the old will be taken.
160: * @param steps the position relative to the destination assignment, where the derived assignment will be pasted.
161: * @return the id of the newly created assignment
162: * @throws com.flexive.shared.exceptions.FxApplicationException
163: * on errors
164: */
165: public long pasteAssignmentRelative(long srcId, String srcNodeType,
166: long destId, String destNodeType, String newName, int steps)
167: throws FxApplicationException {
168: String destXPath = "/";
169: long assignmentId = -1;
170: FxAssignment destAssignment = CacheAdmin.getEnvironment()
171: .getAssignment(destId);
172: FxType destType = destAssignment.getAssignedType();
173:
174: //get destination xpath
175: if (StructureTreeWriter.DOC_TYPE_GROUP.equals(destNodeType)) {
176: destXPath = destAssignment.getXPath();
177: } else if (StructureTreeWriter.DOC_TYPE_ASSIGNMENT
178: .equals(destNodeType)) {
179: if (destAssignment.hasParentGroupAssignment())
180: destXPath = destAssignment.getParentGroupAssignment()
181: .getXPath();
182: } else {
183: throw new FxInvalidParameterException("nodeType",
184: "ex.structureTreeEditor.nodeType.invalid",
185: destNodeType);
186: }
187:
188: if (StructureTreeWriter.DOC_TYPE_GROUP.equals(srcNodeType)) {
189: FxGroupAssignment srcAssignment = (FxGroupAssignment) CacheAdmin
190: .getEnvironment().getAssignment(srcId);
191: //create assignment
192: FxGroupAssignmentEdit newAssignment = FxGroupAssignmentEdit
193: .createNew(srcAssignment, destType,
194: newName == null ? srcAssignment.getAlias()
195: : newName, destXPath);
196: //set position
197: newAssignment.setPosition(destAssignment.getPosition()
198: + steps);
199: //save newly created assignment to db
200: assignmentId = EJBLookup.getAssignmentEngine().save(
201: newAssignment, true);
202: } else if (StructureTreeWriter.DOC_TYPE_ASSIGNMENT
203: .equals(srcNodeType)) {
204: //create assignment
205: FxPropertyAssignmentEdit newAssignment = createReusedPropertyAssignment(
206: srcId, newName, destXPath, destType);
207: //set position
208: newAssignment.setPosition(destAssignment.getPosition()
209: + steps);
210: //save newly created assignment to db
211: assignmentId = EJBLookup.getAssignmentEngine().save(
212: newAssignment, false);
213: } else {
214: throw new FxInvalidParameterException("nodeType",
215: "ex.structureTreeEditor.nodeType.invalid",
216: srcNodeType);
217: }
218: return assignmentId;
219: }
220:
221: /**
222: * Moves a source assignment to a relative position of another destination assignment.
223: * The assignments need to be at the same hierarchy level for positioning to work properly.
224: * Steps indicates the relative position offset:
225: * If steps is 0, the source assignment moves to the current position of the destination assignment.
226: * If steps is -1,-2..n the source assignment will be moved 1,2..n positions before the destination assignment.
227: * If steps is 1,2..n the source assignment will be moved 1,2..n positions after the destination assignment.
228: *
229: * @param srcId the id of the assignment that shall be moved.
230: * @param srcNodeType the node type of the assignment to be moved.
231: * @param destId the id of the destination assignment relative to which the source assignment will be moved.
232: * @param steps relative position offset.
233: * @throws com.flexive.shared.exceptions.FxApplicationException if the node type doesn't match StructureTreeWriter.DOC_TYPE_GROUP or StructureTreeWriter.DOC_TYPE_ASSIGNMENT
234: */
235: public void moveAssignmentRelative(long srcId, String srcNodeType,
236: long destId, int steps) throws FxApplicationException {
237: FxAssignment dest = CacheAdmin.getEnvironment().getAssignment(
238: destId);
239: if (StructureTreeWriter.DOC_TYPE_GROUP.equals(srcNodeType)) {
240: FxGroupAssignmentEdit src = ((FxGroupAssignment) CacheAdmin
241: .getEnvironment().getAssignment(srcId))
242: .asEditable();
243: src.setPosition(dest.getPosition() + steps);
244: EJBLookup.getAssignmentEngine().save(src, true);
245:
246: } else if (StructureTreeWriter.DOC_TYPE_ASSIGNMENT
247: .equals(srcNodeType)) {
248: FxPropertyAssignmentEdit src = ((FxPropertyAssignment) CacheAdmin
249: .getEnvironment().getAssignment(srcId))
250: .asEditable();
251: src.setPosition(dest.getPosition() + steps);
252: EJBLookup.getAssignmentEngine().save(src, false);
253: } else
254: throw new FxInvalidParameterException("nodeType",
255: "ex.structureTreeEditor.nodeType.invalid",
256: srcNodeType);
257: }
258:
259: public boolean validateAlias(String alias) {
260: if (alias != null) {
261: Matcher m = aliasPattern.matcher(alias);
262: if (m.matches())
263: return true; //all correct
264: }
265: return false;
266: }
267:
268: /**
269: * Compares if two assignments are positioned at the same hierarchy level.
270: *
271: * @param id1 id of first assignment
272: * @param id2 id of second assignment
273: * @return true if they have the same parent type, or if parent group assignments exist, true if they have the same parent group assignment
274: */
275:
276: public boolean isSameLevel(long id1, long id2) {
277: FxAssignment a1 = CacheAdmin.getEnvironment()
278: .getAssignment(id1);
279: FxAssignment a2 = CacheAdmin.getEnvironment()
280: .getAssignment(id2);
281: if (a1.hasParentGroupAssignment()
282: && a2.hasParentGroupAssignment()
283: && a1.getParentGroupAssignment().getId() == a2
284: .getParentGroupAssignment().getId())
285: return true;
286: else if (!a1.hasParentGroupAssignment()
287: && !a2.hasParentGroupAssignment()
288: && a1.getAssignedType().getId() == a2.getAssignedType()
289: .getId())
290: return true;
291:
292: return false;
293: }
294:
295: /**
296: * Checks if an assignment is the child of a given type or group.
297: *
298: * @param assId id of the assignment
299: * @param parentId id of type or group assignment
300: * @param parentNodeType the nodeDocType (i.e. StructureTreeWriter.DOC_TYPE_GROUP, StructureTreeWriter.DOC_TYPE_TYPE) of the parent
301: * @return true if the assignment is a direct child of the type or group
302: * @throws FxInvalidParameterException for invalid nodeDocTypes
303: * @throws com.flexive.shared.exceptions.FxNotFoundException on errors
304: */
305:
306: public boolean isChild(long assId, long parentId,
307: String parentNodeType) throws FxInvalidParameterException,
308: FxNotFoundException {
309: if (StructureTreeWriter.DOC_TYPE_GROUP.equals(parentNodeType)) {
310: FxGroupAssignment ga = (FxGroupAssignment) CacheAdmin
311: .getEnvironment().getAssignment(parentId);
312: for (FxAssignment a : ga.getAssignments()) {
313: if (a.getId() == assId)
314: return true;
315: }
316: } else if (StructureTreeWriter.DOC_TYPE_TYPE
317: .equals(parentNodeType)
318: || StructureTreeWriter.DOC_TYPE_TYPE_RELATION
319: .equals(parentNodeType)) {
320: FxType type = CacheAdmin.getEnvironment().getType(parentId);
321: for (FxAssignment a : type.getConnectedAssignments("/")) {
322: if (a.getId() == assId)
323: return true;
324: }
325: } else
326: throw new FxInvalidParameterException("nodeType",
327: "ex.structureTreeEditor.nodeType.invalid",
328: parentNodeType);
329:
330: return false;
331: }
332:
333: /**
334: * Returns if an FxPropertyAssignment has set OPTION_SEARCHABLE to true
335: *
336: * @param assId assignment id
337: * @return if an assignment is searchable
338: */
339: public boolean isSearchable(long assId) {
340: return ((FxPropertyAssignment) CacheAdmin
341: .getFilteredEnvironment().getAssignment(assId))
342: .isSearchable();
343: }
344: }
|