001: package org.tigris.scarab.om;
002:
003: /* ================================================================
004: * Copyright (c) 2000-2005 CollabNet. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions are
008: * met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: *
017: * 3. The end-user documentation included with the redistribution, if
018: * any, must include the following acknowlegement: "This product includes
019: * software developed by Collab.Net <http://www.Collab.Net/>."
020: * Alternately, this acknowlegement may appear in the software itself, if
021: * and wherever such third-party acknowlegements normally appear.
022: *
023: * 4. The hosted project names must not be used to endorse or promote
024: * products derived from this software without prior written
025: * permission. For written permission, please contact info@collab.net.
026: *
027: * 5. Products derived from this software may not use the "Tigris" or
028: * "Scarab" names nor may "Tigris" or "Scarab" appear in their names without
029: * prior written permission of Collab.Net.
030: *
031: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
032: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
033: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
034: * IN NO EVENT SHALL COLLAB.NET OR ITS CONTRIBUTORS BE LIABLE FOR ANY
035: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
036: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
037: * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
038: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
039: * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
040: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
041: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
042: *
043: * ====================================================================
044: *
045: * This software consists of voluntary contributions made by many
046: * individuals on behalf of Collab.Net.
047: */
048:
049: import java.util.List;
050: import java.util.ArrayList;
051: import java.util.LinkedList;
052: import java.util.Iterator;
053: import org.apache.torque.TorqueException;
054: import org.apache.torque.om.SimpleKey;
055: import org.apache.torque.om.Persistent;
056: import org.apache.torque.util.Criteria;
057:
058: import org.tigris.scarab.services.security.ScarabSecurity;
059: import org.tigris.scarab.services.cache.ScarabCache;
060: import org.tigris.scarab.tools.localization.L10NKeySet;
061: import org.tigris.scarab.om.Module;
062: import org.tigris.scarab.om.ModuleManager;
063: import org.tigris.scarab.util.ScarabException;
064: import org.tigris.scarab.util.Log;
065: import org.tigris.scarab.workflow.WorkflowFactory;
066:
067: /**
068: * You should add additional methods to this class to meet the
069: * application requirements. This class will only be generated as
070: * long as it does not already exist in the output directory.
071: */
072: public class AttributeGroup extends BaseAttributeGroup implements
073: Persistent {
074: // the following Strings are method names that are used in caching results
075: public static final String GET_ATTRIBUTES = "getAttributes";
076: private static final String GET_R_ATTRIBUTE_ATTRGROUP = "getRAttributeAttributeGroup";
077:
078: public boolean isGlobal() throws TorqueException {
079: return (getModule() == null);
080: }
081:
082: /**
083: * Throws UnsupportedOperationException. Use
084: * <code>getModule()</code> instead.
085: *
086: * @return a <code>ScarabModule</code> value
087: */
088: public ScarabModule getScarabModule() {
089: throw new UnsupportedOperationException("Should use getModule"); //EXCEPTION
090: }
091:
092: /**
093: * Throws UnsupportedOperationException. Use
094: * <code>setModule(Module)</code> instead.
095: *
096: */
097: public void setScarabModule(ScarabModule module) {
098: throw new UnsupportedOperationException(
099: "Should use setModule(Module). Note module cannot be new."); //EXCEPTION
100: }
101:
102: /**
103: * Use this instead of setScarabModule. Note: module cannot be new.
104: */
105: public void setModule(Module me) throws TorqueException {
106: Integer id = me.getModuleId();
107: if (id == null) {
108: throw new TorqueException("Modules must be saved prior to "
109: + "being associated with other objects."); //EXCEPTION
110: }
111: setModuleId(id);
112: }
113:
114: /**
115: * Module getter. Use this method instead of getScarabModule().
116: *
117: * @return a <code>Module</code> value
118: */
119: public Module getModule() throws TorqueException {
120: Module module = null;
121: Integer id = getModuleId();
122: if (id != null) {
123: module = ModuleManager.getInstance(id);
124: }
125:
126: return module;
127: }
128:
129: private static org.apache.torque.manager.MethodResultCache getMethodResult() {
130: return AttributeGroupManager.getMethodResult();
131: }
132:
133: public boolean hasAnyOptionAttributes() throws TorqueException {
134: boolean result = false;
135: for (Iterator i = getAttributes().iterator(); i.hasNext()
136: && !result;) {
137: result = ((Attribute) i.next()).isOptionAttribute();
138: }
139: return result;
140: }
141:
142: /**
143: * List of Attributes in this group.
144: */
145: public List getAttributes() throws TorqueException {
146: List result = null;
147: Object obj = getMethodResult().get(this , GET_ATTRIBUTES);
148: if (obj == null) {
149: Log.get().debug(
150: "getAttributes() not cached, getting from db");
151: Criteria crit = new Criteria()
152: .add(RAttributeAttributeGroupPeer.GROUP_ID,
153: getAttributeGroupId())
154: .addJoin(RAttributeAttributeGroupPeer.ATTRIBUTE_ID,
155: AttributePeer.ATTRIBUTE_ID)
156: .add(AttributePeer.ATTRIBUTE_TYPE_ID,
157: AttributeTypePeer.USER_TYPE_KEY,
158: Criteria.NOT_EQUAL)
159: .add(AttributePeer.DELETED, false)
160: .addAscendingOrderByColumn(
161: RAttributeAttributeGroupPeer.PREFERRED_ORDER);
162: List raags = RAttributeAttributeGroupPeer.doSelect(crit);
163: result = new LinkedList();
164: Iterator i = raags.iterator();
165: while (i.hasNext()) {
166: Integer id = ((RAttributeAttributeGroup) i.next())
167: .getAttributeId();
168: result.add(AttributeManager.getInstance(SimpleKey
169: .keyFor(id)));
170: if (Log.get().isDebugEnabled()) {
171: Log
172: .get()
173: .debug(
174: "attribute id="
175: + id
176: + "'s relationship to group was in db");
177: }
178: }
179: getMethodResult().put(result, this , GET_ATTRIBUTES);
180: } else {
181: result = (List) obj;
182: if (Log.get().isDebugEnabled()) {
183: Log.get().debug(
184: "getAttributes() returning cached value");
185: for (Iterator i = result.iterator(); i.hasNext();) {
186: Log
187: .get()
188: .debug(
189: "attribute id="
190: + ((Attribute) i.next())
191: .getAttributeId()
192: + "'s relationship to group was in cache");
193: }
194: }
195: }
196: return result;
197: }
198:
199: /**
200: * @param attribute The attribute to check for the existance of in
201: * this group.
202: * @return Whether this attribute group has <code>attribute</code>
203: * as an attribute.
204: */
205: public boolean hasAttribute(Attribute attribute)
206: throws TorqueException {
207: List raags = getAttributes();
208: return (raags != null && raags.contains(attribute));
209: }
210:
211: /**
212: * Retrieves the attribute in this group with the highest preferred order.
213: */
214: public int getHighestOrderedAttribute() throws TorqueException {
215: int highest = 0;
216: Criteria crit = new Criteria().add(
217: RAttributeAttributeGroupPeer.GROUP_ID,
218: getAttributeGroupId()).addAscendingOrderByColumn(
219: RAttributeAttributeGroupPeer.PREFERRED_ORDER);
220: List raags = RAttributeAttributeGroupPeer.doSelect(crit);
221: if (raags.size() > 0) {
222: RAttributeAttributeGroup raag = (RAttributeAttributeGroup) raags
223: .get(raags.size() - 1);
224: highest = raag.getOrder();
225: }
226: return highest + 1;
227: }
228:
229: /**
230: * Retrieves R_ATTRIBUTE_ATTRIBUTEGROUP mapping object for this group
231: * And the given attribute.
232: */
233: public RAttributeAttributeGroup getRAttributeAttributeGroup(
234: Attribute attribute) throws TorqueException {
235: RAttributeAttributeGroup result = null;
236: Object obj = ScarabCache.get(this , GET_R_ATTRIBUTE_ATTRGROUP,
237: attribute);
238: if (obj == null) {
239: Criteria crit = new Criteria().add(
240: RAttributeAttributeGroupPeer.GROUP_ID,
241: getAttributeGroupId()).add(
242: RAttributeAttributeGroupPeer.ATTRIBUTE_ID,
243: attribute.getAttributeId());
244:
245: result = (RAttributeAttributeGroup) RAttributeAttributeGroupPeer
246: .doSelect(crit).get(0);
247: ScarabCache.put(result, this , GET_R_ATTRIBUTE_ATTRGROUP,
248: attribute);
249: } else {
250: result = (RAttributeAttributeGroup) obj;
251: }
252: return result;
253: }
254:
255: /**
256: * List of module-attribute mappings in this group. If there
257: * are no attributes, this method returns an empty list.
258: */
259: public List getRModuleAttributes() throws TorqueException {
260: List attrs = getAttributes();
261: Iterator i = attrs.iterator();
262: List rmas = new ArrayList(attrs.size());
263: while (i.hasNext()) {
264: Attribute attr = (Attribute) i.next();
265: RModuleAttribute rma = getModule().getRModuleAttribute(
266: attr, getIssueType());
267: if (rma != null) {
268: rmas.add(rma);
269: }
270: }
271: return rmas;
272: }
273:
274: /**
275: * List of global issuetype-attribute mappings in this group.
276: * If there are no attributes in this group, then this returns
277: * an empty list.
278: */
279: public List getRIssueTypeAttributes() throws TorqueException {
280: List attrs = getAttributes();
281: Iterator i = attrs.iterator();
282: List rias = new ArrayList(attrs.size());
283: while (i.hasNext()) {
284: Attribute attr = (Attribute) i.next();
285: RIssueTypeAttribute ria = getIssueType()
286: .getRIssueTypeAttribute(attr);
287:
288: if (ria != null) {
289: rias.add(ria);
290: }
291: }
292:
293: return rias;
294: }
295:
296: public void delete() throws TorqueException, ScarabException {
297: int dupeSequence = 0;
298: final Integer issueTypeId = getIssueTypeId();
299: final IssueType issueType = IssueTypeManager.getInstance(
300: SimpleKey.keyFor(issueTypeId), false);
301: List attrGroups = null;
302:
303: if (isGlobal()) {
304: attrGroups = issueType.getAttributeGroups(null, false);
305: dupeSequence = issueType.getDedupeSequence();
306: // Delete issuetype-attribute mapping
307: final Criteria crit = new Criteria().addJoin(
308: RIssueTypeAttributePeer.ATTRIBUTE_ID,
309: RAttributeAttributeGroupPeer.ATTRIBUTE_ID).add(
310: RAttributeAttributeGroupPeer.GROUP_ID,
311: getAttributeGroupId()).add(
312: RIssueTypeAttributePeer.ISSUE_TYPE_ID, issueTypeId);
313: final List results = RIssueTypeAttributePeer.doSelect(crit);
314: for (Iterator i = results.iterator(); i.hasNext();) {
315: ((RIssueTypeAttribute) i.next()).delete();
316: }
317: } else {
318: if (issueType.getLocked()) {
319:
320: throw new ScarabException(
321: L10NKeySet.ExceptionGroupDeleteForbidden, this
322: .getName(), issueType.getName());
323: } else {
324: final Module module = getModule();
325: attrGroups = getIssueType().getAttributeGroups(module,
326: false);
327: dupeSequence = module.getDedupeSequence(issueType);
328: // Delete module-attribute mapping
329: final Criteria crit = new Criteria().addJoin(
330: RModuleAttributePeer.ATTRIBUTE_ID,
331: RAttributeAttributeGroupPeer.ATTRIBUTE_ID).add(
332: RAttributeAttributeGroupPeer.GROUP_ID,
333: getAttributeGroupId()).add(
334: RModuleAttributePeer.MODULE_ID, getModuleId());
335: final Criteria.Criterion critIssueType = crit
336: .getNewCriterion(
337: RModuleAttributePeer.ISSUE_TYPE_ID,
338: getIssueTypeId(), Criteria.EQUAL);
339: critIssueType.or(crit.getNewCriterion(
340: RModuleAttributePeer.ISSUE_TYPE_ID, issueType
341: .getTemplateId(), Criteria.EQUAL));
342: crit.and(critIssueType);
343: final List results = RModuleAttributePeer
344: .doSelect(crit);
345: for (int i = 0; i < results.size(); i++) {
346: final RModuleAttribute rma = (RModuleAttribute) results
347: .get(i);
348: rma.delete();
349: }
350: }
351: }
352:
353: // Delete attribute - attribute group mapping
354: Criteria crit2 = new Criteria().add(
355: RAttributeAttributeGroupPeer.GROUP_ID,
356: getAttributeGroupId());
357: RAttributeAttributeGroupPeer.doDelete(crit2);
358:
359: // Delete the attribute group
360: final int order = getOrder();
361: crit2 = new Criteria().add(
362: AttributeGroupPeer.ATTRIBUTE_GROUP_ID,
363: getAttributeGroupId());
364: AttributeGroupPeer.doDelete(crit2);
365: IssueTypeManager.getManager().refreshedObject(this );
366:
367: // Adjust the orders for the other attribute groups
368: for (int i = 0; i < attrGroups.size(); i++) {
369: final AttributeGroup tempGroup = (AttributeGroup) attrGroups
370: .get(i);
371: int tempOrder = tempGroup.getOrder();
372: if (tempGroup.getOrder() > order) {
373: if (tempOrder == dupeSequence + 1 && tempOrder == 3) {
374: tempGroup.setOrder(tempOrder - 2);
375: } else {
376: tempGroup.setOrder(tempOrder - 1);
377: }
378: tempGroup.save();
379: }
380: }
381: }
382:
383: public void addAttribute(final Attribute attribute)
384: throws TorqueException, ScarabException {
385: final IssueType issueType = getIssueType();
386: final Module module = getModule();
387:
388: // add attribute group-attribute mapping
389: final RAttributeAttributeGroup raag = addRAttributeAttributeGroup(attribute);
390: raag.save();
391: if (Log.get().isDebugEnabled()) {
392: Log.get().debug(
393: "Calling getAttributes() from addAttribute in order to add attribute id="
394: + attribute.getAttributeId()
395: + " to the List");
396: }
397: // FIXME! Distributed cache buster, cache should be invalidated.
398: final List attributes = getAttributes();
399: if (!attributes.contains(attribute)) {
400: attributes.add(attribute);
401: }
402:
403: final List allOptions = attribute.getAttributeOptions(false);
404: // remove duplicate options
405: // FIXME! why would we ever want Attribute.getAttributeOptions to
406: // return dupes, should this code be in that method?
407: final ArrayList options = new ArrayList();
408: for (int i = 0; i < allOptions.size(); i++) {
409: final AttributeOption option = (AttributeOption) allOptions
410: .get(i);
411: if (!options.contains(option)) {
412: options.add(option);
413: }
414: }
415:
416: if (isGlobal()) {
417: // this is a global attribute group
418: // add issuetype-attribute groupings
419: issueType.addRIssueTypeAttribute(attribute);
420:
421: // add issueType-attributeoption mappings
422: for (int j = 0; j < options.size(); j++) {
423: final AttributeOption option = (AttributeOption) options
424: .get(j);
425: final List roos = option
426: .getROptionOptionsRelatedByOption2Id();
427: final ROptionOption roo = (ROptionOption) roos.get(0);
428: final RIssueTypeOption rio = new RIssueTypeOption();
429: rio.setIssueTypeId(issueType.getIssueTypeId());
430: rio.setOptionId(option.getOptionId());
431: rio.setOrder(roo.getPreferredOrder());
432: rio.setWeight(roo.getWeight());
433: // making sure error is recorded in same log as our other
434: // debugging for pcn 17683.
435: try {
436: rio.save();
437: } catch (TorqueException e) {
438: Log.get().error("Exception saving rio", e);
439: throw e; //EXCEPTION
440: }
441: }
442: } else {
443: // add module-attribute groupings
444: module.addRModuleAttribute(issueType, attribute);
445:
446: // add module-attributeoption mappings
447: for (int j = 0; j < options.size(); j++) {
448: final AttributeOption option = (AttributeOption) options
449: .get(j);
450: final List roos = option
451: .getROptionOptionsRelatedByOption2Id();
452: final ROptionOption roo = (ROptionOption) roos.get(0);
453: final RModuleOption rmo = new RModuleOption();
454: rmo.setModuleId(getModuleId());
455: rmo.setIssueTypeId(issueType.getIssueTypeId());
456: rmo.setOptionId(option.getOptionId());
457: rmo.setDisplayValue(option.getName());
458: rmo.setOrder(roo.getPreferredOrder());
459: rmo.setWeight(roo.getWeight());
460: rmo.save();
461:
462: // add module-attributeoption mappings to template type
463: final IssueType templateType = IssueTypeManager
464: .getInstance(issueType.getTemplateId(), false);
465: final RModuleOption rmo2 = module.addRModuleOption(
466: templateType, option);
467: rmo2.save();
468: }
469: }
470: getMethodResult().remove(this , AttributeGroup.GET_ATTRIBUTES);
471: }
472:
473: public void deleteAttribute(final Attribute attribute,
474: final ScarabUser user, final Module module)
475: throws TorqueException, ScarabException {
476: String permission = null;
477: if (isGlobal()) {
478: permission = (ScarabSecurity.DOMAIN__EDIT);
479: } else {
480: permission = (ScarabSecurity.MODULE__CONFIGURE);
481: }
482: if (user.hasPermission(permission, module)) {
483: final IssueType issueType = getIssueType();
484: final IssueType template = IssueTypeManager
485: .getInstance(issueType.getTemplateId());
486: boolean success = true;
487:
488: final RIssueTypeAttribute ria = issueType
489: .getRIssueTypeAttribute(attribute);
490: if (isGlobal()) {
491: // This is a global attribute group
492: // Remove attribute - issue type mapping
493: final List rias = issueType.getRIssueTypeAttributes(
494: false, AttributePeer.NON_USER);
495: if (ria != null) {
496: ria.delete();
497: }
498: if (rias != null) {
499: rias.remove(ria);
500: }
501: } else {
502: // Check if attribute is locked
503: if (ria != null && ria.getLocked()) {
504: success = false;
505: throw new TorqueException(attribute.getName()
506: + "is locked"); //EXCEPTION
507: } else {
508: // Remove attribute - module mapping
509: final List rmas = module.getRModuleAttributes(
510: issueType, false, AttributePeer.NON_USER);
511: final RModuleAttribute rma = module
512: .getRModuleAttribute(attribute, issueType);
513: rma.delete();
514: WorkflowFactory.getInstance()
515: .deleteWorkflowsForAttribute(attribute,
516: module, issueType);
517: rmas.remove(rma);
518:
519: // Remove attribute - module mapping from template type
520: final RModuleAttribute rma2 = module
521: .getRModuleAttribute(attribute, template);
522: rma2.delete();
523: rmas.remove(rma2);
524: }
525: }
526:
527: if (success) {
528: // Remove attribute - group mapping
529: final RAttributeAttributeGroup raag = getRAttributeAttributeGroup(attribute);
530: raag.delete();
531:
532: if (attribute.isOptionAttribute()) {
533: if (isGlobal()) {
534: // global attributeGroup; remove issuetype-option maps
535: final List rios = issueType
536: .getRIssueTypeOptions(attribute);
537: if (rios != null) {
538: for (int i = 0; i < rios.size(); i++) {
539: ((RIssueTypeOption) rios.get(i))
540: .delete(user, module);
541: }
542: }
543: } else {
544: // Remove module-option mapping
545: final List rmos = module.getRModuleOptions(
546: attribute, issueType);
547: if (rmos != null) {
548: rmos.addAll(module.getRModuleOptions(
549: attribute, template));
550: for (int j = 0; j < rmos.size(); j++) {
551: final RModuleOption rmo = (RModuleOption) rmos
552: .get(j);
553: // rmo's may be inherited by the parent module.
554: // don't delete unless they are directly associated
555: // with this module. Will know by the first one.
556: if (rmo.getModuleId().equals(
557: module.getModuleId())) {
558: rmo.delete();
559: } else {
560: break;
561: }
562: }
563: }
564: }
565: }
566: }
567: } else {
568: throw new ScarabException(
569: L10NKeySet.YouDoNotHavePermissionToAction);
570: }
571: getMethodResult().remove(this , AttributeGroup.GET_ATTRIBUTES);
572: }
573:
574: private RAttributeAttributeGroup addRAttributeAttributeGroup(
575: Attribute attribute) throws TorqueException {
576: RAttributeAttributeGroup raag = new RAttributeAttributeGroup();
577: raag.setGroupId(getAttributeGroupId());
578: raag.setAttributeId(attribute.getAttributeId());
579: if (Log.get().isDebugEnabled()) {
580: Log
581: .get()
582: .debug(
583: "Calling getAttributes() from addRAttributeAttributeGroup "
584: + "in order to determine order for attribute id="
585: + attribute.getAttributeId());
586: }
587: raag.setOrder(getAttributes().size() + 1);
588: return raag;
589: }
590:
591: public AttributeGroup copyGroup() throws TorqueException {
592: AttributeGroup newGroup = new AttributeGroup();
593: newGroup.setName(getName());
594: newGroup.setDescription(getDescription());
595: newGroup.setDedupe(getDedupe());
596: newGroup.setActive(getActive());
597: newGroup.setOrder(getOrder());
598: return newGroup;
599: }
600: }
|