001: /*
002: The contents of this file are subject to the Common Public Attribution License
003: Version 1.0 (the "License"); you may not use this file except in compliance with
004: the License. You may obtain a copy of the License at
005: http://www.projity.com/license . The License is based on the Mozilla Public
006: License Version 1.1 but Sections 14 and 15 have been added to cover use of
007: software over a computer network and provide for limited attribution for the
008: Original Developer. In addition, Exhibit A has been modified to be consistent
009: with Exhibit B.
010:
011: Software distributed under the License is distributed on an "AS IS" basis,
012: WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
013: specific language governing rights and limitations under the License. The
014: Original Code is OpenProj. The Original Developer is the Initial Developer and
015: is Projity, Inc. All portions of the code written by Projity are Copyright (c)
016: 2006, 2007. All Rights Reserved. Contributors Projity, Inc.
017:
018: Alternatively, the contents of this file may be used under the terms of the
019: Projity End-User License Agreeement (the Projity License), in which case the
020: provisions of the Projity License are applicable instead of those above. If you
021: wish to allow use of your version of this file only under the terms of the
022: Projity License and not to allow others to use your version of this file under
023: the CPAL, indicate your decision by deleting the provisions above and replace
024: them with the notice and other provisions required by the Projity License. If
025: you do not delete the provisions above, a recipient may use your version of this
026: file under either the CPAL or the Projity License.
027:
028: [NOTE: The text of this license may differ slightly from the text of the notices
029: in Exhibits A and B of the license at http://www.projity.com/license. You should
030: use the latest text at http://www.projity.com/license for your modifications.
031: You may not remove this license text from the source files.]
032:
033: Attribution Information: Attribution Copyright Notice: Copyright © 2006, 2007
034: Projity, Inc. Attribution Phrase (not exceeding 10 words): Powered by OpenProj,
035: an open source solution from Projity. Attribution URL: http://www.projity.com
036: Graphic Image as provided in the Covered Code as file: openproj_logo.png with
037: alternatives listed on http://www.projity.com/logo
038:
039: Display of Attribution Information is required in Larger Works which are defined
040: in the CPAL as a work which combines Covered Code or portions thereof with code
041: not governed by the terms of the CPAL. However, in addition to the other notice
042: obligations, all copies of the Covered Code in Executable and Source Code form
043: distributed must, as a form of attribution of the original author, include on
044: each user interface screen the "OpenProj" logo visible to all users. The
045: OpenProj logo should be located horizontally aligned with the menu bar and left
046: justified on the top left of the screen adjacent to the File menu. The logo
047: must be at least 100 x 25 pixels. When users click on the "OpenProj" logo it
048: must direct them back to http://www.projity.com.
049: */
050: package com.projity.association;
051:
052: import java.text.ParsePosition;
053: import java.util.ArrayList;
054: import java.util.Collection;
055: import java.util.Collections;
056: import java.util.Iterator;
057: import java.util.LinkedList;
058: import java.util.List;
059: import java.util.ListIterator;
060:
061: import com.projity.field.FieldParseException;
062:
063: /**
064: * Container for managing lists of associated elements, such as Dependency or Assignment
065: */
066: public class AssociationList implements List {
067:
068: protected LinkedList list;
069:
070: public AssociationList() {
071: list = new LinkedList();
072: }
073:
074: public AssociationList(AssociationList from) {
075: this ();
076: list.addAll(from.list);
077: }
078:
079: public boolean add(Association association) {
080: Association found = AssociationList.findAssociation(list,
081: association.getLeft(), association.getRight(), null);
082: if (found != null) // if already in list
083: return false;
084: return list.add(association);
085: }
086:
087: private static Object getObject(Association association,
088: boolean leftObject) {
089: return leftObject ? association.getLeft() : association
090: .getRight();
091: }
092:
093: public Association find(boolean leftObject, Object object) {
094: Association association;
095: for (Iterator i = list.iterator(); i.hasNext();) {
096: association = (Association) i.next();
097: if (getObject(association, leftObject) == object)
098: return association;
099: }
100: return null;
101: }
102:
103: public Association findLeft(Object left) {
104: return find(true, left);
105: }
106:
107: public Association findRight(Object right) {
108: return find(false, right);
109: }
110:
111: public static Association findAssociation(LinkedList findInList,
112: Object left, Object right, Association exclude) {
113: Association association;
114: for (Iterator i = findInList.iterator(); i.hasNext();) {
115: association = (Association) i.next();
116: if (association == exclude)
117: continue;
118: if (association.getLeft() == left
119: && association.getRight() == right)
120: return association;
121: }
122: return null;
123: }
124:
125: public static List extractDistinct(List list, boolean leftObject) {
126: ArrayList result = new ArrayList();
127: Association association;
128: Object object;
129: for (Iterator i = list.iterator(); i.hasNext();) {
130: association = (Association) i.next();
131: object = getObject(association, leftObject);
132: if (!result.contains(object)) // if not already in list, add it
133: result.add(object);
134: }
135: return result;
136: }
137:
138: protected void testValid(boolean allowDuplicate)
139: throws InvalidAssociationException {
140: Association association;
141: for (Iterator i = list.iterator(); i.hasNext();) {
142: association = (Association) i.next();
143: association.testValid(allowDuplicate); //throws if exception
144: }
145: }
146:
147: public void replaceAll(Object object, boolean leftObject) {
148: Association association;
149: for (Iterator i = list.iterator(); i.hasNext();) {
150: association = (Association) i.next();
151: association.replace(object, leftObject);
152: }
153: }
154:
155: public AssociationList setAssociations(String associations,
156: AssociationFormat associationFormat)
157: throws FieldParseException {
158: AssociationListFormat format = AssociationListFormat
159: .getInstance(associationFormat);
160: AssociationList result = (AssociationList) format.parseObject(
161: associations, new ParsePosition(0));
162: if (result == null) {
163: System.out.println(associationFormat.getParameters()
164: .getError());
165: throw new FieldParseException(associationFormat
166: .getParameters().getError());
167: }
168: LinkedList oldList = list; // (LinkedList) list.clone(); // make a copy of original list since we'll be modifying real list
169: LinkedList newList = result.list;
170:
171: // validate each element in new list
172: try {
173: result.testValid(true);
174: } catch (InvalidAssociationException e) {
175: // newList = oldList;
176:
177: System.out.println(e.getMessage());
178: throw new FieldParseException(e.getMessage());
179: }
180:
181: Association association;
182: Iterator i;
183:
184: // check for duplicates
185: for (i = newList.iterator(); i.hasNext();) {
186: association = (Association) i.next();
187: // if duplicate
188: if (AssociationList.findAssociation(newList, association
189: .getLeft(), association.getRight(), association) != null) {
190: // newList = oldList;
191: throw new FieldParseException("Duplicate association"); //TODO better message
192: }
193: }
194:
195: // At this point, the newList is valid, so now merge
196:
197: // Go through old list figuring out which elements were removed and updating those that are modified.
198: Association oldAssociation;
199: Association newAssociation;
200: LinkedList removed = new LinkedList();
201: LinkedList modified = new LinkedList();
202: for (i = oldList.iterator(); i.hasNext();) {
203: oldAssociation = (Association) i.next();
204: if (oldAssociation.isDefault()) // don't treat default association. It will be removed by later code if needed
205: continue;
206: newAssociation = AssociationList.findAssociation(newList,
207: oldAssociation.getLeft(),
208: oldAssociation.getRight(), null);
209: if (newAssociation == null) {
210: removed.add(oldAssociation);
211: } else {
212: if (associationFormat.getParameters()
213: .isAllowDetailsEntry()) // some fields don't allow you to enter details. In which case, ignore values
214: modified.add(oldAssociation); // for later use?
215: oldAssociation.copyPrincipalFieldsFrom(newAssociation);
216: //TODO fire update event?
217: }
218: }
219:
220: // Remove ones that were eliminated
221: for (i = removed.iterator(); i.hasNext();) {
222: ((Association) i.next()).doRemoveService(this ); // will remove from real list
223: }
224:
225: // Get a list of added elements
226: LinkedList added = new LinkedList();
227: for (i = newList.iterator(); i.hasNext();) {
228: association = (Association) i.next();
229: if (association.isDefault()) // don't treat default association. It will be added by later code if needed
230: continue;
231:
232: // see if new one (not in modified list)
233: if (AssociationList.findAssociation(modified, association
234: .getLeft(), association.getRight(), null) == null) {
235: added.add(association);
236: }
237: }
238:
239: // Add new ones
240: for (i = added.iterator(); i.hasNext();) {
241: ((Association) i.next()).doAddService(this ); // will remove from real list
242: }
243:
244: // Signal update of modified ones
245: for (i = modified.iterator(); i.hasNext();) {
246: ((Association) i.next()).doUpdateService(this ); // will send update message
247: }
248: // sort the resulting list
249: // TODO sort inverse lists too
250: Collections.sort(list, new AssociationComparator(
251: associationFormat.getParameters().getIdField()));
252: return result;
253: }
254:
255: /**
256: * @return
257: */
258: public boolean isEmpty() {
259: return list.isEmpty();
260: }
261:
262: /**
263: * @param arg0
264: * @return
265: */
266: public boolean remove(Object arg0) {
267: return list.remove(arg0);
268: }
269:
270: /**
271: * @param arg0
272: */
273: public void addFirst(Object arg0) {
274: list.addFirst(arg0);
275: }
276:
277: /**
278: * @return
279: */
280: public Iterator iterator() {
281: return list.iterator();
282: }
283:
284: /**
285: * @return Returns the list.
286: */
287: public LinkedList getList() {
288: return list;
289: }
290:
291: /**
292: * @param arg0
293: * @param arg1
294: */
295: public void add(int arg0, Object arg1) {
296: list.add(arg0, arg1);
297: }
298:
299: /**
300: * @param arg0
301: * @return
302: */
303: public boolean add(Object arg0) {
304: return list.add(arg0);
305: }
306:
307: /**
308: * @param arg0
309: * @param arg1
310: * @return
311: */
312: public boolean addAll(int arg0, Collection arg1) {
313: return list.addAll(arg0, arg1);
314: }
315:
316: /**
317: * @param arg0
318: * @return
319: */
320: public boolean addAll(Collection arg0) {
321: return list.addAll(arg0);
322: }
323:
324: /**
325: * @param arg0
326: */
327: public void addLast(Object arg0) {
328: list.addLast(arg0);
329: }
330:
331: /**
332: *
333: */
334: public void clear() {
335: list.clear();
336: }
337:
338: /**
339: * @param arg0
340: * @return
341: */
342: public boolean contains(Object arg0) {
343: return list.contains(arg0);
344: }
345:
346: /**
347: * @param arg0
348: * @return
349: */
350: public boolean containsAll(Collection arg0) {
351: return list.containsAll(arg0);
352: }
353:
354: /* (non-Javadoc)
355: * @see java.lang.Object#equals(java.lang.Object)
356: */
357: public boolean equals(Object arg0) {
358: return list.equals(arg0);
359: }
360:
361: /**
362: * @param arg0
363: * @return
364: */
365: public Object get(int arg0) {
366: return list.get(arg0);
367: }
368:
369: /**
370: * @return
371: */
372: public Object getFirst() {
373: return list.getFirst();
374: }
375:
376: /**
377: * @return
378: */
379: public Object getLast() {
380: return list.getLast();
381: }
382:
383: /* (non-Javadoc)
384: * @see java.lang.Object#hashCode()
385: */
386: public int hashCode() {
387: return list.hashCode();
388: }
389:
390: /**
391: * @param arg0
392: * @return
393: */
394: public int indexOf(Object arg0) {
395: return list.indexOf(arg0);
396: }
397:
398: /**
399: * @param arg0
400: * @return
401: */
402: public int lastIndexOf(Object arg0) {
403: return list.lastIndexOf(arg0);
404: }
405:
406: /**
407: * @return
408: */
409: public ListIterator listIterator() {
410: return list.listIterator();
411: }
412:
413: /**
414: * @param arg0
415: * @return
416: */
417: public ListIterator listIterator(int arg0) {
418: return list.listIterator(arg0);
419: }
420:
421: /**
422: * @param arg0
423: * @return
424: */
425: public Object remove(int arg0) {
426: return list.remove(arg0);
427: }
428:
429: /**
430: * @param arg0
431: * @return
432: */
433: public boolean removeAll(Collection arg0) {
434: return list.removeAll(arg0);
435: }
436:
437: /**
438: * @return
439: */
440: public Object removeFirst() {
441: return list.removeFirst();
442: }
443:
444: /**
445: * @return
446: */
447: public Object removeLast() {
448: return list.removeLast();
449: }
450:
451: /**
452: * @param arg0
453: * @return
454: */
455: public boolean retainAll(Collection arg0) {
456: return list.retainAll(arg0);
457: }
458:
459: /**
460: * @param arg0
461: * @param arg1
462: * @return
463: */
464: public Object set(int arg0, Object arg1) {
465: return list.set(arg0, arg1);
466: }
467:
468: /**
469: * @return
470: */
471: public int size() {
472: return list.size();
473: }
474:
475: /**
476: * @param arg0
477: * @param arg1
478: * @return
479: */
480: public List subList(int arg0, int arg1) {
481: return list.subList(arg0, arg1);
482: }
483:
484: /**
485: * @return
486: */
487: public Object[] toArray() {
488: return list.toArray();
489: }
490:
491: /**
492: * @param arg0
493: * @return
494: */
495: public Object[] toArray(Object[] arg0) {
496: return list.toArray(arg0);
497: }
498:
499: /* (non-Javadoc)
500: * @see java.lang.Object#toString()
501: */
502: public String toString() {
503: return list.toString();
504: }
505:
506: public void dump(boolean leftObject) {
507: Association association;
508: for (Iterator i = list.iterator(); i.hasNext();) {
509: association = (Association) i.next();
510: System.out.println(getObject(association, leftObject));
511: }
512: }
513: }
|