001: /***************************************************************
002: * This file is part of the [fleXive](R) project.
003: *
004: * Copyright (c) 1999-2008
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.shared.structure;
034:
035: import com.flexive.shared.XPathElement;
036: import com.flexive.shared.FxContext;
037: import com.flexive.shared.security.UserTicket;
038: import com.flexive.shared.content.FxData;
039: import com.flexive.shared.content.FxGroupData;
040: import com.flexive.shared.exceptions.FxCreateException;
041: import com.flexive.shared.exceptions.FxInvalidParameterException;
042: import com.flexive.shared.exceptions.FxNotFoundException;
043: import com.flexive.shared.value.FxString;
044:
045: import java.io.Serializable;
046: import java.util.ArrayList;
047: import java.util.Collections;
048: import java.util.List;
049: import java.util.Random;
050:
051: /**
052: * Assignment of a (structure) group to a type or another assignment of a (structure) group
053: *
054: * @author Markus Plesser (markus.plesser@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
055: */
056: public class FxGroupAssignment extends FxAssignment implements
057: Serializable {
058:
059: private static final long serialVersionUID = 4006780797029441250L;
060:
061: /**
062: * The group assigned
063: */
064: protected FxGroup group;
065:
066: /**
067: * mode used for children
068: */
069: protected GroupMode mode;
070: private List<FxAssignment> assignments;
071: private List<FxPropertyAssignment> propertyAssignments;
072: private List<FxGroupAssignment> groupAssignments;
073:
074: /**
075: * Constructor
076: *
077: * @param assignmentId internal id of this assignment
078: * @param enabled is this assignment enabled?
079: * @param assignedType the FxType this assignment belongs to
080: * @param alias an optional alias, if <code>null</code> the original name will be used
081: * @param xpath XPath relative to the assigned FxType
082: * @param position position within the same XPath hierarchy
083: * @param multiplicity multiplicity
084: * @param defaultMultiplicity default multiplicity
085: * @param parentGroupAssignment (optional) parent FxGroupAssignment this group assignment belongs to
086: * @param baseAssignment base assignment (if derived the parent, if not the root assignment, if its a root assignment FxAssignment.ROOT_BASE)
087: * @param label (optional) label
088: * @param hint (optional) hint
089: * @param group the assigned group
090: * @param mode used group mode (any-of or one-of)
091: * @param options options
092: */
093: public FxGroupAssignment(long assignmentId, boolean enabled,
094: FxType assignedType, String alias, String xpath,
095: int position, FxMultiplicity multiplicity,
096: int defaultMultiplicity,
097: FxGroupAssignment parentGroupAssignment,
098: long baseAssignment, FxString label, FxString hint,
099: FxGroup group, GroupMode mode,
100: List<FxStructureOption> options) {
101: super (assignmentId, enabled, assignedType, alias, xpath,
102: position, multiplicity, defaultMultiplicity,
103: parentGroupAssignment, baseAssignment, label, hint,
104: options);
105: this .group = group;
106: this .mode = mode;
107: this .assignments = new ArrayList<FxAssignment>(10);
108: this .propertyAssignments = new ArrayList<FxPropertyAssignment>(
109: 5);
110: this .groupAssignments = new ArrayList<FxGroupAssignment>(5);
111:
112: //allow null alias only for creating new groups if only subgroups but not the group itself should be created
113: if ((alias == null || alias.trim().length() == 0)
114: && assignmentId >= 0)
115: this .alias = (group != null ? group.getName() : null); //catcher if using preload assignment
116: }
117:
118: /**
119: * Get the group this assignment relates to
120: *
121: * @return group this assignment relates to
122: */
123: public FxGroup getGroup() {
124: return group;
125: }
126:
127: /**
128: * Get the multiplicity of this assignment.
129: * Depending on if the assigned element allows overriding of its base multiplicity the base
130: * elements multiplicity is returned or the multiplicity of the assignment
131: *
132: * @return multiplicity of this assignment
133: */
134: public FxMultiplicity getMultiplicity() {
135: return (getGroup().mayOverrideBaseMultiplicity() ? this .multiplicity
136: : getGroup().getMultiplicity());
137: }
138:
139: /**
140: * Get all assignments (groups and properties in correct order) that are assigned to this group
141: *
142: * @return group assignments that are assigned to this assignment
143: */
144: public List<FxAssignment> getAssignments() {
145: return Collections.unmodifiableList(assignments);
146: }
147:
148: /**
149: * Get all group assignments that are assigned to this assignment
150: *
151: * @return group assignments that are assigned to this assignment
152: */
153: public List<FxGroupAssignment> getAssignedGroups() {
154: return Collections.unmodifiableList(groupAssignments);
155: }
156:
157: /**
158: * Get all property assignments that are assigned to this assignment
159: *
160: * @return property assignments that are assigned to this assignment
161: */
162: public List<FxPropertyAssignment> getAssignedProperties() {
163: return Collections.unmodifiableList(propertyAssignments);
164: }
165:
166: /**
167: * Get all assignments of this group and its subgroups
168: *
169: * @return all assignments of this group and its subgroups
170: */
171: public List<FxAssignment> getAllChildAssignments() {
172: List<FxAssignment> ret = new ArrayList<FxAssignment>(
173: assignments.size() * 5);
174: for (FxAssignment as : assignments) {
175: ret.add(as);
176: if (as instanceof FxGroupAssignment)
177: addGroup(ret, (FxGroupAssignment) as);
178: }
179: return Collections.unmodifiableList(ret);
180: }
181:
182: /**
183: * Recursively add all subgroups to the given list
184: *
185: * @param ret list of assignments to build
186: * @param as current group processed
187: */
188: private void addGroup(List<FxAssignment> ret, FxGroupAssignment as) {
189: for (FxAssignment sub : as.getAssignments()) {
190: ret.add(sub);
191: if (sub instanceof FxGroupAssignment)
192: addGroup(ret, (FxGroupAssignment) sub);
193: }
194: }
195:
196: /**
197: * Add an assignment sorted by position to an ArrayList of assignments
198: *
199: * @param assignments list of assignments
200: * @param as assignment to add at the correct position in assignments
201: */
202: private static <T extends FxAssignment> void addSorted(
203: List<T> assignments, T as) {
204: synchronized (assignments) {
205: if (assignments.contains(as))
206: return;
207: for (int i = 0; i < assignments.size(); i++) {
208: if ((assignments).get(i).getPosition() >= as
209: .getPosition()) {
210: assignments.add(i, as);
211: return;
212: }
213: }
214: assignments.add(as);
215: }
216: }
217:
218: /**
219: * Add and sort an assignment during initialization phase
220: *
221: * @param as assignment to add at the correct position
222: */
223: protected void addAssignment(FxAssignment as) {
224: addSorted(assignments, as);
225: if (as instanceof FxGroupAssignment)
226: addSorted(groupAssignments, (FxGroupAssignment) as);
227: if (as instanceof FxPropertyAssignment)
228: addSorted(propertyAssignments, (FxPropertyAssignment) as);
229: }
230:
231: /**
232: * {@inheritDoc}
233: */
234: public FxData createEmptyData(FxGroupData parent, int index)
235: throws FxCreateException {
236: ArrayList<FxData> children = new ArrayList<FxData>(5);
237: FxGroupData this Group;
238: try {
239: final UserTicket ticket = FxContext.get().getTicket();
240: if (!this .getMultiplicity().isValid(index))
241: throw new FxCreateException(
242: "ex.content.xpath.index.invalid", index, this
243: .getMultiplicity(), this .getXPath())
244: .setAffectedXPath(parent.getXPathFull());
245: this Group = new FxGroupData(parent == null ? "" : parent
246: .getXPathPrefix(), this .getAlias(), index, this
247: .getXPath(), XPathElement.stripType(XPathElement
248: .toXPathMult(this .getXPath())), XPathElement
249: .getIndices(getXPath()), this .getId(), this
250: .getMultiplicity(), this .getPosition(), parent,
251: children, this .isSystemInternal());
252: if (this .getMode() == GroupMode.OneOf) {
253: //if One-Of more find the first non-optional child and create it (should not happen if correctly setup
254: //but still possible, multiple non-optional childs will result in errors that are thrown in an exception
255: boolean hasRequired = false;
256: for (FxAssignment as : assignments) {
257: if (as instanceof FxPropertyAssignment
258: && as.getAssignedType()
259: .usePropertyPermissions()
260: && !ticket.mayCreateACL(
261: ((FxPropertyAssignment) as)
262: .getACL().getId(), ticket
263: .getUserId()))
264: continue;
265: if (as.getMultiplicity().isRequired()) {
266: if (hasRequired)
267: throw new FxCreateException(
268: "ex.content.data.create.oneof.multiple",
269: this Group.getXPathFull())
270: .setAffectedXPath(this Group
271: .getXPathFull());
272: hasRequired = true;
273: for (int c = 0; c < as.getMultiplicity()
274: .getMin(); c++)
275: this Group.getChildren().add(
276: as
277: .createEmptyData(this Group,
278: c + 1));
279: }
280: }
281: } else { // 'regular' Any-Of group
282: for (FxAssignment as : assignments) {
283: if (as instanceof FxPropertyAssignment
284: && as.getAssignedType()
285: .usePropertyPermissions()
286: && !ticket.mayCreateACL(
287: ((FxPropertyAssignment) as)
288: .getACL().getId(), ticket
289: .getUserId()))
290: continue;
291: if (as.getMultiplicity().isOptional())
292: this Group.getChildren().add(
293: as.createEmptyData(this Group, 1));
294: else
295: for (int c = 0; c < as.getMultiplicity()
296: .getMin(); c++)
297: this Group.getChildren().add(
298: as
299: .createEmptyData(this Group,
300: c + 1));
301: }
302: }
303: this Group.fixChildIndices();
304: return this Group;
305: } catch (FxInvalidParameterException e) {
306: throw new FxCreateException(e);
307: }
308: }
309:
310: /**
311: * {@inheritDoc}
312: */
313: @Override
314: public FxStructureOption getOption(String key) {
315: FxStructureOption gOpt = group.getOption(key);
316: if (!gOpt.isSet())
317: return super .getOption(key);
318: if (!gOpt.isOverrideable())
319: return gOpt;
320: if (super .hasOption(key))
321: return super .getOption(key);
322: return gOpt;
323: }
324:
325: /**
326: * {@inheritDoc}
327: */
328: @Override
329: public FxData createRandomData(Random rnd, FxEnvironment env,
330: FxGroupData parent, int index, int maxMultiplicity)
331: throws FxCreateException {
332: ArrayList<FxData> children = new ArrayList<FxData>(5);
333: FxGroupData this Group;
334: try {
335: final UserTicket ticket = FxContext.get().getTicket();
336: this Group = new FxGroupData(parent == null ? "" : parent
337: .getXPathPrefix(), this .getAlias(), index, this
338: .getXPath(), XPathElement.stripType(XPathElement
339: .toXPathMult(this .getXPath())), XPathElement
340: .getIndices(getXPath()), this .getId(), this
341: .getMultiplicity(), this .getPosition(), parent,
342: children, this .isSystemInternal());
343: int count;
344: for (FxAssignment as : assignments) {
345: if (!as.isEnabled()
346: || as.isSystemInternal()
347: || (as instanceof FxPropertyAssignment
348: && as.getAssignedType()
349: .usePropertyPermissions() && !ticket
350: .mayCreateACL(
351: ((FxPropertyAssignment) as)
352: .getACL().getId(),
353: ticket.getUserId()))
354: || (as instanceof FxPropertyAssignment && ((FxPropertyAssignment) as)
355: .getProperty().getDataType() == FxDataType.Binary)
356: || (as instanceof FxPropertyAssignment && ((FxPropertyAssignment) as)
357: .getProperty().getDataType() == FxDataType.Reference))
358: continue;
359: count = as.getMultiplicity().getRandomRange(rnd,
360: maxMultiplicity);
361: for (int i = 0; i < count; i++)
362: this Group.getChildren().add(
363: as.createRandomData(rnd, env, this Group,
364: i + 1, maxMultiplicity));
365: }
366: // thisGroup.fixChildIndices();
367: return this Group;
368: } catch (FxInvalidParameterException e) {
369: throw new FxCreateException(e);
370: }
371: }
372:
373: /**
374: * Get an assignment for the given (relative to this group) XPath
375: *
376: * @param XPath XPathElement array starting at this group
377: * @param fullXPath the full XPath for exception reporting
378: * @return FxAssignment
379: * @throws FxNotFoundException if no assignment was found
380: */
381: public FxAssignment getAssignment(List<XPathElement> XPath,
382: String fullXPath) throws FxNotFoundException {
383: XPathElement curr = XPath.remove(0); //consume 'us'
384: if (curr.getAlias().equals(this .getAlias())
385: && XPath.size() == 0)
386: return this ; //ok, its us
387: if (XPath.size() > 0) {
388: curr = XPath.get(0);
389: for (FxAssignment as : assignments)
390: if (as.getAlias().equals(curr.getAlias())) {
391: if (as instanceof FxGroupAssignment)
392: return ((FxGroupAssignment) as).getAssignment(
393: XPath, fullXPath);
394: else
395: return as;
396: }
397: }
398: throw new FxNotFoundException(
399: "ex.structure.assignment.notFound.xpath", fullXPath);
400: }
401:
402: /**
403: * Get the mode used for this group.
404: *
405: * @return group mode used
406: */
407: public GroupMode getMode() {
408: return mode;
409: }
410:
411: /**
412: * Get this FxGroupAssignment as editable
413: *
414: * @return FxGroupAssignmentEdit
415: */
416: public FxGroupAssignmentEdit asEditable() {
417: return new FxGroupAssignmentEdit(this);
418: }
419: }
|