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.content;
034:
035: import com.flexive.shared.CacheAdmin;
036: import com.flexive.shared.FxContext;
037: import com.flexive.shared.XPathElement;
038: import com.flexive.shared.exceptions.*;
039: import com.flexive.shared.security.UserTicket;
040: import com.flexive.shared.structure.*;
041: import com.flexive.shared.value.FxReference;
042: import com.flexive.shared.value.FxValue;
043: import org.apache.commons.lang.ArrayUtils;
044:
045: import java.util.ArrayList;
046: import java.util.List;
047:
048: /**
049: * FxData extension for groups
050: *
051: * @author Markus Plesser (markus.plesser@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
052: */
053: public class FxGroupData extends FxData implements Cloneable {
054: private static final long serialVersionUID = 133412774300450631L;
055: private List<FxData> data;
056:
057: public FxGroupData(String xpPrefix, String alias, int index,
058: String xPath, String xPathFull, int[] indices,
059: long assignmentId, FxMultiplicity assignmentMultiplicity,
060: int pos, FxGroupData parent, List<FxData> data,
061: boolean systemInternal) throws FxInvalidParameterException {
062: super (xpPrefix, alias, index, xPath, xPathFull, indices,
063: assignmentId, assignmentMultiplicity, pos, parent,
064: systemInternal);
065: this .data = data;
066: }
067:
068: /**
069: * {@inheritDoc}
070: */
071: @Override
072: public boolean isProperty() {
073: return false;
074: }
075:
076: /**
077: * {@inheritDoc}
078: */
079: @Override
080: public boolean isGroup() {
081: return true;
082: }
083:
084: /**
085: * Get all child entries for this group
086: *
087: * @return child entries
088: */
089: public List<FxData> getChildren() {
090: return data;
091: }
092:
093: /**
094: * {@inheritDoc}
095: */
096: @Override
097: public boolean isEmpty() {
098: for (FxData curr : this .getChildren())
099: if (!curr.isEmpty())
100: return false;
101: return true;
102: }
103:
104: /**
105: * Helper to create a virtual root group
106: *
107: * @param xpPrefix XPath prefix like "FxType name[@pk=..]"
108: * @return virtual root group
109: * @throws FxInvalidParameterException on errors
110: */
111: public static FxGroupData createVirtualRootGroup(String xpPrefix)
112: throws FxInvalidParameterException {
113: return new FxGroupData(xpPrefix, "", 1, "/", "/", new int[0],
114: -1, new FxMultiplicity(1, 1), -1, null,
115: new ArrayList<FxData>(10), false);
116: }
117:
118: /**
119: * Move a child element identified by its alias and multiplicity by delta positions within this group
120: * If delta is Integer.MAX_VALUE the data will always be placed at the bottom,
121: * Integer.MIN_VALUE will always place it at the top.
122: *
123: * @param xp element to move
124: * @param delta delta positions to move
125: */
126: public void moveChild(XPathElement xp, int delta) {
127: if (delta == 0 || data.size() < 2)
128: return;
129: int currPos = -1, newPos;
130: FxData child = null;
131: List<String> aliases = new ArrayList<String>(
132: (int) (data.size() * 0.7));
133: for (int i = 0; i < data.size(); i++) {
134: child = data.get(i);
135: if (!aliases.contains(child.getAlias()))
136: aliases.add(child.getAlias());
137: if (child.getXPathElement().equals(xp)) {
138: currPos = i;
139: break;
140: }
141: }
142: if (currPos == -1)
143: throw new FxNotFoundException("ex.xpath.alias.notFound", xp)
144: .asRuntimeException();
145:
146: newPos = currPos + delta;
147: if (newPos < 0)
148: newPos = 0; //move to top
149: if (newPos >= data.size())
150: newPos = data.size() - 1; //move to bottom
151: data.remove(currPos);
152: data.add(newPos, child);
153: //resync positions and indices
154: for (int i = 0; i < data.size(); i++) {
155: data.get(i).setPos(i);
156: if (aliases.contains(data.get(i).getAlias())) {
157: //make sure to sync the multiplicity for each alias only once
158: data.get(i).compact();
159: aliases.remove(data.get(i).getAlias());
160: }
161: }
162:
163: }
164:
165: /**
166: * Add a child FxData at the correct position
167: *
168: * @param child FxData to add
169: * @return the child
170: */
171: public synchronized FxData addChild(FxData child) {
172: if (data.contains(child)) //TODO: change to containsChild()?
173: return child;
174: int pos = (data.size() == 0 ? 0 : child.getPos());
175: switch (child.getPos()) {
176: case POSITION_TOP:
177: pos = 0;
178: break;
179: case POSITION_BOTTOM:
180: pos = data.size();
181: break;
182: }
183: if (!child.isSystemInternal() && pos < 20
184: && child.getParent().isRootGroup())
185: pos = 20;
186: child.setPos(pos);
187: //check if the position is taken (if so move the child and successors at the given position one place down)
188: for (int i = 0; i < data.size(); i++) {
189: if (data.get(i).getPos() < pos)
190: continue;
191: if (data.get(i).getPos() > pos) {
192: if (i > 0 && data.get(i - 1).getPos() < pos)
193: data.add(i, child);
194: else
195: data.add((i - 1 < 0 ? 0 : i - 1), child);
196: return child;
197: }
198: if (data.get(i).getPos() == pos) {
199: //move successors down
200: int lastPos = pos + 1;
201: data.get(i).setPos(lastPos);
202: for (int j = i + 1; j < data.size(); j++) {
203: if (!(data.get(j).getPos() > lastPos))
204: data.get(j).setPos(lastPos + 1);
205: lastPos = data.get(j).getPos();
206: }
207: }
208: }
209: data.add(child); //add at bottom
210: return child;
211: }
212:
213: /**
214: * Add an and FxData entry with the given XPath to this group (must be a direct child of this group, no nesting allowed!).
215: * Empty groups consist of empty but preinitialized elements!
216: *
217: * @param xPath XPath to add to this group (must be a direct child of this group, no nesting allowed!)
218: * @param pos position in same hierarchy level
219: * @return the added data element
220: * @throws FxInvalidParameterException on errors
221: * @throws FxNoAccessException on errors
222: * @throws FxNotFoundException on errors
223: * @throws FxCreateException on errors
224: */
225: public FxData addEmptyChild(String xPath, int pos)
226: throws FxInvalidParameterException, FxNoAccessException,
227: FxNotFoundException, FxCreateException {
228: FxType type;
229: List<FxAssignment> childAssignments;
230: if (this .isRootGroup()) {
231: type = CacheAdmin.getEnvironment().getAssignment(
232: this .getChildren().get(0).getAssignmentId())
233: .getAssignedType();
234: childAssignments = type.getConnectedAssignments("/");
235: } else {
236: type = CacheAdmin.getEnvironment().getAssignment(
237: this .getAssignmentId()).getAssignedType();
238: childAssignments = ((FxGroupAssignment) type
239: .getAssignment(this .getXPath())).getAssignments();
240: }
241: if (childAssignments != null && childAssignments.size() > 0) {
242: FxGroupAssignment this Group = childAssignments.get(0)
243: .getParentGroupAssignment();
244: boolean isOneOf = false;
245: if (this Group != null)
246: isOneOf = this Group.getMode() == GroupMode.OneOf;
247:
248: String xPathNoMult = type.getName().toUpperCase()
249: + XPathElement.stripType(XPathElement
250: .toXPathNoMult(xPath));
251: for (FxAssignment as : childAssignments) {
252: if (as.getXPath().equals(xPathNoMult)) {
253: if (isOneOf) {
254: //check if other assignments exist
255: for (FxData child : this .getChildren()) {
256: if (child.getAssignmentId() != as.getId())
257: throw new FxCreateException(
258: "ex.content.xpath.group.oneof",
259: as.getXPath(), this
260: .getXPathFull())
261: .setAffectedXPath(xPath);
262: }
263: }
264: int index = XPathElement.lastElement(xPath)
265: .getIndex();
266: if (as.getMultiplicity().isValid(index))
267: return this .addChild(as.createEmptyData(this ,
268: index).setPos(pos));
269: else
270: throw new FxInvalidParameterException("pos",
271: "ex.content.xpath.index.invalid",
272: index, as.getMultiplicity(), this
273: .getXPath())
274: .setAffectedXPath(xPath);
275: }
276: }
277: }
278: throw new FxNotFoundException("ex.content.xpath.add.notFound",
279: xPath);
280: }
281:
282: /**
283: * Apply the multiplicity to XPath and children if its a group
284: */
285: @Override
286: protected void applyIndices() {
287: try {
288: List<XPathElement> elements = XPathElement.split(this
289: .getXPathFull());
290: if (elements.get(elements.size() - 1).getIndex() == this
291: .getIndex())
292: return;
293: int pos = elements.size() - 1;
294: elements.get(pos).setIndex(this .getIndex());
295: this .XPathFull = XPathElement.toXPath(elements);
296: this .indices = XPathElement.getIndices(this .XPathFull);
297: if (this .getChildren() != null)
298: _changeIndex(this .getChildren(), pos, this .getIndex());
299: } catch (FxInvalidParameterException e) {
300: throw e.asRuntimeException();
301: }
302: }
303:
304: /**
305: * 'Fix' the indices of children after they have been added to reflect the parent groups index in
306: * their XPath
307: *
308: */
309: public void fixChildIndices() {
310: try {
311: List<XPathElement> elements = XPathElement.split(this
312: .getXPathFull());
313: int pos = elements.size() - 1;
314: if (this .getChildren() != null)
315: _changeIndex(this .getChildren(), pos, this .getIndex());
316: } catch (FxInvalidParameterException e) {
317: throw e.asRuntimeException();
318: }
319: }
320:
321: /**
322: * Recursively change the index for an element in the XPath of all children and their sub groups/properties
323: *
324: * @param children array of FxData to process
325: * @param pos position of the element to change in the XPath
326: * @param index the index to apply
327: * @throws FxInvalidParameterException on errors with XPath composition
328: */
329: private void _changeIndex(List<FxData> children, int pos, int index)
330: throws FxInvalidParameterException {
331: List<XPathElement> elements;
332: for (FxData curr : children) {
333: elements = XPathElement.split(curr.getXPath());
334: elements.get(pos).setIndex(index);
335: curr.XPathFull = XPathElement.toXPath(elements);
336: curr.indices = XPathElement.getIndices(curr.XPathFull);
337: if (curr instanceof FxGroupData)
338: _changeIndex(((FxGroupData) curr).getChildren(), pos,
339: index);
340: }
341: }
342:
343: /**
344: * Remove all empty entries of this group that are not required
345: *
346: * @see #removeEmptyEntries(boolean)
347: */
348: public void removeEmptyEntries() {
349: removeEmptyEntries(false);
350: }
351:
352: /**
353: * Remove all empty entries of this group
354: *
355: * @param includeRequired include entries that are required?
356: */
357: public void removeEmptyEntries(boolean includeRequired) {
358: for (FxData curr : data)
359: if (curr.isEmpty()
360: && (curr.isGroup() || includeRequired || curr
361: .isRemoveable())
362: && !curr.isSystemInternal()) {
363: data.remove(curr);
364: for (FxData com : data) {
365: if (com.getAssignmentId() == curr.getAssignmentId()) {
366: com.compact();
367: break;
368: }
369: }
370: removeEmptyEntries(includeRequired);
371: return;
372: } else if (curr instanceof FxGroupData) {
373: ((FxGroupData) curr)
374: .removeEmptyEntries(includeRequired);
375: }
376: }
377:
378: /**
379: * Synchronize positions closing gaps optionally including sub groups
380: *
381: * @param includeSubGroups close gaps for subgroups as well?
382: */
383: public void compactPositions(boolean includeSubGroups) {
384: int pos = 0;
385: for (FxData curr : data) {
386: curr.setPos(pos++);
387: if (includeSubGroups && curr instanceof FxGroupData)
388: ((FxGroupData) curr).compactPositions(true);
389: }
390: }
391:
392: /**
393: * Get the root group for this group
394: *
395: * @return root group
396: */
397: private FxGroupData getRootGroup() {
398: FxGroupData root = this ;
399: while (root.getParent() != null)
400: root = root.getParent();
401: return root;
402: }
403:
404: /**
405: * Is this group the root group?
406: *
407: * @return if this group is the root group
408: */
409: public boolean isRootGroup() {
410: return this .getAssignmentId() == -1;
411: }
412:
413: /**
414: * Get the group denoted by the given XPath
415: *
416: * @param xPath requested XPath for the group
417: * @return FxGroupData
418: * @throws FxNotFoundException if no group with this XPath is found
419: * @throws FxInvalidParameterException if the XPath is invalid
420: */
421: public FxGroupData getGroup(String xPath)
422: throws FxNotFoundException, FxInvalidParameterException {
423: FxGroupData root = getRootGroup();
424: if ("/".equals(xPath))
425: return root;
426: List<XPathElement> elements = XPathElement.split(xPath);
427:
428: FxGroupData found = null;
429: List<FxData> currGroup = root.getChildren();
430: for (XPathElement e : elements) {
431: found = null;
432: for (FxData curr : currGroup) {
433: if (curr instanceof FxGroupData
434: && curr.getXPathElement().equals(e)) {
435: found = (FxGroupData) curr;
436: currGroup = found.getChildren();
437: break;
438: }
439: }
440: if (found == null)
441: throw new FxNotFoundException(
442: "ex.content.xpath.notFound", xPath);
443: }
444: if (found == null)
445: throw new FxNotFoundException("ex.content.xpath.notFound",
446: xPath);
447: return found;
448: }
449:
450: /**
451: * Add a property at the given XPath location, removing eventually existing properties.
452: * The group for this property has to exist already!
453: *
454: * @param xPath requested XPath
455: * @param assignment assignment of the property
456: * @param value value
457: * @param pos position
458: * @throws FxInvalidParameterException if the XPath is invalid
459: * @throws FxNotFoundException if the parent group does not exist
460: */
461: public void addProperty(String xPath,
462: FxPropertyAssignment assignment, FxValue value, int pos)
463: throws FxInvalidParameterException, FxNotFoundException {
464: FxGroupData parentGroup = this ;
465: List<XPathElement> elements = XPathElement.split(xPath);
466: if (elements.size() > 1) {
467: String groupXPath = XPathElement.toXPath(elements.subList(
468: 0, elements.size() - 1));
469: parentGroup = getGroup(groupXPath);
470: }
471: int index = elements.get(elements.size() - 1).getIndex();
472: FxPropertyData data = new FxPropertyData(this .xpPrefix,
473: assignment.getAlias(), index, XPathElement
474: .stripType(XPathElement.toXPathNoMult(xPath)),
475: xPath, XPathElement.getIndices(xPath), assignment
476: .getId(), assignment.getProperty().getId(),
477: assignment.getMultiplicity(), pos, parentGroup, value,
478: assignment.isSystemInternal());
479:
480: FxData check = parentGroup
481: .containsChild(data.getXPathElement());
482: if (check != null)
483: parentGroup.data.remove(check);
484: parentGroup.addChild(data);
485: /*boolean added = false;
486: for (int i = 0; i < parentGroup.data.size(); i++) {
487: if (parentGroup.data.get(i).getPos() > data.getPos()) {
488: parentGroup.data.add(i, data);
489: added = true;
490: break;
491: }
492: }
493: if (!added) //add at end
494: parentGroup.data.add(data);*/
495: // parentGroup.replaceChild(data.getXPathElement(), data);
496: // } else { //TODO: check if adding allowed!
497: // parentGroup.data.add(pos, data);
498: // }
499: }
500:
501: /**
502: * Check if a child with the same alias and multiplicity that is not empty exists.
503: * No elements of subgroups are checked, just <i>direct</i> childs!
504: *
505: * @param check XPathElement to check
506: * @return FxData or <code>null</code>
507: */
508: public FxData containsChild(XPathElement check) {
509: for (FxData curr : getChildren()) {
510: if (curr.getXPathElement().equals(check))
511: return curr;
512: }
513: return null;
514: }
515:
516: public void replaceChild(XPathElement xpath, FxData data) {
517: for (int i = 0; i < this .data.size(); i++) {
518: if (this .data.get(i).getXPathElement().equals(xpath)) {
519: this .data.set(i, data);
520: return;
521: }
522: }
523: }
524:
525: /**
526: * Add a group entry at the given XPath. Existing entries will stay untouched but position adjusted.
527: * If parent groups of this group do not exist, they will be created as well.
528: *
529: * @param xPath requested XPath
530: * @param fxGroupAssignment the assignment of the group
531: * @param pos position
532: * @throws FxInvalidParameterException on errors
533: * @throws FxNotFoundException on errors
534: * @throws FxCreateException on errors
535: */
536: public void addGroup(String xPath,
537: FxGroupAssignment fxGroupAssignment, int pos)
538: throws FxInvalidParameterException, FxNotFoundException,
539: FxCreateException {
540: if (xPath.endsWith("/"))
541: xPath = xPath.substring(0, xPath.length() - 1);
542: List<XPathElement> xp = XPathElement.split(xPath);
543: XPathElement addy = xp.get(xp.size() - 1);
544: FxGroupData currGroup = getRootGroup(), tmp;
545: // System.out.println("adding group(s): " + xPath);
546: for (XPathElement curr : xp) {
547: if ((tmp = (FxGroupData) currGroup.containsChild(curr)) != null) {
548: currGroup = tmp;
549: } else {
550: FxGroupAssignment gaNew = (FxGroupAssignment) fxGroupAssignment
551: .getAssignedType().getAssignment(
552: XPathElement.buildXPath(true, currGroup
553: .getXPath(), curr.getAlias()));
554: FxData gdNew = gaNew.createEmptyData(currGroup, curr
555: .getIndex());
556: //TODO: check if adding allowed here!
557: // System.out.println("creating " + curr + " in " + xPath);
558: if (addy.equals(curr)) {
559: // System.out.println("creating the actual addy group...");
560: gdNew.setPos(pos);
561: }
562: currGroup.addChild(gdNew);
563: currGroup = currGroup.getGroup(gdNew.getXPathFull());
564: }
565: }
566: }
567:
568: /**
569: * Remove the requested child data and compact indices and positions
570: *
571: * @param data FxData to remove
572: * @throws FxInvalidParameterException on errors
573: * @throws FxNoAccessException on errors
574: */
575: public void removeChild(FxData data)
576: throws FxInvalidParameterException, FxNoAccessException {
577: if (!data.isRemoveable())
578: throw new FxNoAccessException(
579: "ex.content.xpath.remove.invalid", data
580: .getXPathFull());
581:
582: if (!this .data.remove(data)) //was: if (!data.getParent().data.remove(data))
583: throw new FxInvalidParameterException(
584: "ex.content.xpath.remove.notFound", data
585: .getXPathFull());
586:
587: data.compact();
588: compactPositions(false);
589: }
590:
591: /**
592: * "Explode" this group by adding all createable assignments at the bottom
593: *
594: * @param explodeChildGroups recursively explode all <i>existing</i> child groups?
595: */
596: public void explode(boolean explodeChildGroups) {
597: for (String xpath : getCreateableChildren(false))
598: try {
599: addEmptyChild(xpath, POSITION_BOTTOM);
600: } catch (FxApplicationException e) {
601: throw e.asRuntimeException();
602: }
603: if (explodeChildGroups) {
604: // explode child groups
605: for (FxData child : getChildren()) {
606: if (child.isGroup()) {
607: ((FxGroupData) child).explode(true);
608: }
609: }
610: }
611: }
612:
613: /**
614: * Get a list of child FxData instances (as XPath with full indices) that can be created as children for this group.
615: * Readonly or no access properties or groups will not be returned!
616: *
617: * @param includeExisting include entries for children that already exist but with a new (higher) multiplicity?
618: * @return List of XPaths
619: */
620: public List<String> getCreateableChildren(boolean includeExisting) {
621: List<String> ret = new ArrayList<String>(20);
622: FxType type;
623: List<FxAssignment> childAssignments;
624: boolean checkOneOf;
625: try {
626: if (this .isRootGroup()) {
627: type = CacheAdmin.getEnvironment().getAssignment(
628: this .getChildren().get(0).getAssignmentId())
629: .getAssignedType();
630: childAssignments = type.getConnectedAssignments("/");
631: checkOneOf = false;
632: } else {
633: type = CacheAdmin.getEnvironment().getAssignment(
634: this .getAssignmentId()).getAssignedType();
635: FxGroupAssignment this Assignment = ((FxGroupAssignment) type
636: .getAssignment(this .getXPath()));
637: childAssignments = this Assignment.getAssignments();
638: checkOneOf = this Assignment.getMode() == GroupMode.OneOf;
639: }
640: } catch (FxApplicationException e) {
641: throw e.asRuntimeException();
642: }
643:
644: int count;
645: for (FxAssignment as : childAssignments) {
646: if (!as.isEnabled() || as.isSystemInternal())
647: continue;
648: count = 0;
649: if (as instanceof FxPropertyAssignment
650: && type.usePropertyPermissions()) {
651: UserTicket ticket = FxContext.get().getTicket();
652: long aclId = ((FxPropertyAssignment) as).getACL()
653: .getId();
654: //ignore owner in this checks since owner membership does not allow creation
655: if (!ticket.mayReadACL(aclId, 0)
656: || !ticket.mayCreateACL(aclId, 0)
657: || !ticket.mayEditACL(aclId, 0))
658: continue;
659: }
660: for (FxData _curr : this .getChildren()) {
661: if (_curr.getAssignmentId() == as.getId())
662: count++;
663: }
664: if (checkOneOf && count > 0) {
665: //one child exists already -> can only use this one
666: ret.clear();
667: }
668: try {
669: if (as.getMultiplicity().getMax() > count
670: && (includeExisting || (count == 0 && !includeExisting)))
671: ret.add(as.createEmptyData(this , count + 1)
672: .getXPathFull());
673: } catch (Exception e) {
674: //ignore
675: }
676: if (checkOneOf && count > 0)
677: return ret; //now we either have another to add of an existing or none -> return
678: }
679: return ret;
680: }
681:
682: /**
683: * {@inheritDoc}
684: */
685: @Override
686: protected FxGroupData copy(FxGroupData parent) {
687: FxGroupData clone;
688: try {
689: clone = new FxGroupData(xpPrefix, getAlias(), getIndex(),
690: getXPath(), getXPathFull(), ArrayUtils
691: .clone(getIndices()), getAssignmentId(),
692: getAssignmentMultiplicity(), getPos(), parent,
693: null, isSystemInternal());
694: List<FxData> cloneData = new ArrayList<FxData>(data.size());
695: for (FxData org : data)
696: cloneData.add(org.copy(clone));
697: clone.data = cloneData;
698: } catch (FxInvalidParameterException e) {
699: throw e.asRuntimeException();
700: }
701: return clone;
702: }
703:
704: /**
705: * Get a list of all FxReference values in this group and optionally all sub groups
706: *
707: * @param includeSubGroups collect FxReferences from sub groups as well?
708: * @return list of all FxReference values in this group and optionally all sub groups
709: */
710: protected List<FxReference> getReferences(boolean includeSubGroups) {
711: List<FxReference> refs = new ArrayList<FxReference>(20);
712: gatherReferences(refs, includeSubGroups);
713: return refs;
714: }
715:
716: /**
717: * Walk through all data nodes and collect FxReference instances
718: *
719: * @param refs list to add references to
720: * @param includeSubGroups should sub groups be included?
721: */
722: private void gatherReferences(List<FxReference> refs,
723: boolean includeSubGroups) {
724: for (FxData d : data) {
725: if (d instanceof FxGroupData) {
726: if (includeSubGroups)
727: ((FxGroupData) d).gatherReferences(refs,
728: includeSubGroups);
729: } else if (d instanceof FxPropertyData) {
730: if (((FxPropertyData) d).getValue() instanceof FxReference)
731: refs.add((FxReference) ((FxPropertyData) d)
732: .getValue());
733: }
734: }
735: }
736:
737: /**
738: * Get a list of all FxPropertyData entries that are assigned to propertyId
739: *
740: * @param propertyId the property id requested
741: * @param includeEmpty include empty data instances?
742: * @return list of all FxPropertyData entries that are assigned to propertyId
743: */
744: public List<FxPropertyData> getPropertyData(long propertyId,
745: boolean includeEmpty) {
746: List<FxPropertyData> res = new ArrayList<FxPropertyData>(5);
747: for (FxData d : getChildren()) {
748: if (d instanceof FxPropertyData
749: && ((FxPropertyData) d).getPropertyId() == propertyId) {
750: if (includeEmpty || !d.isEmpty())
751: res.add((FxPropertyData) d);
752: } else if (d instanceof FxGroupData)
753: res.addAll(((FxGroupData) d).getPropertyData(
754: propertyId, includeEmpty));
755: }
756: return res;
757: }
758: }
|