0001: package org.tigris.scarab.om;
0002:
0003: /* ================================================================
0004: * Copyright (c) 2000-2005 CollabNet. All rights reserved.
0005: *
0006: * Redistribution and use in source and binary forms, with or without
0007: * modification, are permitted provided that the following conditions are
0008: * met:
0009: *
0010: * 1. Redistributions of source code must retain the above copyright
0011: * notice, this list of conditions and the following disclaimer.
0012: *
0013: * 2. Redistributions in binary form must reproduce the above copyright
0014: * notice, this list of conditions and the following disclaimer in the
0015: * documentation and/or other materials provided with the distribution.
0016: *
0017: * 3. The end-user documentation included with the redistribution, if
0018: * any, must include the following acknowlegement: "This product includes
0019: * software developed by Collab.Net <http://www.Collab.Net/>."
0020: * Alternately, this acknowlegement may appear in the software itself, if
0021: * and wherever such third-party acknowlegements normally appear.
0022: *
0023: * 4. The hosted project names must not be used to endorse or promote
0024: * products derived from this software without prior written
0025: * permission. For written permission, please contact info@collab.net.
0026: *
0027: * 5. Products derived from this software may not use the "Tigris" or
0028: * "Scarab" names nor may "Tigris" or "Scarab" appear in their names without
0029: * prior written permission of Collab.Net.
0030: *
0031: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0032: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
0033: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
0034: * IN NO EVENT SHALL COLLAB.NET OR ITS CONTRIBUTORS BE LIABLE FOR ANY
0035: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0036: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
0037: * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0038: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
0039: * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
0040: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
0041: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0042: *
0043: * ====================================================================
0044: *
0045: * This software consists of voluntary contributions made by many
0046: * individuals on behalf of Collab.Net.
0047: */
0048:
0049: import com.workingdogs.village.DataSetException;
0050: import java.util.Set;
0051: import java.util.HashSet;
0052: import java.util.List;
0053: import java.util.ArrayList;
0054: import java.util.Iterator;
0055: import java.util.Collections;
0056: import java.sql.Connection;
0057: import org.apache.fulcrum.security.util.TurbineSecurityException;
0058: import org.apache.torque.om.Persistent;
0059: import org.apache.torque.util.Criteria;
0060: import org.apache.torque.TorqueException;
0061: import org.apache.torque.TorqueRuntimeException;
0062: import org.tigris.scarab.services.security.ScarabSecurity;
0063: import org.tigris.scarab.tools.localization.L10NKeySet;
0064: import org.tigris.scarab.util.Log;
0065: import org.tigris.scarab.util.ScarabException;
0066:
0067: /**
0068: * A class representing a list (not List) of MITListItems. MIT stands for
0069: * Module and IssueType. This class contains corresponding methods to many
0070: * in Module which take a single IssueType. for example
0071: * module.getAttributes(issueType) is replaced with
0072: * mitList.getCommonAttributes() in cases where several modules and issuetypes
0073: * are involved.
0074: *
0075: * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
0076: * @author <a href="mailto:jmcnally@collab.net">John McNally</a>
0077: * @version $Id: MITList.java 10080 2006-04-30 23:38:30Z jorgeuriarte $
0078: */
0079: public class MITList extends BaseMITList implements Persistent {
0080: /**
0081: * A local reference to the user.
0082: */
0083: private ScarabUser aScarabUser;
0084:
0085: private List itemsScheduledForDeletion;
0086:
0087: /**
0088: * Cache the expanded list because it is widely used and unlikely
0089: * to change after initialization.
0090: */
0091: private List expandedList = null;
0092:
0093: /**
0094: * Whether this list represents everything the user can query.
0095: */
0096: private boolean isAllMITs = false;
0097:
0098: public int size() {
0099: int size = 0;
0100: List items = getExpandedMITListItems();
0101: if (items != null) {
0102: size = items.size();
0103: }
0104: return size;
0105: }
0106:
0107: /**
0108: * tests if the list is empty
0109: *
0110: * @return true if the list is empty, otherwise false
0111: */
0112: public boolean isEmpty() {
0113: boolean empty = true;
0114: List items = getExpandedMITListItems();
0115: if (items != null) {
0116: empty = items.isEmpty();
0117: }
0118: return empty;
0119: }
0120:
0121: /**
0122: * asserts that the list is not empty
0123: *
0124: * @throws IllegalStateException if the list is empty
0125: */
0126: private void assertNotEmpty() {
0127: if (isEmpty()) {
0128: throw new IllegalStateException(
0129: "method should not be called on an empty list."); //EXCEPTION
0130: }
0131: }
0132:
0133: public Iterator iterator() {
0134: Iterator i = null;
0135: List items = getExpandedMITListItems();
0136: if (items == null) {
0137: i = Collections.EMPTY_LIST.iterator();
0138: } else {
0139: i = new ItemsIterator(items.iterator());
0140: }
0141: return i;
0142: }
0143:
0144: public boolean contains(MITListItem item) {
0145: boolean result = false;
0146: for (Iterator i = iterator(); i.hasNext() && !result;) {
0147: result = i.next().equals(item);
0148: }
0149: return result;
0150: }
0151:
0152: public class ItemsIterator implements Iterator {
0153: private Iterator i;
0154: private Object currentObject;
0155:
0156: private ItemsIterator(Iterator i) {
0157: this .i = i;
0158: }
0159:
0160: public boolean hasNext() {
0161: return i.hasNext();
0162: }
0163:
0164: public Object next() {
0165: currentObject = i.next();
0166: return currentObject;
0167: }
0168:
0169: public void remove() {
0170: List rawList = null;
0171: try {
0172: rawList = getMITListItems();
0173: } catch (TorqueException e) {
0174: throw new TorqueRuntimeException(e); //EXCEPTION
0175: }
0176:
0177: if (rawList.contains(currentObject)) {
0178: rawList.remove(currentObject);
0179: i.remove();
0180: expandedList = null;
0181: } else {
0182: throw new UnsupportedOperationException(
0183: "Removing items "
0184: + "from a list containing wildcards is not supported."); //EXCEPTION
0185: }
0186: }
0187: }
0188:
0189: /**
0190: * Alias for getModifiable()
0191: *
0192: * @return a <code>boolean</code> value
0193: */
0194: public boolean isModifiable() {
0195: return getModifiable();
0196: }
0197:
0198: public boolean isAnonymous() {
0199: return !isNew() && getName() == null;
0200: }
0201:
0202: /**
0203: * Makes a copy of this object.
0204: * It creates a new object filling in the simple attributes.
0205: * It then fills all the association collections and sets the
0206: * related objects to isNew=true.
0207: */
0208: public MITList copy() throws TorqueException {
0209: MITList copyObj = new MITList();
0210: copyObj.setName(getName());
0211: copyObj.setActive(getActive());
0212: copyObj.setModifiable(getModifiable());
0213: copyObj.setUserId(getUserId());
0214:
0215: List v = getMITListItems();
0216: for (int i = 0; i < v.size(); i++) {
0217: MITListItem obj = (MITListItem) v.get(i);
0218: copyObj.addMITListItem(obj.copy());
0219: }
0220:
0221: return copyObj;
0222: }
0223:
0224: /**
0225: * Creates a new MITList containing only those items from this list
0226: * for which the searcher has the given permission.
0227: *
0228: * @param permission a <code>String</code> value
0229: * @param searcher a <code>ScarabUser</code> value
0230: * @return a <code>MITList</code> value
0231: */
0232: public MITList getPermittedSublist(String permission,
0233: ScarabUser user) throws TorqueException {
0234: String[] perms = { permission };
0235: return getPermittedSublist(perms, user);
0236: }
0237:
0238: /**
0239: * Creates a new MITList containing only those items from this list
0240: * for which the searcher has at least one of the permission.
0241: *
0242: * @param permission a <code>String</code> value
0243: * @param searcher a <code>ScarabUser</code> value
0244: * @return a <code>MITList</code> value
0245: */
0246: public MITList getPermittedSublist(String[] permissions,
0247: ScarabUser user) throws TorqueException {
0248: MITList sublist = new MITList();
0249: ScarabUser userB = getScarabUser();
0250: if (userB != null) {
0251: sublist.setScarabUser(userB);
0252: }
0253: List items = getExpandedMITListItems();
0254: sublist.isAllMITs = this .isAllMITs;
0255: Module[] validModules = user.getModules(permissions);
0256:
0257: Set moduleIds = new HashSet();
0258: for (int j = 0; j < validModules.length; j++) {
0259: moduleIds.add(validModules[j].getModuleId());
0260: }
0261:
0262: for (Iterator i = items.iterator(); i.hasNext();) {
0263: MITListItem item = (MITListItem) i.next();
0264: if (moduleIds.contains(item.getModuleId())) {
0265: // use a copy of the item here to avoid changing the the
0266: // list_id of the original
0267: sublist.addMITListItem(item.copy());
0268: }
0269: }
0270:
0271: return sublist;
0272: }
0273:
0274: public MITListItem getFirstItem() {
0275: MITListItem i = null;
0276: List items = getExpandedMITListItems();
0277: if (items != null) {
0278: i = (MITListItem) items.get(0);
0279: }
0280: return i;
0281: }
0282:
0283: public boolean isSingleModuleIssueType() {
0284: return size() == 1 && getFirstItem().isSingleModuleIssueType();
0285: }
0286:
0287: public boolean isSingleModule() {
0288: List ids = getModuleIds();
0289: return ids.size() == 1;
0290: }
0291:
0292: public boolean isSingleIssueType() {
0293: List ids = getIssueTypeIds();
0294: return ids.size() == 1;
0295: }
0296:
0297: public Module getModule() throws TorqueException {
0298: if (!isSingleModule()) {
0299: throw new IllegalStateException(
0300: "method should not be called on"
0301: + " a list including more than one module."); //EXCEPTION
0302: }
0303: return getModule(getFirstItem());
0304: }
0305:
0306: public IssueType getIssueType() throws TorqueException {
0307: if (!isSingleIssueType()) {
0308: throw new IllegalStateException(
0309: "method should not be called on"
0310: + " a list including more than one issue type."); //EXCEPTION
0311: }
0312: return getFirstItem().getIssueType();
0313: }
0314:
0315: Module getModule(MITListItem item) throws TorqueException {
0316: Module module = null;
0317: if (item.getModuleId() == null) {
0318: module = getScarabUser().getCurrentModule();
0319: } else {
0320: module = item.getModule();
0321: }
0322: return module;
0323: }
0324:
0325: /**
0326: * Declares an association between this object and a ScarabUser object
0327: *
0328: * @param v
0329: */
0330: public void setScarabUser(ScarabUser v) throws TorqueException {
0331: if (v == null) {
0332: throw new IllegalArgumentException(
0333: "cannot set user to null."); //EXCEPTION
0334: }
0335:
0336: super .setScarabUser(v);
0337: aScarabUser = v;
0338: expandedList = null;
0339: }
0340:
0341: public ScarabUser getScarabUser() throws TorqueException {
0342: ScarabUser user = null;
0343: if (aScarabUser == null) {
0344: user = super .getScarabUser();
0345: } else {
0346: user = aScarabUser;
0347: }
0348: return user;
0349: }
0350:
0351: /**
0352: * Get the list of all attributes in this MITList.
0353: * If activeOnly is set to true, return only active attrivutes.
0354: * If commonOnly is true,return only attributes, which are common
0355: * in all MITListItems in this list.
0356: * @param activeOnly
0357: * @param commonOnly
0358: * @return
0359: * @throws TorqueException
0360: * @throws DataSetException
0361: */
0362: public List getAttributes(final boolean activeOnly,
0363: final boolean commonOnly) throws TorqueException,
0364: DataSetException {
0365:
0366: Set matchingAttributes = new HashSet();
0367: Iterator iter = iterator();
0368: while (iter.hasNext()) {
0369: final MITListItem item = (MITListItem) iter.next();
0370: final List rmas = getModule(item).getRModuleAttributes(
0371: item.getIssueType());
0372: for (Iterator i = rmas.iterator(); i.hasNext();) {
0373: final RModuleAttribute rma = (RModuleAttribute) i
0374: .next();
0375: final Attribute att = rma.getAttribute();
0376: if ((!activeOnly || rma.getActive())) {
0377: boolean wantedAttribute = (commonOnly) ? isCommon(
0378: att, activeOnly) : true;
0379: if (size() == 1 || wantedAttribute) {
0380: matchingAttributes.add(att);
0381: }
0382: }
0383: }
0384: if (commonOnly) {
0385: // don't need to iterate through other Items, because the
0386: // intersection with the first MITListItem is sufficient
0387: // to fulfill the commonOnly rule.
0388: break;
0389: }
0390: }
0391:
0392: // Finally copy the resultset into an ArrayList for
0393: // compatibility to older implementaiton of this method.
0394: final List result = new ArrayList();
0395: iter = matchingAttributes.iterator();
0396: while (iter.hasNext()) {
0397: result.add(iter.next());
0398: }
0399: return result;
0400: }
0401:
0402: public List getCommonAttributes() throws TorqueException,
0403: DataSetException {
0404: return getAttributes(true, true);
0405: }
0406:
0407: public List getCommonAttributes(final boolean activeOnly)
0408: throws TorqueException, DataSetException {
0409: return getAttributes(activeOnly, true);
0410: }
0411:
0412: /**
0413: * Checks all items to see if they contain the attribute.
0414: *
0415: * @param attribute an <code>Attribute</code> value
0416: * @return a <code>boolean</code> value
0417: */
0418: public boolean isCommon(final Attribute attribute,
0419: final boolean activeOnly) throws TorqueException,
0420: DataSetException {
0421: final Criteria crit = new Criteria();
0422: addToCriteria(crit, RModuleAttributePeer.MODULE_ID,
0423: RModuleAttributePeer.ISSUE_TYPE_ID);
0424: crit.add(RModuleAttributePeer.ATTRIBUTE_ID, attribute
0425: .getAttributeId());
0426: if (activeOnly) {
0427: crit.add(RModuleAttributePeer.ACTIVE, true);
0428: }
0429:
0430: return size() == RModuleAttributePeer.count(crit);
0431: }
0432:
0433: public boolean isCommon(final Attribute attribute)
0434: throws TorqueException, DataSetException {
0435: return isCommon(attribute, true);
0436: }
0437:
0438: public List getCommonNonUserAttributes() throws TorqueException,
0439: DataSetException {
0440: assertNotEmpty();
0441:
0442: final List matchingAttributes = new ArrayList();
0443: final MITListItem item = getFirstItem();
0444:
0445: final List rmas = getModule(item).getRModuleAttributes(
0446: item.getIssueType());
0447: final Iterator i = rmas.iterator();
0448: while (i.hasNext()) {
0449: final RModuleAttribute rma = (RModuleAttribute) i.next();
0450: final Attribute att = rma.getAttribute();
0451: if (!att.isUserAttribute() && rma.getActive()
0452: && isCommon(att)) {
0453: matchingAttributes.add(att);
0454: }
0455: }
0456:
0457: return matchingAttributes;
0458: }
0459:
0460: public List getCommonOptionAttributes() throws TorqueException,
0461: DataSetException {
0462: assertNotEmpty();
0463:
0464: final List matchingAttributes = new ArrayList();
0465: final MITListItem item = getFirstItem();
0466:
0467: final List rmas = getModule(item).getRModuleAttributes(
0468: item.getIssueType());
0469: final Iterator i = rmas.iterator();
0470: while (i.hasNext()) {
0471: final RModuleAttribute rma = (RModuleAttribute) i.next();
0472: final Attribute att = rma.getAttribute();
0473: if (att.isOptionAttribute() && rma.getActive()
0474: && isCommon(att)) {
0475: matchingAttributes.add(att);
0476: }
0477: }
0478:
0479: return matchingAttributes;
0480: }
0481:
0482: /**
0483: * gets a list of all of the User Attributes common to all modules in
0484: * the list.
0485: */
0486: public List getCommonUserAttributes(final boolean activeOnly)
0487: throws TorqueException, DataSetException {
0488: List attributes = null;
0489: if (isSingleModuleIssueType()) {
0490: attributes = getModule().getUserAttributes(getIssueType(),
0491: activeOnly);
0492: } else {
0493: final List matchingAttributes = new ArrayList();
0494: final MITListItem item = getFirstItem();
0495: final List rmas = getModule(item).getRModuleAttributes(
0496: item.getIssueType(), activeOnly, Module.USER);
0497: final Iterator i = rmas.iterator();
0498: while (i.hasNext()) {
0499: final RModuleAttribute rma = (RModuleAttribute) i
0500: .next();
0501: final Attribute att = rma.getAttribute();
0502: if ((!activeOnly || rma.getActive())
0503: && isCommon(att, activeOnly)) {
0504: matchingAttributes.add(att);
0505: }
0506: }
0507: attributes = matchingAttributes;
0508: }
0509: return attributes;
0510: }
0511:
0512: public List getCommonUserAttributes() throws TorqueException,
0513: DataSetException {
0514: return getCommonUserAttributes(false);
0515: }
0516:
0517: /**
0518: * potential assignee must have at least one of the permissions
0519: * for the user attributes in all the modules.
0520: */
0521: public List getPotentialAssignees(boolean includeCommitters)
0522: throws TorqueException, DataSetException {
0523: List users = new ArrayList();
0524: List perms = getUserAttributePermissions();
0525: if (includeCommitters
0526: && !perms.contains(ScarabSecurity.ISSUE__ENTER)) {
0527: perms.add(ScarabSecurity.ISSUE__ENTER);
0528: }
0529: if (isSingleModule()) {
0530: ScarabUser[] userArray = getModule().getUsers(perms);
0531: for (int i = 0; i < userArray.length; i++) {
0532: users.add(userArray[i]);
0533: }
0534: } else {
0535: MITListItem item = getFirstItem();
0536: ScarabUser[] userArray = getModule(item).getUsers(perms);
0537: List modules = getModules();
0538: for (int i = 0; i < userArray.length; i++) {
0539: boolean validUser = false;
0540: ScarabUser user = userArray[i];
0541: for (Iterator j = perms.iterator(); j.hasNext()
0542: && !validUser;) {
0543: validUser = user.hasPermission((String) j.next(),
0544: modules);
0545: }
0546: if (validUser) {
0547: users.add(user);
0548: }
0549: }
0550: }
0551: return users;
0552: }
0553:
0554: /**
0555: * gets a list of permissions associated with the User Attributes
0556: * that are active for this Module.
0557: */
0558: public List getUserAttributePermissions() throws TorqueException,
0559: DataSetException {
0560: final List userAttrs = getCommonUserAttributes();
0561: final List permissions = new ArrayList();
0562: for (int i = 0; i < userAttrs.size(); i++) {
0563: final String permission = ((Attribute) userAttrs.get(i))
0564: .getPermission();
0565: if (!permissions.contains(permission)) {
0566: permissions.add(permission);
0567: }
0568: }
0569: return permissions;
0570: }
0571:
0572: public List getAllRModuleUserAttributes() throws TorqueException,
0573: DataSetException, TurbineSecurityException {
0574: List rmuas = getSavedRMUAs();
0575: return rmuas;
0576: }
0577:
0578: public List getCommonRModuleUserAttributes()
0579: throws TorqueException, DataSetException,
0580: TurbineSecurityException {
0581: final List matchingRMUAs = new ArrayList();
0582: List rmuas = getSavedRMUAs();
0583: Iterator i = rmuas.iterator();
0584: final ScarabUser user = getScarabUser();
0585: while (i.hasNext()) {
0586: final RModuleUserAttribute rmua = (RModuleUserAttribute) i
0587: .next();
0588: final Attribute att = rmua.getAttribute();
0589: if (isCommon(att, false)) {
0590: matchingRMUAs.add(rmua);
0591: }
0592: }
0593:
0594: // None of the saved RMUAs are common for these pairs
0595: // Delete them and seek new ones.
0596: if (matchingRMUAs.isEmpty()) {
0597: i = rmuas.iterator();
0598: while (i.hasNext()) {
0599: final RModuleUserAttribute rmua = (RModuleUserAttribute) i
0600: .next();
0601: rmua.delete(user);
0602: }
0603: final int sizeGoal = 3;
0604: int moreAttributes = sizeGoal;
0605:
0606: // First try saved RMUAs for first module-issuetype pair
0607: final MITListItem item = getFirstItem();
0608: final Module module = getModule(item);
0609: final IssueType issueType = item.getIssueType();
0610: rmuas = user.getRModuleUserAttributes(module, issueType);
0611: // Next try default RMUAs for first module-issuetype pair
0612: if (rmuas.isEmpty()) {
0613: rmuas = module
0614: .getDefaultRModuleUserAttributes(issueType);
0615: }
0616:
0617: // Loop through these and if find common ones, save the RMUAs
0618: i = rmuas.iterator();
0619: while (i.hasNext() && moreAttributes > 0) {
0620: final RModuleUserAttribute rmua = (RModuleUserAttribute) i
0621: .next();
0622: final Attribute att = rmua.getAttribute();
0623: if (isCommon(att, false)
0624: && !matchingRMUAs.contains(rmua)) {
0625: final RModuleUserAttribute newRmua = getNewRModuleUserAttribute(att);
0626: newRmua.setOrder(1);
0627: newRmua.save();
0628: matchingRMUAs.add(rmua);
0629: moreAttributes--;
0630: }
0631: }
0632:
0633: // if nothing better, go with random common attributes
0634: moreAttributes = sizeGoal - matchingRMUAs.size();
0635: if (moreAttributes > 0) {
0636: Iterator attributes = getCommonAttributes(false)
0637: .iterator();
0638: int k = 1;
0639: while (attributes.hasNext() && moreAttributes > 0) {
0640: Attribute att = (Attribute) attributes.next();
0641: boolean isInList = false;
0642: i = matchingRMUAs.iterator();
0643: while (i.hasNext()) {
0644: RModuleUserAttribute rmua = (RModuleUserAttribute) i
0645: .next();
0646: if (rmua.getAttribute().equals(att)) {
0647: isInList = true;
0648: break;
0649: }
0650: }
0651: if (!isInList) {
0652: RModuleUserAttribute rmua = getNewRModuleUserAttribute(att);
0653: rmua.setOrder(k++);
0654: rmua.save();
0655: matchingRMUAs.add(rmua);
0656: moreAttributes--;
0657: }
0658: }
0659: }
0660: }
0661:
0662: return matchingRMUAs;
0663: }
0664:
0665: protected RModuleUserAttribute getNewRModuleUserAttribute(
0666: Attribute attribute) throws TorqueException {
0667: RModuleUserAttribute result = RModuleUserAttributeManager
0668: .getInstance();
0669: result.setUserId(getUserId());
0670: result.setAttributeId(attribute.getAttributeId());
0671:
0672: if (isSingleModuleIssueType()) {
0673: result.setModuleId(getModule().getModuleId());
0674: result.setIssueTypeId(getIssueType().getIssueTypeId());
0675: }
0676:
0677: if (!isNew()) {
0678: result.setListId(getListId());
0679: }
0680: return result;
0681: }
0682:
0683: /**
0684: * get common and active RMOs.
0685: *
0686: * @param rmos a list of RModuleOptions
0687: * @return the sublist of common and active RMOs
0688: * @throws TorqueException
0689: * @throws TorqueException
0690: *
0691: * TODO write a more generic search routine (e.g. for getCommonAttributes,
0692: * getCommonNonUserAttributes, getCommonOptionAttributes, ...)
0693: */
0694: private List getMatchingRMOs(List rmos) throws TorqueException,
0695: Exception {
0696: List matchingRMOs = new ArrayList();
0697: if (rmos != null) {
0698: for (Iterator i = rmos.iterator(); i.hasNext();) {
0699: RModuleOption rmo = (RModuleOption) i.next();
0700: AttributeOption option = rmo.getAttributeOption();
0701: if (rmo.getActive() && isCommon(option)) {
0702: matchingRMOs.add(rmo);
0703: }
0704: }
0705: }
0706: return matchingRMOs;
0707: }
0708:
0709: protected List getSavedRMUAs() throws TorqueException {
0710: Criteria crit = new Criteria();
0711: crit.add(RModuleUserAttributePeer.USER_ID, getUserId());
0712: if (!isNew()) {
0713: Long listId = getListId();
0714: crit.add(RModuleUserAttributePeer.LIST_ID, listId);
0715: } else {
0716: Integer moduleId;
0717: Integer issueTypeId;
0718:
0719: if (isSingleModuleIssueType()) {
0720: moduleId = getModule().getModuleId();
0721: issueTypeId = getIssueType().getIssueTypeId();
0722: } else if (isSingleModule()) {
0723: moduleId = getModule().getModuleId();
0724: issueTypeId = null;
0725: } else if (isSingleIssueType()) {
0726: moduleId = null;
0727: issueTypeId = getIssueType().getIssueTypeId();
0728: } else {
0729: moduleId = null;
0730: issueTypeId = null;
0731: }
0732:
0733: crit.add(RModuleUserAttributePeer.LIST_ID, null);
0734: crit.add(RModuleUserAttributePeer.MODULE_ID, moduleId);
0735: crit.add(RModuleUserAttributePeer.ISSUE_TYPE_ID,
0736: issueTypeId);
0737: }
0738:
0739: crit
0740: .addAscendingOrderByColumn(RModuleUserAttributePeer.PREFERRED_ORDER);
0741:
0742: return RModuleUserAttributePeer.doSelect(crit);
0743: }
0744:
0745: public List getCommonLeafRModuleOptions(final Attribute attribute)
0746: throws TorqueException, ScarabException {
0747: assertNotEmpty();
0748:
0749: final MITListItem item = getFirstItem();
0750: final List rmos = getModule(item).getLeafRModuleOptions(
0751: attribute, item.getIssueType());
0752: try {
0753: return getMatchingRMOs(rmos);
0754: } catch (Exception e) {
0755: throw new ScarabException(L10NKeySet.ExceptionGeneral, e);
0756: }
0757: }
0758:
0759: public List getCommonRModuleOptionTree(Attribute attribute)
0760: throws TorqueException, ScarabException {
0761: assertNotEmpty();
0762: final MITListItem item = getFirstItem();
0763: final List rmos = getModule(item).getOptionTree(attribute,
0764: item.getIssueType());
0765: try {
0766: return getMatchingRMOs(rmos);
0767: } catch (Exception ex) {
0768: throw new ScarabException(L10NKeySet.ExceptionGeneral, ex);
0769: }
0770: }
0771:
0772: public List getAllRModuleOptionTree(Attribute attribute)
0773: throws TorqueException {
0774: assertNotEmpty();
0775:
0776: // Get all isse types from this MITList
0777: List listItems = getExpandedMITListItems();
0778:
0779: // Get all attribute options from all issue types for the requested attribute
0780: List attributeOptions = new ArrayList();
0781: if (listItems != null) {
0782: Iterator listItemIterator = listItems.iterator();
0783: while (listItemIterator.hasNext()) {
0784: MITListItem item = (MITListItem) listItemIterator
0785: .next();
0786: List rmos = getModule(item).getOptionTree(attribute,
0787: item.getIssueType());
0788: mergeRModuleOptionsIgnoreDuplicates(attributeOptions,
0789: rmos);
0790: }
0791: }
0792:
0793: return attributeOptions;
0794: }
0795:
0796: private void mergeRModuleOptionsIgnoreDuplicates(List masterList,
0797: List addList) throws TorqueException {
0798: // Get a set of all existing option ids
0799: Set optionIds = new HashSet();
0800: Iterator masterIterator = masterList.iterator();
0801: while (masterIterator.hasNext()) {
0802: RModuleOption option = (RModuleOption) masterIterator
0803: .next();
0804: optionIds.add(option.getOptionId());
0805: }
0806:
0807: // add all options not already present in the list, add only active options
0808: Iterator addIterator = addList.iterator();
0809: while (addIterator.hasNext()) {
0810: RModuleOption rmo = (RModuleOption) addIterator.next();
0811: if (rmo.getActive()
0812: && !optionIds.contains(rmo.getOptionId())) {
0813: masterList.add(rmo);
0814: }
0815: }
0816: }
0817:
0818: public List getDescendantsUnion(AttributeOption option)
0819: throws TorqueException {
0820: assertNotEmpty();
0821:
0822: List matchingRMOs = new ArrayList();
0823: Iterator items = iterator();
0824: while (items.hasNext()) {
0825: MITListItem item = (MITListItem) items.next();
0826: IssueType issueType = item.getIssueType();
0827: RModuleOption parent = getModule(item).getRModuleOption(
0828: option, issueType);
0829: if (parent != null) {
0830: Iterator i = parent.getDescendants(issueType)
0831: .iterator();
0832: while (i.hasNext()) {
0833: RModuleOption rmo = (RModuleOption) i.next();
0834: if (!matchingRMOs.contains(rmo)) {
0835: matchingRMOs.add(rmo);
0836: }
0837: }
0838: }
0839: }
0840:
0841: return matchingRMOs;
0842: }
0843:
0844: public boolean isCommon(final AttributeOption option)
0845: throws TorqueException, DataSetException {
0846: return isCommon(option, true);
0847: }
0848:
0849: /**
0850: * Checks all items after the first to see if they contain the attribute.
0851: * It is assumed the attribute is included in the first item.
0852: *
0853: * @param option an <code>Attribute</code> value
0854: * @return a <code>boolean</code> value
0855: */
0856: public boolean isCommon(final AttributeOption option,
0857: final boolean activeOnly) throws TorqueException,
0858: DataSetException {
0859: final Criteria crit = new Criteria();
0860: addToCriteria(crit, RModuleOptionPeer.MODULE_ID,
0861: RModuleOptionPeer.ISSUE_TYPE_ID);
0862: crit.add(RModuleOptionPeer.OPTION_ID, option.getOptionId());
0863: if (activeOnly) {
0864: crit.add(RModuleOptionPeer.ACTIVE, true);
0865: }
0866:
0867: return size() == RModuleOptionPeer.count(crit);
0868: }
0869:
0870: public List getModuleIds() {
0871: assertNotEmpty();
0872:
0873: List items = getExpandedMITListItems();
0874: ArrayList ids = new ArrayList(items.size());
0875: Iterator i = items.iterator();
0876: while (i.hasNext()) {
0877: Integer id = ((MITListItem) i.next()).getModuleId();
0878: if (!ids.contains(id)) {
0879: ids.add(id);
0880: }
0881: }
0882: return ids;
0883: }
0884:
0885: public List getModules() throws TorqueException {
0886: assertNotEmpty();
0887:
0888: List items = getExpandedMITListItems();
0889: ArrayList modules = new ArrayList(items.size());
0890: Iterator i = items.iterator();
0891: while (i.hasNext()) {
0892: Module m = ((MITListItem) i.next()).getModule();
0893: if (!modules.contains(m)) {
0894: modules.add(m);
0895: }
0896: }
0897: return modules;
0898: }
0899:
0900: public List getIssueTypeIds() {
0901: assertNotEmpty();
0902:
0903: List items = getExpandedMITListItems();
0904: ArrayList ids = new ArrayList(items.size());
0905: Iterator i = items.iterator();
0906: while (i.hasNext()) {
0907: Integer id = ((MITListItem) i.next()).getIssueTypeId();
0908: if (!ids.contains(id)) {
0909: ids.add(id);
0910: }
0911: }
0912: return ids;
0913: }
0914:
0915: public void addToCriteria(Criteria crit) throws TorqueException {
0916: addToCriteria(crit, IssuePeer.MODULE_ID, IssuePeer.TYPE_ID);
0917: }
0918:
0919: private void addToCriteria(Criteria crit, String moduleField,
0920: String issueTypeField) throws TorqueException {
0921: if (!isSingleModule() && isSingleIssueType()) {
0922: crit.addIn(moduleField, getModuleIds());
0923: crit.add(issueTypeField, getIssueType().getIssueTypeId());
0924: } else if (isSingleModule() && !isSingleIssueType()) {
0925: crit.add(moduleField, getModule().getModuleId());
0926: crit.addIn(issueTypeField, getIssueTypeIds());
0927: } else if (isAllMITs) {
0928: crit.addIn(moduleField, getModuleIds());
0929: // we do this to avoid including templates in results
0930: crit.addIn(issueTypeField, getIssueTypeIds());
0931: } else if (size() > 0) {
0932: List items = getExpandedMITListItems();
0933: Iterator i = items.iterator();
0934: Criteria.Criterion c = null;
0935: while (i.hasNext()) {
0936: MITListItem item = (MITListItem) i.next();
0937: Criteria.Criterion c1 = crit
0938: .getNewCriterion(moduleField, item
0939: .getModuleId(), Criteria.EQUAL);
0940: Criteria.Criterion c2 = crit.getNewCriterion(
0941: issueTypeField, item.getIssueTypeId(),
0942: Criteria.EQUAL);
0943: c1.and(c2);
0944: if (c == null) {
0945: c = c1;
0946: } else {
0947: c.or(c1);
0948: }
0949: }
0950: crit.add(c);
0951: }
0952: }
0953:
0954: public void addAll(MITList list) throws TorqueException {
0955: List currentList = getExpandedMITListItems();
0956: for (Iterator i = list.getExpandedMITListItems().iterator(); i
0957: .hasNext();) {
0958: MITListItem item = (MITListItem) i.next();
0959: if (!currentList.contains(item)) {
0960: addMITListItem(item);
0961: }
0962: }
0963: }
0964:
0965: public void addMITListItem(MITListItem item) throws TorqueException {
0966: super .addMITListItem(item);
0967: expandedList = null;
0968: calculateIsAllMITs(item);
0969: }
0970:
0971: private void calculateIsAllMITs(MITListItem item) {
0972: isAllMITs |= (MITListItem.MULTIPLE_KEY.equals(item
0973: .getModuleId()) && MITListItem.MULTIPLE_KEY.equals(item
0974: .getIssueTypeId()));
0975: }
0976:
0977: public List getExpandedMITListItems() {
0978: if (expandedList == null) {
0979: List items = new ArrayList();
0980: try {
0981: for (Iterator rawItems = getMITListItems().iterator(); rawItems
0982: .hasNext();) {
0983: MITListItem item = (MITListItem) rawItems.next();
0984: calculateIsAllMITs(item);
0985: if (!item.isSingleModule()) {
0986: Module[] modules = getScarabUser().getModules(
0987: ScarabSecurity.ISSUE__SEARCH);
0988: for (int i = 0; i < modules.length; i++) {
0989: Module module = modules[i];
0990: if (item.isSingleIssueType()) {
0991: IssueType type = item.getIssueType();
0992: if (module.getRModuleIssueType(type) != null) {
0993: MITListItem newItem = MITListItemManager
0994: .getInstance();
0995: newItem.setModule(module);
0996: newItem.setIssueType(type);
0997: newItem.setListId(getListId());
0998: items.add(newItem);
0999: }
1000: } else {
1001: addIssueTypes(module, items);
1002: }
1003: }
1004: } else if (!item.isSingleIssueType()) {
1005: addIssueTypes(getModule(item), items);
1006: } else {
1007: items.add(item);
1008: }
1009: }
1010: } catch (Exception e) {
1011: throw new TorqueRuntimeException(e); //EXCEPTION
1012: }
1013: expandedList = items;
1014: }
1015:
1016: return expandedList;
1017: }
1018:
1019: /**
1020: * Adds all the active issue types in module to the items List
1021: */
1022: private void addIssueTypes(Module module, List items)
1023: throws TorqueException {
1024: Iterator rmits = module.getRModuleIssueTypes().iterator();
1025: while (rmits.hasNext()) {
1026: MITListItem newItem = MITListItemManager.getInstance();
1027: newItem.setModuleId(module.getModuleId());
1028: newItem.setIssueTypeId(((RModuleIssueType) rmits.next())
1029: .getIssueTypeId());
1030: newItem.setListId(getListId());
1031: items.add(newItem);
1032: }
1033: }
1034:
1035: public void scheduleItemForDeletion(MITListItem item) {
1036: if (itemsScheduledForDeletion == null) {
1037: itemsScheduledForDeletion = new ArrayList();
1038: }
1039: itemsScheduledForDeletion.add(item);
1040: }
1041:
1042: public void save(Connection con) throws TorqueException {
1043: super .save(con);
1044: if (itemsScheduledForDeletion != null
1045: && !itemsScheduledForDeletion.isEmpty()) {
1046: List itemIds = new ArrayList(itemsScheduledForDeletion
1047: .size());
1048: for (Iterator iter = itemsScheduledForDeletion.iterator(); iter
1049: .hasNext();) {
1050: MITListItem item = (MITListItem) iter.next();
1051: if (!item.isNew()) {
1052: itemIds.add(item.getItemId());
1053: }
1054: }
1055: if (!itemIds.isEmpty()) {
1056: Criteria crit = new Criteria();
1057: crit.addIn(MITListItemPeer.ITEM_ID, itemIds);
1058: MITListItemPeer.doDelete(crit);
1059: }
1060: }
1061: }
1062:
1063: public String toString() {
1064: StringBuffer sb = new StringBuffer(100);
1065: sb.append(super .toString()).append(':');
1066: sb.append((getListId() == null) ? "New" : getListId()
1067: .toString());
1068: if (getName() != null) {
1069: sb.append(" name=").append(getName());
1070: }
1071: sb.append('[');
1072: boolean addComma = false;
1073: try {
1074: for (Iterator rawItems = getMITListItems().iterator(); rawItems
1075: .hasNext();) {
1076: if (addComma) {
1077: sb.append(", ");
1078: } else {
1079: addComma = true;
1080: }
1081:
1082: MITListItem item = (MITListItem) rawItems.next();
1083: sb.append('(').append(item.getModuleId()).append(',')
1084: .append(item.getIssueTypeId()).append(',')
1085: .append(item.getListId()).append(')');
1086: }
1087: } catch (Exception e) {
1088: sb.append("Error retrieving list items. see logs.");
1089: Log.get().warn("", e);
1090: }
1091:
1092: return sb.append(']').toString();
1093: }
1094: }
|