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 CollabNet <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 CollabNet.
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 CollabNet.
0047: */
0048:
0049: import com.workingdogs.village.DataSetException;
0050: import java.util.Collections;
0051: import java.util.ArrayList;
0052: import java.util.Iterator;
0053: import java.util.List;
0054: import java.util.Locale;
0055: import java.util.Map;
0056: import java.util.HashMap;
0057: import java.util.Comparator;
0058: import java.sql.Connection;
0059: import org.apache.fulcrum.security.util.TurbineSecurityException;
0060:
0061: import org.apache.torque.TorqueException;
0062: import org.apache.torque.util.Criteria;
0063: import org.apache.torque.om.BaseObject;
0064:
0065: import org.apache.fulcrum.localization.Localization;
0066:
0067: import org.tigris.scarab.reports.ReportBridge;
0068: import org.tigris.scarab.tools.localization.L10NKey;
0069: import org.tigris.scarab.tools.localization.L10NKeySet;
0070: import org.tigris.scarab.util.ScarabException;
0071: import org.tigris.scarab.services.security.ScarabSecurity;
0072: import org.tigris.scarab.services.cache.ScarabCache;
0073: import org.tigris.scarab.util.Log;
0074: import org.tigris.scarab.util.ScarabConstants;
0075:
0076: /**
0077: * This class contains common code for the use in ScarabUser implementations.
0078: * Functionality that is not implementation specific should go here.
0079: *
0080: * @author <a href="mailto:jon@collab.net">Jon S. Stevens</a>
0081: * @author <a href="mailto:jmcnally@collab.net">John McNally</a>
0082: * @version $Id: AbstractScarabUser.java 10264 2006-08-27 15:37:01Z jorgeuriarte $
0083: */
0084: public abstract class AbstractScarabUser extends BaseObject {
0085: /** Method name used as part of a cache key */
0086: private static final String GET_R_MODULE_USERATTRIBUTES = "getRModuleUserAttributes";
0087: /** Method name used as part of a cache key */
0088: private static final String GET_R_MODULE_USERATTRIBUTE = "getRModuleUserAttribute";
0089:
0090: private static final String[] HOME_PAGES = { "home,EnterNew.vm",
0091: "query", "Index.vm" };
0092:
0093: private static final int MAX_INDEPENDENT_WINDOWS = 10;
0094:
0095: /**
0096: * The user's preferred locale.
0097: */
0098: protected Locale locale = null;
0099:
0100: /**
0101: * counter used as part of a key to store an Issue the user is
0102: * currently entering
0103: */
0104: private int issueCount = 0;
0105:
0106: /**
0107: * Map to store <code>Issue</code>'s the user is currently entering
0108: */
0109: private Map issueMap;
0110:
0111: /**
0112: * counter used as part of a key to store an ReportBridge the user is
0113: * currently editing
0114: */
0115: private int reportCount = 0;
0116:
0117: /**
0118: * Map to store <code>ReportBridge</code>'s the user is currently entering
0119: */
0120: private Map reportMap;
0121:
0122: /**
0123: * Map to store the most recent query entered by the user
0124: */
0125: private Map mostRecentQueryMap;
0126:
0127: /**
0128: * Map to store the MITList that may have went with the most recent query
0129: * entered by the user
0130: */
0131: private Map mostRecentQueryMITMap;
0132:
0133: /**
0134: * Map to store the working user list in Assign Issue.
0135: */
0136: private Map associatedUsersMap;
0137:
0138: /**
0139: * Map to store the working user list in Advanced Query.
0140: */
0141: private Map selectedUsersMap;
0142:
0143: /**
0144: * Code for user's preference on which screen to return to
0145: * After entering an issue
0146: */
0147: private int enterIssueRedirect = 0;
0148:
0149: /**
0150: * The list of MITListItems that will be searched in a
0151: * X-project query.
0152: */
0153: private Map mitListMap;
0154:
0155: /**
0156: * The last entered issue type
0157: */
0158: private Map enterIssueMap;
0159:
0160: /**
0161: * toggle switch for show/hide the cross module section of the
0162: * issue type selection widget.
0163: */
0164: private boolean showOtherModulesInIssueTypeList;
0165:
0166: private Map activeKeys = new HashMap();
0167: private transient ThreadLocal threadKey = null;
0168:
0169: /**
0170: * counter used as a key to keep concurrent activities by the same
0171: * user from overwriting each others state. Might want to use something
0172: * better than a simple counter.
0173: */
0174: private int threadCount = 0;
0175:
0176: // we could create Maps for these and use the threadKey, but these
0177: // will be reset for each request, so we can keep it simple and use
0178: // a ThreadLocal for each. Even though the threads may be pooled the
0179: // value will be set correctly when first needed in a request cycle.
0180: private transient ThreadLocal currentModule = null;
0181: private transient ThreadLocal currentIssueType = null;
0182:
0183: /**
0184: * Calls the superclass constructor to initialize this object.
0185: */
0186: public AbstractScarabUser() {
0187: super ();
0188: issueMap = new HashMap();
0189: reportMap = new HashMap();
0190: mitListMap = new HashMap();
0191: enterIssueMap = new HashMap();
0192: mostRecentQueryMap = new HashMap();
0193: mostRecentQueryMITMap = new HashMap();
0194: associatedUsersMap = new HashMap();
0195: selectedUsersMap = new HashMap();
0196: initThreadLocals();
0197: }
0198:
0199: /**
0200: * Need to override readObject in order to initialize
0201: * the transient ThreadLocal objects which are not serializable.
0202: */
0203: private void readObject(java.io.ObjectInputStream in)
0204: throws java.io.IOException, ClassNotFoundException {
0205: try {
0206: in.defaultReadObject();
0207: } catch (java.io.NotActiveException e) {
0208: }
0209: initThreadLocals();
0210: }
0211:
0212: private void initThreadLocals() {
0213: currentIssueType = new ThreadLocal();
0214: currentModule = new ThreadLocal();
0215: threadKey = new ThreadLocal();
0216: }
0217:
0218: /** The Primary Key used to reference this user in storage */
0219: public abstract Integer getUserId();
0220:
0221: /**
0222: * @see org.tigris.scarab.om.ScarabUser#getEmail()
0223: */
0224: public abstract String getEmail();
0225:
0226: /**
0227: * @see org.tigris.scarab.om.ScarabUser#getFirstName()
0228: */
0229: public abstract String getFirstName();
0230:
0231: /**
0232: * @see org.tigris.scarab.om.ScarabUser#getLastName()
0233: */
0234: public abstract String getLastName();
0235:
0236: /**
0237: * @see org.tigris.scarab.om.ScarabUser#hasPermission(String, Module)
0238: */
0239: public abstract boolean hasPermission(String perm, Module module);
0240:
0241: /**
0242: * @see org.tigris.scarab.om.ScarabUser#hasPermission(String, List)
0243: */
0244: public boolean hasPermission(String perm, List modules) {
0245: boolean hasPerm = false;
0246: if (modules != null && !modules.isEmpty()) {
0247: hasPerm = true;
0248: Iterator i = modules.iterator();
0249: while (i.hasNext() && hasPerm) {
0250: hasPerm = hasPermission(perm, (Module) i.next());
0251: }
0252: }
0253: return hasPerm;
0254: }
0255:
0256: /**
0257: * @see org.tigris.scarab.om.ScarabUser#getName()
0258: * It will be the "FirstName LastName", if both names have a value.
0259: */
0260: public String getName() {
0261: String first = getFirstName();
0262: String last = getLastName();
0263: int firstlength = 0;
0264: int lastlength = 0;
0265: if (first != null) {
0266: firstlength = first.length();
0267: }
0268: if (last != null) {
0269: lastlength = last.length();
0270: }
0271: StringBuffer sb = new StringBuffer(firstlength + lastlength + 1);
0272: if (firstlength > 0) {
0273: sb.append(first);
0274: if (lastlength > 0) {
0275: sb.append(' ');
0276: }
0277: }
0278: if (lastlength > 0) {
0279: sb.append(last);
0280: }
0281:
0282: return sb.toString();
0283: }
0284:
0285: /**
0286: * @see org.tigris.scarab.om.ScarabUser#getModules()
0287: */
0288: public abstract List getModules() throws TorqueException;
0289:
0290: /**
0291: * @see org.tigris.scarab.om.ScarabUser#getModules(String)
0292: */
0293: public abstract Module[] getModules(String permission)
0294: throws TorqueException;
0295:
0296: /**
0297: * @see org.tigris.scarab.om.ScarabUser#getModules(boolean)
0298: */
0299: public abstract List getModules(boolean showDeletedModules)
0300: throws TorqueException;
0301:
0302: /**
0303: * @see org.tigris.scarab.om.ScarabUser#getEditableModules()
0304: */
0305: public List getEditableModules() throws TorqueException {
0306: return getEditableModules(null);
0307: }
0308:
0309: /**
0310: * Get modules user can copy or move to.
0311: * If copying, requires ISSUE_ENTER permission
0312: * If moving, requires ISSUE_MOVE permission to move
0313: * To another module, or ISSUE_EDIT to move to another issue type.
0314: */
0315: public List getCopyToModules(Module currentModule, String action,
0316: String searchString) throws TorqueException {
0317: List copyToModules = new ArrayList();
0318: if (hasPermission(ScarabSecurity.ISSUE__MOVE, currentModule)
0319: || "copy".equals(action)) {
0320: Module[] userModules = getModules(ScarabSecurity.ISSUE__ENTER);
0321: for (int i = 0; i < userModules.length; i++) {
0322: Module module = userModules[i];
0323: if (!module.isGlobalModule()
0324: && (searchString == null
0325: || searchString.equals("") || module
0326: .getName().indexOf(searchString) != -1)) {
0327: copyToModules.add(module);
0328: }
0329: }
0330: } else if (hasPermission(ScarabSecurity.ISSUE__EDIT,
0331: currentModule)
0332: && currentModule.getIssueTypes().size() > 1) {
0333: copyToModules.add(currentModule);
0334: }
0335: return copyToModules;
0336: }
0337:
0338: /**
0339: * @see org.tigris.scarab.om.ScarabUser#getCopyToModules(Module)
0340: */
0341: public List getCopyToModules(Module currentModule)
0342: throws TorqueException {
0343: return getCopyToModules(currentModule, "copy", null);
0344: }
0345:
0346: /**
0347: * @see org.tigris.scarab.om.ScarabUser#getCopyToModules(Module, String)
0348: */
0349: public List getCopyToModules(Module currentModule, String action)
0350: throws TorqueException {
0351: return getCopyToModules(currentModule, action, null);
0352: }
0353:
0354: /**
0355: * @see org.tigris.scarab.om.ScarabUser#getEditableModules(Module)
0356: */
0357: public List getEditableModules(Module currEditModule)
0358: throws TorqueException {
0359: List userModules = getModules(true);
0360: List editModules = new ArrayList();
0361:
0362: if (currEditModule != null) {
0363: editModules.add(currEditModule.getParent());
0364: }
0365: for (int i = 0; i < userModules.size(); i++) {
0366: Module module = (Module) userModules.get(i);
0367: Module parent = module.getParent();
0368:
0369: if (!editModules.contains(module)
0370: && parent != currEditModule) {
0371: if (hasPermission(ScarabSecurity.MODULE__EDIT, module)) {
0372: editModules.add(module);
0373: }
0374: }
0375: }
0376: // we want to remove the module we are editing
0377: if (currEditModule != null
0378: && editModules.contains(currEditModule)) {
0379: editModules.remove(currEditModule);
0380: }
0381:
0382: return editModules;
0383: }
0384:
0385: /**
0386: * @see org.tigris.scarab.om.ScarabUser#getRModuleUserAttributes(Module, IssueType)
0387: */
0388: public List getRModuleUserAttributes(Module module,
0389: IssueType issueType) throws TorqueException {
0390: List result = null;
0391: Object obj = ScarabCache.get(this , GET_R_MODULE_USERATTRIBUTES,
0392: module, issueType);
0393: if (obj == null) {
0394: Criteria crit = new Criteria().add(
0395: RModuleUserAttributePeer.USER_ID, getUserId()).add(
0396: RModuleUserAttributePeer.MODULE_ID,
0397: module.getModuleId()).add(
0398: RModuleUserAttributePeer.ISSUE_TYPE_ID,
0399: issueType.getIssueTypeId())
0400: .addAscendingOrderByColumn(
0401: RModuleUserAttributePeer.PREFERRED_ORDER);
0402:
0403: result = getRModuleUserAttributes(crit);
0404: ScarabCache.put(result, this , GET_R_MODULE_USERATTRIBUTES,
0405: module, issueType);
0406: } else {
0407: result = (List) obj;
0408: }
0409: return result;
0410: }
0411:
0412: /**
0413: * Should return a list of <code>RModuleUserAttribute</code>'s that
0414: * meet the given criteria.
0415: */
0416: protected abstract List getRModuleUserAttributes(Criteria crit)
0417: throws TorqueException;
0418:
0419: /**
0420: * @see org.tigris.scarab.om.ScarabUser#getRModuleUserAttribute(Module, Attribute, IssueType)
0421: */
0422: public RModuleUserAttribute getRModuleUserAttribute(
0423: final Module module, final Attribute attribute,
0424: final IssueType issueType) throws TorqueException,
0425: ScarabException {
0426: RModuleUserAttribute result = null;
0427: final Object obj = ScarabCache.get(this ,
0428: GET_R_MODULE_USERATTRIBUTE, module, attribute,
0429: issueType);
0430: if (obj == null) {
0431: final Criteria crit = new Criteria(4).add(
0432: RModuleUserAttributePeer.USER_ID, getUserId()).add(
0433: RModuleUserAttributePeer.ATTRIBUTE_ID,
0434: attribute.getAttributeId()).add(
0435: RModuleUserAttributePeer.LIST_ID, null);
0436: if (module == null) {
0437: crit.add(RModuleUserAttributePeer.MODULE_ID, null);
0438: } else {
0439: crit.add(RModuleUserAttributePeer.MODULE_ID, module
0440: .getModuleId());
0441:
0442: }
0443: if (issueType == null) {
0444: crit.add(RModuleUserAttributePeer.ISSUE_TYPE_ID, null);
0445: } else {
0446: crit.add(RModuleUserAttributePeer.ISSUE_TYPE_ID,
0447: issueType.getIssueTypeId());
0448: }
0449:
0450: final List muas = RModuleUserAttributePeer.doSelect(crit);
0451: if (muas.size() == 1) {
0452: result = (RModuleUserAttribute) muas.get(0);
0453: } else if (muas.isEmpty()) {
0454: result = getNewRModuleUserAttribute(attribute, module,
0455: issueType);
0456: } else {
0457: throw new ScarabException(
0458: L10NKeySet.ExceptionMultipleJDMs);
0459: }
0460: ScarabCache.put(result, this , GET_R_MODULE_USERATTRIBUTE,
0461: module, attribute, issueType);
0462: } else {
0463: result = (RModuleUserAttribute) obj;
0464: }
0465: return result;
0466: }
0467:
0468: protected RModuleUserAttribute getNewRModuleUserAttribute(
0469: Attribute attribute, Module module, IssueType issueType)
0470: throws TorqueException {
0471: RModuleUserAttribute result = RModuleUserAttributeManager
0472: .getInstance();
0473: result.setUserId(getUserId());
0474: result.setAttributeId(attribute.getAttributeId());
0475: if (module != null) {
0476: result.setModuleId(module.getModuleId());
0477: }
0478: if (issueType != null) {
0479: result.setIssueTypeId(issueType.getIssueTypeId());
0480: }
0481: return result;
0482: }
0483:
0484: /**
0485: * @see org.tigris.scarab.om.ScarabUser#getReportingIssue(String)
0486: */
0487: public Issue getReportingIssue(String key) {
0488: return (Issue) issueMap.get(key);
0489: }
0490:
0491: /**
0492: * @see org.tigris.scarab.om.ScarabUser#setReportingIssue(Issue)
0493: */
0494: public String setReportingIssue(Issue issue) throws ScarabException {
0495: String key = null;
0496: if (issue == null) {
0497: throw new ScarabException(
0498: L10NKeySet.ExceptionNullIssueForbidden);
0499: } else {
0500: key = String.valueOf(issueCount++);
0501: setReportingIssue(key, issue);
0502: }
0503: return key;
0504: }
0505:
0506: /**
0507: * @see org.tigris.scarab.om.ScarabUser#setReportingIssue(String, Issue)
0508: */
0509: public void setReportingIssue(String key, Issue issue) {
0510: if (issue == null) {
0511: issueMap.remove(key);
0512: } else {
0513: try {
0514: if (issueMap.size() >= MAX_INDEPENDENT_WINDOWS) {
0515: // make sure issues are not being accumulated, set a
0516: // reasonable limit of 10 open new issues
0517: int intKey = Integer.parseInt(key);
0518: int count = 0;
0519: for (int i = intKey - 1; i >= 0; i--) {
0520: String testKey = String.valueOf(i);
0521: if (getReportingIssue(testKey) != null) {
0522: if (++count >= MAX_INDEPENDENT_WINDOWS) {
0523: issueMap.remove(testKey);
0524: }
0525: }
0526: }
0527: }
0528: } catch (Exception e) {
0529: Log.get().error(
0530: "Nonfatal error clearing old issues. "
0531: + "This could be a memory leak.", e);
0532: }
0533:
0534: issueMap.put(key, issue);
0535: }
0536: }
0537:
0538: /**
0539: * @see org.tigris.scarab.om.ScarabUser#getCurrentReport(String)
0540: */
0541: public ReportBridge getCurrentReport(String key) {
0542: return (ReportBridge) reportMap.get(key);
0543: }
0544:
0545: /**
0546: * @see org.tigris.scarab.om.ScarabUser#setCurrentReport(ReportBridge)
0547: */
0548: public String setCurrentReport(ReportBridge report)
0549: throws ScarabException {
0550: String key = null;
0551: if (report == null) {
0552: throw new ScarabException(
0553: L10NKeySet.ExceptionNullReportForbidden);
0554: } else {
0555: key = String.valueOf(reportCount++);
0556: setCurrentReport(key, report);
0557: }
0558: return key;
0559: }
0560:
0561: /**
0562: * @see org.tigris.scarab.om.ScarabUser#setCurrentReport(String, ReportBridge)
0563: */
0564: public void setCurrentReport(String key, ReportBridge report) {
0565: if (report == null) {
0566: reportMap.remove(key);
0567: } else {
0568: try {
0569: if (reportMap.size() >= MAX_INDEPENDENT_WINDOWS) {
0570: // make sure reports are not being accumulated, set a
0571: // reasonable limit of MAX_INDEPENDENT_WINDOWS open reports
0572: int intKey = Integer.parseInt(key);
0573: int count = 0;
0574: for (int i = intKey - 1; i >= 0; i--) {
0575: String testKey = String.valueOf(i);
0576: if (getCurrentReport(testKey) != null) {
0577: if (++count >= MAX_INDEPENDENT_WINDOWS) {
0578: reportMap.remove(testKey);
0579: }
0580: }
0581: }
0582: }
0583: } catch (Exception e) {
0584: Log.get().error(
0585: "Nonfatal error clearing old reports. "
0586: + "This could be a memory leak.", e);
0587: }
0588:
0589: reportMap.put(String.valueOf(key), report);
0590: }
0591: }
0592:
0593: /**
0594: * @see org.apache.torque.om.Persistent#save()
0595: * this implementation throws an UnsupportedOperationException.
0596: */
0597: public void save() throws TorqueException {
0598: throw new UnsupportedOperationException("Not implemented"); //EXCEPTION
0599: }
0600:
0601: /**
0602: * @see org.apache.torque.om.Persistent#save(String)
0603: * this implementation throws an UnsupportedOperationException.
0604: */
0605: public void save(String dbName) throws TorqueException {
0606: throw new UnsupportedOperationException("Not implemented"); //EXCEPTION
0607: }
0608:
0609: /**
0610: * @see org.apache.torque.om.Persistent#save(Connection)
0611: * this implementation throws an UnsupportedOperationException.
0612: */
0613: public void save(Connection dbCon) throws TorqueException {
0614: throw new UnsupportedOperationException("Not implemented"); //EXCEPTION
0615: }
0616:
0617: /**
0618: * Returns integer representing user preference for
0619: * Which screen to return to after entering an issue.
0620: * 1 = Enter New Issue. 2 = Assign Issue (default)
0621: * 3 = View Issue. 4 = Issue Types index.
0622: */
0623: public int getEnterIssueRedirect() throws TorqueException {
0624: if (enterIssueRedirect == 0) {
0625: UserPreference up = UserPreferenceManager
0626: .getInstance(getUserId());
0627: if (up != null && up.getEnterIssueRedirect() != 0) {
0628: enterIssueRedirect = up.getEnterIssueRedirect();
0629: }
0630: }
0631: return enterIssueRedirect;
0632: }
0633:
0634: /**
0635: * Sets integer representing user preference for
0636: * Which screen to return to after entering an issue.
0637: * 1 = Enter New Issue. 2 = Assign Issue (default)
0638: * 3 = View Issue. 4 = Issue Types index.
0639: */
0640: public void setEnterIssueRedirect(int templateCode)
0641: throws TorqueException {
0642: UserPreference up = UserPreferenceManager
0643: .getInstance(getUserId());
0644: up.setEnterIssueRedirect(templateCode);
0645: up.save();
0646: enterIssueRedirect = templateCode;
0647: }
0648:
0649: /**
0650: * @see ScarabUser#getHomePage()
0651: */
0652: public String getHomePage() throws TorqueException {
0653: return getHomePage(getCurrentModule());
0654: }
0655:
0656: /**
0657: * @see ScarabUser#getHomePage(Module)
0658: */
0659: public String getHomePage(Module module) {
0660: String homePage = null;
0661: try {
0662: // A user with no id won't have preferences. The
0663: // anonymous user used during password expiration (or an
0664: // unsaved user) would exhibit this behavior.
0665: Integer uid = getUserId();
0666: if (uid != null) {
0667: UserPreference up = UserPreferenceManager
0668: .getInstance(uid);
0669: homePage = up.getHomePage();
0670:
0671: if (module == null) {
0672: homePage = "SelectModule.vm";
0673: } else if ("query".equals(homePage)) {
0674: homePage = getQueryTarget();
0675: } else if ("matrix".equals(homePage)) {
0676: homePage = getMatrixTarget();
0677: }
0678: // protect against removal of old screens
0679: else if (homePage != null
0680: && (homePage.endsWith("ModuleQuery.vm") || homePage
0681: .endsWith("XModuleList.vm"))) {
0682: homePage = getQueryTarget();
0683: }
0684:
0685: int i = 0;
0686: while (homePage == null
0687: || !isHomePageValid(homePage, module)) {
0688: homePage = HOME_PAGES[i++];
0689: if ("query".equals(homePage)) {
0690: homePage = getQueryTarget();
0691: }
0692: }
0693: }
0694: } catch (Exception e) {
0695: Log.get().warn("Error determining user homepage", e);
0696: }
0697: return (homePage != null ? homePage : "Index.vm");
0698: }
0699:
0700: /**
0701: * This method is used in getHomePage() and expects the homePage to
0702: * be non-null.
0703: */
0704: private boolean isHomePageValid(String homePage, Module module) {
0705: boolean result = true;
0706: String perm = ScarabSecurity.getScreenPermission(homePage
0707: .replace(',', '.'));
0708: if (perm != null && !hasPermission(perm, module)) {
0709: result = false;
0710: }
0711: return result;
0712: }
0713:
0714: /**
0715: * @see ScarabUser#setHomePage(String)
0716: */
0717: public void setHomePage(final String homePage)
0718: throws TorqueException, ScarabException {
0719: if ("ModuleNotReady.vm".equals(homePage)) {
0720: throw new ScarabException(
0721: L10NKeySet.ExceptionForbiddenHomeModuleNotReady);
0722: }
0723: final UserPreference up = UserPreferenceManager
0724: .getInstance(getUserId());
0725: up.setHomePage(homePage);
0726: up.save();
0727: }
0728:
0729: // TODO: make this persist
0730: private final Map queryTargetMap = new HashMap();
0731:
0732: /**
0733: * @see ScarabUser#getQueryTarget()
0734: */
0735: public String getQueryTarget() {
0736: MITList mitlist = getCurrentMITList();
0737: String target = null;
0738: if (mitlist == null) {
0739: target = "IssueTypeList.vm";
0740: } else if (mitlist.isSingleModuleIssueType()) {
0741: try {
0742: Integer issueTypeId = mitlist.getIssueType()
0743: .getIssueTypeId();
0744: target = (String) queryTargetMap.get(issueTypeId);
0745: } catch (Exception e) {
0746: Log.get().warn("Could not determine query target.", e);
0747: }
0748:
0749: if (target == null) {
0750: target = "Search.vm";
0751: }
0752: } else {
0753: target = "AdvancedQuery.vm";
0754: }
0755: return target;
0756: }
0757:
0758: public String getMatrixTarget() {
0759: String target = "QueryMatrix.vm";
0760: return target;
0761: }
0762:
0763: /**
0764: * @see ScarabUser#setSingleIssueTypeQueryTarget(IssueType, String)
0765: */
0766: public void setSingleIssueTypeQueryTarget(IssueType type,
0767: String target) {
0768: queryTargetMap.put(type.getIssueTypeId(), target);
0769: }
0770:
0771: /**
0772: * Gets active, named lists
0773: *
0774: * @return a <code>List</code> value
0775: * @exception TorqueException if an error occurs
0776: */
0777: public List getMITLists() throws TorqueException {
0778: List result = null;
0779:
0780: Criteria crit = new Criteria();
0781: crit.add(MITListPeer.ACTIVE, true);
0782: Criteria.Criterion userCrit = crit.getNewCriterion(
0783: MITListPeer.USER_ID, getUserId(), Criteria.EQUAL);
0784: userCrit.or(crit.getNewCriterion(MITListPeer.USER_ID, null,
0785: Criteria.EQUAL));
0786: crit.add(userCrit);
0787: crit.add(MITListPeer.MODIFIABLE, true);
0788: crit.add(MITListPeer.ACTIVE, true);
0789: crit.add(MITListPeer.NAME, (Object) null, Criteria.NOT_EQUAL);
0790: crit.addAscendingOrderByColumn(MITListPeer.NAME);
0791: result = MITListPeer.doSelect(crit);
0792:
0793: return result;
0794: }
0795:
0796: /**
0797: * @see ScarabUser#hasAnySearchableRMITs().
0798: */
0799: public boolean hasAnySearchableRMITs() throws TorqueException,
0800: DataSetException {
0801: boolean result = false;
0802: final List moduleIds = getSearchableModuleIds();
0803: if (!moduleIds.isEmpty()) {
0804: final Criteria crit = new Criteria();
0805: crit.addIn(RModuleIssueTypePeer.MODULE_ID, moduleIds);
0806: result = (RModuleIssueTypePeer.count(crit) > 0);
0807: }
0808: return result;
0809: }
0810:
0811: private List getSearchableModuleIds() throws TorqueException {
0812: Module[] userModules = getModules(ScarabSecurity.ISSUE__SEARCH);
0813: List moduleIds;
0814: if (userModules != null
0815: && (userModules.length > 1 || userModules.length == 1
0816: && !userModules[0].isGlobalModule())) {
0817: moduleIds = new ArrayList(userModules.length);
0818: for (int i = 0; i < userModules.length; i++) {
0819: Module module = userModules[i];
0820: if (!module.isGlobalModule()) {
0821: moduleIds.add(module.getModuleId());
0822: }
0823: }
0824: } else {
0825: moduleIds = Collections.EMPTY_LIST;
0826: }
0827: return moduleIds;
0828: }
0829:
0830: /**
0831: * @see ScarabUser#getUnusedRModuleIssueTypes(Module).
0832: */
0833: public List getUnusedRModuleIssueTypes(Module module)
0834: throws TorqueException {
0835: List result;
0836: if (module == null) {
0837: result = Collections.EMPTY_LIST;
0838: } else {
0839: Criteria crit = new Criteria();
0840: crit.add(RModuleIssueTypePeer.MODULE_ID,
0841: module.getModuleId()).addJoin(
0842: RModuleIssueTypePeer.ISSUE_TYPE_ID,
0843: IssueTypePeer.ISSUE_TYPE_ID).add(
0844: IssueTypePeer.PARENT_ID, 0).add(
0845: IssueTypePeer.DELETED, false);
0846: addCurrentMITListExclusion(crit);
0847: result = RModuleIssueTypePeer.doSelect(crit);
0848: }
0849: return result;
0850: }
0851:
0852: /**
0853: * @see ScarabUser#getAllRModuleIssueTypes(Module).
0854: */
0855: public List getAllRModuleIssueTypes(Module module)
0856: throws TorqueException {
0857: List result;
0858: if (module == null) {
0859: result = Collections.EMPTY_LIST;
0860: } else {
0861: Criteria crit = new Criteria();
0862: crit.add(RModuleIssueTypePeer.MODULE_ID,
0863: module.getModuleId()).addJoin(
0864: RModuleIssueTypePeer.ISSUE_TYPE_ID,
0865: IssueTypePeer.ISSUE_TYPE_ID).add(
0866: IssueTypePeer.PARENT_ID, 0).add(
0867: IssueTypePeer.DELETED, false);
0868: result = RModuleIssueTypePeer.doSelect(crit);
0869: }
0870: return result;
0871: }
0872:
0873: private void addCurrentMITListExclusion(Criteria crit)
0874: throws TorqueException {
0875: // do not include RMIT's related to current MITListItems.
0876: MITList mitList = getCurrentMITList(getGenThreadKey());
0877: if (mitList != null && mitList.getMITListItems() != null
0878: && !mitList.getMITListItems().isEmpty()) {
0879: boolean addAnd = false;
0880: StringBuffer sb = new StringBuffer();
0881: Iterator mitItems = mitList.getExpandedMITListItems()
0882: .iterator();
0883: while (mitItems.hasNext()) {
0884: MITListItem item = (MITListItem) mitItems.next();
0885: if (mitList.getModule(item) != null
0886: && item.getIssueType() != null) {
0887: if (addAnd) {
0888: sb.append(" AND ");
0889: }
0890:
0891: sb.append(" NOT (").append(
0892: RModuleIssueTypePeer.MODULE_ID).append('=')
0893: .append(
0894: mitList.getModule(item)
0895: .getModuleId()).append(
0896: " AND ").append(
0897: RModuleIssueTypePeer.ISSUE_TYPE_ID)
0898: .append('=').append(
0899: item.getIssueType()
0900: .getIssueTypeId()).append(
0901: ')');
0902: addAnd = true;
0903: }
0904: }
0905: // the column name used here is arbitrary (within limits)
0906: crit.add(IssueTypePeer.ISSUE_TYPE_ID, (Object) sb
0907: .toString(), Criteria.CUSTOM);
0908: }
0909: }
0910:
0911: /**
0912: * @see ScarabUser#getSearchableRMITs(String, String, String, String, Module).
0913: * This list does not include
0914: * RModuleIssueTypes that are part of the current MITList.
0915: */
0916: public List getSearchableRMITs(String searchField,
0917: String searchString, String sortColumn,
0918: String sortPolarity, Module skipModule)
0919: throws TorqueException {
0920: List moduleIds = getSearchableModuleIds();
0921: if (skipModule != null) {
0922: moduleIds.remove(skipModule.getModuleId());
0923: }
0924:
0925: List result;
0926: if (moduleIds.isEmpty()) {
0927: result = Collections.EMPTY_LIST;
0928: } else {
0929: Criteria crit = new Criteria();
0930: crit.addIn(RModuleIssueTypePeer.MODULE_ID, moduleIds);
0931: crit.addJoin(RModuleIssueTypePeer.ISSUE_TYPE_ID,
0932: IssueTypePeer.ISSUE_TYPE_ID);
0933: crit.add(IssueTypePeer.PARENT_ID, 0);
0934: crit.add(IssueTypePeer.DELETED, false);
0935: addCurrentMITListExclusion(crit);
0936:
0937: // we could add the filter criteria here, but this might
0938: // result in full table scans. Even if the table scan turns out
0939: // to be more efficient, I think it is better to move this
0940: // into the middle/front tier.
0941: //addFilterCriteria(crit, searchField, searchString);
0942: //addSortCriteria(crit, sortColumn, sortPolarity);
0943:
0944: result = RModuleIssueTypePeer.doSelect(crit);
0945: filterRMITList(result, searchField, searchString);
0946: sortRMITList(result, sortColumn, sortPolarity);
0947: }
0948:
0949: return result;
0950: }
0951:
0952: /**
0953: * Filter on module or issue type name.
0954: */
0955: protected void filterRMITList(List rmits, String searchField,
0956: String searchString) throws TorqueException {
0957: String moduleName = null;
0958: String issueTypeName = null;
0959: if ("issuetype".equals(searchField)) {
0960: issueTypeName = searchString;
0961: } else {
0962: moduleName = searchString;
0963: }
0964:
0965: if (moduleName != null && moduleName.length() > 0) {
0966: for (int i = rmits.size() - 1; i >= 0; i--) {
0967: String name = ((RModuleIssueType) rmits.get(i))
0968: .getModule().getRealName();
0969: if (name == null || name.indexOf(moduleName) == -1) {
0970: rmits.remove(i);
0971: }
0972: }
0973: }
0974: if (issueTypeName != null && issueTypeName.length() > 0) {
0975: for (int i = rmits.size() - 1; i >= 0; i--) {
0976: String name = ((RModuleIssueType) rmits.get(i))
0977: .getDisplayName();
0978: if (name == null || name.indexOf(issueTypeName) == -1) {
0979: rmits.remove(i);
0980: }
0981: }
0982: }
0983: }
0984:
0985: /**
0986: * Sort module or issue type name.
0987: */
0988: protected void sortRMITList(List rmits, final String sortColumn,
0989: String sortPolarity) throws TorqueException {
0990: final int polarity = ("desc".equals(sortPolarity)) ? -1 : 1;
0991: Comparator c = new Comparator() {
0992: public int compare(Object o1, Object o2) {
0993: int i = 0;
0994: if (sortColumn != null
0995: && sortColumn.equals("issuetype")) {
0996: i = polarity
0997: * ((RModuleIssueType) o1).getDisplayName()
0998: .compareTo(
0999: ((RModuleIssueType) o2)
1000: .getDisplayName());
1001: } else {
1002: try {
1003: i = polarity
1004: * ((RModuleIssueType) o1).getModule()
1005: .getRealName().compareTo(
1006: ((RModuleIssueType) o2)
1007: .getModule()
1008: .getRealName());
1009: } catch (TorqueException e) {
1010: Log.get().error(
1011: "Unable to sort on module names", e);
1012: }
1013: }
1014: return i;
1015: }
1016: };
1017: Collections.sort(rmits, c);
1018: }
1019:
1020: public void addRMITsToCurrentMITList(List rmits)
1021: throws TorqueException {
1022: if (rmits != null && !rmits.isEmpty()) {
1023: MITList mitList = getCurrentMITList(getGenThreadKey());
1024: if (mitList == null) {
1025: mitList = MITListManager.getInstance();
1026: setCurrentMITList(mitList);
1027: }
1028:
1029: Iterator i = rmits.iterator();
1030: while (i.hasNext()) {
1031: RModuleIssueType rmit = (RModuleIssueType) i.next();
1032: MITListItem item = MITListItemManager.getInstance();
1033: item.setModuleId(rmit.getModuleId());
1034: item.setIssueTypeId(rmit.getIssueTypeId());
1035: if (!mitList.contains(item)) {
1036: mitList.addMITListItem(item);
1037: }
1038: }
1039: }
1040: }
1041:
1042: private Object getGenThreadKey() {
1043: Object key = threadKey.get();
1044: if (key == null) {
1045: key = getNewThreadKey();
1046: setThreadKey((Integer) key);
1047: }
1048: return key;
1049: }
1050:
1051: private synchronized Object getNewThreadKey() {
1052: // this algorithm is not very good. what happens if someone bookmarks
1053: // a deep link which includes a thread key
1054: Integer key = new Integer(threadCount++);
1055: activeKeys.put(key, null);
1056: // make sure user is not using up too many resources, set a
1057: // reasonable limit of 10 open "threads"/browser windows.
1058: Integer testKey = new Integer(key.intValue() - 10);
1059: invalidateKey(testKey);
1060: return key;
1061: }
1062:
1063: private void invalidateKey(Object key) {
1064: activeKeys.remove(key);
1065: mitListMap.remove(key);
1066: enterIssueMap.remove(key);
1067: }
1068:
1069: /**
1070: * @see ScarabUser#getThreadKey()
1071: */
1072: public Object getThreadKey() {
1073: return threadKey.get();
1074: }
1075:
1076: /**
1077: * @see ScarabUser#setThreadKey(Integer)
1078: */
1079: public void setThreadKey(Integer key) {
1080: if (activeKeys.containsKey(key)) {
1081: threadKey.set(key);
1082: }
1083: }
1084:
1085: public MITList getCurrentMITList() {
1086: return getCurrentMITList(getGenThreadKey());
1087: }
1088:
1089: private MITList getCurrentMITList(Object key) {
1090: Log.get().debug("Getting mitlist for key " + key);
1091: return (MITList) mitListMap.get(key);
1092: }
1093:
1094: /**
1095: * @see org.tigris.scarab.om.ScarabUser#setCurrentMITList(MITList)
1096: */
1097: public void setCurrentMITList(MITList list) {
1098: if (list != null) {
1099: setCurrentMITList(getGenThreadKey(), list);
1100: } else if (getThreadKey() != null) {
1101: setCurrentMITList(getThreadKey(), list);
1102: }
1103: }
1104:
1105: private void setCurrentMITList(Object key, MITList list) {
1106: if (list == null) {
1107: mitListMap.remove(key);
1108: } else {
1109: try {
1110: if (mitListMap.size() >= MAX_INDEPENDENT_WINDOWS) {
1111: // make sure lists are not being accumulated, set a
1112: // reasonable limit of MAX_INDEPENDENT_WINDOWS open lists
1113: int intKey = Integer.parseInt(String.valueOf(key));
1114: int count = 0;
1115: for (int i = intKey - 1; i >= 0; i--) {
1116: String testKey = String.valueOf(i);
1117: if (getCurrentMITList(testKey) != null) {
1118: if (++count >= MAX_INDEPENDENT_WINDOWS) {
1119: mitListMap.remove(testKey);
1120: }
1121: }
1122: }
1123: }
1124: } catch (Exception e) {
1125: Log.get().error(
1126: "Nonfatal error clearing old MIT lists. "
1127: + "This could be a memory leak.", e);
1128: }
1129: Log.get().debug(
1130: "Set mitList for key " + key + " to " + list);
1131:
1132: mitListMap.put(key, list);
1133: }
1134: }
1135:
1136: public void removeItemsFromCurrentMITList(String[] ids) {
1137: MITList mitList = getCurrentMITList(getGenThreadKey());
1138: if (mitList != null && !mitList.isEmpty() && ids != null
1139: && ids.length > 0) {
1140: for (int i = 0; i < ids.length; i++) {
1141: Iterator iter = mitList.iterator();
1142: while (iter.hasNext()) {
1143: MITListItem item = (MITListItem) iter.next();
1144: if (item.getQueryKey().equals(ids[i])) {
1145: iter.remove();
1146: mitList.scheduleItemForDeletion(item);
1147: continue;
1148: }
1149: }
1150:
1151: }
1152: }
1153: }
1154:
1155: /**
1156: * @see org.tigris.scarab.om.ScarabUser#hasMostRecentQuery()
1157: */
1158: public boolean hasMostRecentQuery() {
1159: return hasMostRecentQuery(getGenThreadKey());
1160: }
1161:
1162: private boolean hasMostRecentQuery(Object key) {
1163: return mostRecentQueryMap.get(key) != null;
1164: }
1165:
1166: /**
1167: * @see org.tigris.scarab.om.ScarabUser#getMostRecentQuery()
1168: */
1169: public String getMostRecentQuery() {
1170: return getMostRecentQuery(getGenThreadKey());
1171: }
1172:
1173: private String getMostRecentQuery(Object key) {
1174: setCurrentMITList(key, (MITList) mostRecentQueryMITMap.get(key));
1175: return (String) mostRecentQueryMap.get(key);
1176: }
1177:
1178: /**
1179: * @see org.tigris.scarab.om.ScarabUser#setMostRecentQuery(String)
1180: */
1181: public void setMostRecentQuery(String queryString) {
1182: if (queryString != null) {
1183: setMostRecentQuery(getGenThreadKey(), queryString);
1184: } else if (getThreadKey() != null) {
1185: setMostRecentQuery(getThreadKey(), null);
1186: }
1187: }
1188:
1189: private void setMostRecentQuery(Object key, String queryString) {
1190: if (queryString == null) {
1191: mostRecentQueryMap.remove(key);
1192: mostRecentQueryMITMap.remove(key);
1193: } else {
1194: try {
1195: if (mostRecentQueryMap.size() >= MAX_INDEPENDENT_WINDOWS) {
1196: // make sure lists are not being accumulated, set a
1197: // reasonable limit of MAX_INDEPENDENT_WINDOWS open lists
1198: int intKey = Integer.parseInt(String.valueOf(key));
1199: int count = 0;
1200: for (int i = intKey - 1; i >= 0; i--) {
1201: String testKey = String.valueOf(i);
1202: if (getMostRecentQuery(testKey) != null) {
1203: if (++count >= MAX_INDEPENDENT_WINDOWS) {
1204: mostRecentQueryMap.remove(testKey);
1205: mostRecentQueryMITMap.remove(testKey);
1206: }
1207: }
1208: }
1209: }
1210: } catch (Exception e) {
1211: Log.get().error(
1212: "Nonfatal error clearing old queries. "
1213: + "This could be a memory leak.", e);
1214: }
1215: MITList list = getCurrentMITList(key);
1216: if (list != null) {
1217: mostRecentQueryMITMap.put(key, list);
1218: mostRecentQueryMap.put(key, queryString);
1219: } else {
1220: Log
1221: .get()
1222: .warn(
1223: "Tried to set most recent query without any mitlist.");
1224: }
1225: }
1226: }
1227:
1228: public Object lastEnteredIssueTypeOrTemplate() {
1229: return lastEnteredIssueTypeOrTemplate(getGenThreadKey());
1230: }
1231:
1232: private Object lastEnteredIssueTypeOrTemplate(Object key) {
1233: Log.get().debug("Getting last entered type for key " + key);
1234: return enterIssueMap.get(key);
1235: }
1236:
1237: /**
1238: * @see org.tigris.scarab.om.ScarabUser#setLastEnteredIssueType(IssueType)
1239: */
1240: public void setLastEnteredIssueType(IssueType type) {
1241: setLastEnteredIssueTypeOrTemplate(type);
1242: }
1243:
1244: /**
1245: * @see org.tigris.scarab.om.ScarabUser#setLastEnteredTemplate(Issue)
1246: */
1247: public void setLastEnteredTemplate(Issue template) {
1248: setLastEnteredIssueTypeOrTemplate(template);
1249: }
1250:
1251: /**
1252: * set the template or issue type
1253: */
1254: private void setLastEnteredIssueTypeOrTemplate(Object obj) {
1255: if (obj != null) {
1256: setLastEnteredIssueTypeOrTemplate(getGenThreadKey(), obj);
1257: } else if (getThreadKey() != null) {
1258: setLastEnteredIssueTypeOrTemplate(getThreadKey(), null);
1259: }
1260: }
1261:
1262: private void setLastEnteredIssueTypeOrTemplate(Object key,
1263: Object obj) {
1264: if (obj == null) {
1265: enterIssueMap.remove(key);
1266: } else {
1267: try {
1268: if (enterIssueMap.size() >= MAX_INDEPENDENT_WINDOWS) {
1269: // make sure lists are not being accumulated, set a
1270: // reasonable limit of MAX_INDEPENDENT_WINDOWS open lists
1271: int intKey = Integer.parseInt(String.valueOf(key));
1272: int count = 0;
1273: for (int i = intKey - 1; i >= 0; i--) {
1274: String testKey = String.valueOf(i);
1275: if (lastEnteredIssueTypeOrTemplate(testKey) != null) {
1276: if (++count >= MAX_INDEPENDENT_WINDOWS) {
1277: enterIssueMap.remove(testKey);
1278: }
1279: }
1280: }
1281: }
1282: } catch (Exception e) {
1283: Log.get().error(
1284: "Nonfatal error clearing entered issue types. "
1285: + "This could be a memory leak.", e);
1286: }
1287: Log.get().debug(
1288: "Set issue type for key " + key + " to " + obj);
1289:
1290: enterIssueMap.put(key, obj);
1291: }
1292: }
1293:
1294: private void setUsersMap(final Map map, final Map users)
1295: throws TorqueException {
1296: final Object key = (users != null ? getGenThreadKey()
1297: : getThreadKey());
1298: if (key == null) {
1299: // With no hash key, this method won't work.
1300: return;
1301: }
1302:
1303: if (users != null && users.size() >= MAX_INDEPENDENT_WINDOWS) {
1304: try {
1305: // Set a reasonable limit on the number of open lists.
1306: final int intKey = Integer
1307: .parseInt(String.valueOf(key));
1308: int count = 0;
1309: for (int i = intKey - 1; i >= 0; i--) {
1310: final String testKey = String.valueOf(i);
1311: if (map.get(testKey) != null) {
1312: if (++count >= MAX_INDEPENDENT_WINDOWS) {
1313: users.remove(testKey);
1314: }
1315: }
1316: }
1317: } catch (Exception e) {
1318: final L10NKey msg = new L10NKey(
1319: "ErrorPossibleMemoryLeak");
1320: Log.get().warn(msg.getMessage(), e);
1321: }
1322: }
1323:
1324: map.put(key, users);
1325: }
1326:
1327: /**
1328: * @see org.tigris.scarab.om.ScarabUser#getAssociatedUsersMap()
1329: */
1330: public Map getAssociatedUsersMap() throws TorqueException {
1331: return (Map) associatedUsersMap.get(getGenThreadKey());
1332: }
1333:
1334: /**
1335: * @see org.tigris.scarab.om.ScarabUser#setAssociatedUsersMap(Map)
1336: */
1337: public void setAssociatedUsersMap(Map associatedUsers)
1338: throws TorqueException {
1339: setUsersMap(associatedUsersMap, associatedUsers);
1340: }
1341:
1342: /**
1343: * @see org.tigris.scarab.om.ScarabUser#getSelectedUsersMap()
1344: */
1345: public Map getSelectedUsersMap() throws TorqueException {
1346: return (Map) selectedUsersMap.get(getGenThreadKey());
1347: }
1348:
1349: /**
1350: * @see org.tigris.scarab.om.ScarabUser#setSelectedUsersMap(Map)
1351: */
1352: public void setSelectedUsersMap(Map selectedUsers)
1353: throws TorqueException {
1354: setUsersMap(selectedUsersMap, selectedUsers);
1355: }
1356:
1357: /**
1358: * The current module
1359: */
1360: public Module getCurrentModule() {
1361: return (Module) currentModule.get();
1362: }
1363:
1364: /**
1365: * The current module
1366: */
1367: public void setCurrentModule(Module v) {
1368: this .currentModule.set(v);
1369: }
1370:
1371: /**
1372: * The current issue type
1373: */
1374: public IssueType getCurrentIssueType() throws TorqueException {
1375: return (IssueType) currentIssueType.get();
1376: }
1377:
1378: /**
1379: * The current issue type
1380: */
1381: public void setCurrentIssueType(IssueType v) {
1382: this .currentIssueType.set(v);
1383: }
1384:
1385: /**
1386: * @see ScarabUser#getCurrentRModuleIssueType()
1387: */
1388: public RModuleIssueType getCurrentRModuleIssueType()
1389: throws TorqueException {
1390: RModuleIssueType rmit = null;
1391: Module module = getCurrentModule();
1392: if (module != null) {
1393: IssueType it = getCurrentIssueType();
1394: if (it != null) {
1395: rmit = module.getRModuleIssueType(it);
1396: }
1397: }
1398:
1399: return rmit;
1400: }
1401:
1402: /**
1403: * @see org.tigris.scarab.om.ScarabUser#updateIssueListAttributes(List)
1404: */
1405: public void updateIssueListAttributes(List attributes)
1406: throws TorqueException, TurbineSecurityException {
1407: MITList mitList = getCurrentMITList();
1408:
1409: // Delete current attribute selections for user
1410: for (Iterator currentAttributes = mitList.getSavedRMUAs()
1411: .iterator(); currentAttributes.hasNext();) {
1412: RModuleUserAttribute rmua = (RModuleUserAttribute) currentAttributes
1413: .next();
1414: Criteria crit = new Criteria();
1415: crit.add(RModuleUserAttributePeer.MODULE_ID, rmua
1416: .getModuleId());
1417: crit.add(RModuleUserAttributePeer.ISSUE_TYPE_ID, rmua
1418: .getIssueTypeId());
1419: crit
1420: .add(RModuleUserAttributePeer.USER_ID, rmua
1421: .getUserId());
1422: crit
1423: .add(RModuleUserAttributePeer.LIST_ID, rmua
1424: .getListId());
1425: crit.add(RModuleUserAttributePeer.INTERNAL_ATTRIBUTE, rmua
1426: .getInternalAttribute());
1427: RModuleUserAttributePeer.doDelete(crit);
1428: }
1429:
1430: int i = 1;
1431: for (Iterator iter = attributes.iterator(); iter.hasNext();) {
1432: RModuleUserAttribute rmua = (RModuleUserAttribute) iter
1433: .next();
1434: rmua.setOrder(i++);
1435: rmua.setListId(mitList.getListId());
1436: if (mitList.isSingleIssueType()) {
1437: rmua.setIssueType(mitList.getIssueType());
1438: }
1439: if (mitList.isSingleModule()) {
1440: rmua.setModule(mitList.getModule());
1441: }
1442: rmua.save();
1443: }
1444: }
1445:
1446: protected abstract void deleteRModuleUserAttribute(
1447: RModuleUserAttribute rmua) throws TorqueException,
1448: TurbineSecurityException;
1449:
1450: /**
1451: * Report the sizes of maps used to hold per-thread attributes
1452: */
1453: public String getStats() {
1454: return " IssueMap=" + issueMap.size() + "; ReportMap="
1455: + reportMap.size() + "; MITListMap="
1456: + mitListMap.size() + "; MostRecentQueryMap="
1457: + mostRecentQueryMap.size()
1458: + "; MostRecentQueryMITMap="
1459: + mostRecentQueryMITMap.size() + "; EnterIssueMap="
1460: + enterIssueMap.size();
1461: }
1462:
1463: /**
1464: * Set the user's locale to a new value.
1465: */
1466: public void setLocale(Locale newLocale) {
1467: locale = newLocale;
1468: }
1469:
1470: /**
1471: * Gets the users default locale from the users preferences.
1472: */
1473: public Locale getLocale() {
1474: if (locale == null) {
1475: locale = getPreferredLocale();
1476: }
1477: return locale;
1478: }
1479:
1480: /**
1481: * get preferred Locale from user preferences
1482: * @return
1483: */
1484: public Locale getPreferredLocale() {
1485: Locale result;
1486: try {
1487: UserPreference up = UserPreferenceManager
1488: .getInstance(getUserId());
1489: result = Localization.getLocale(up.getLocale());
1490: } catch (Exception e) {
1491: // I think it might be ok to return null from this method
1492: // but until that is investigated return the default in
1493: // event of error
1494: result = ScarabConstants.DEFAULT_LOCALE;
1495: Log.get().warn(
1496: "AbstractScarabUser.getLocale() could not "
1497: + "retrieve locale for user id="
1498: + getUserId() + "; Error message: "
1499: + e.getMessage());
1500: }
1501: return result;
1502: }
1503:
1504: /**
1505: * @see org.tigris.scarab.om.ScarabUser#isShowOtherModulesInIssueTypeList()
1506: */
1507: public boolean isShowOtherModulesInIssueTypeList() {
1508: return showOtherModulesInIssueTypeList;
1509: }
1510:
1511: /**
1512: * @see org.tigris.scarab.om.ScarabUser#setShowOtherModulesInIssueTypeList(boolean)
1513: */
1514: public void setShowOtherModulesInIssueTypeList(
1515: boolean newShowOtherModulesInIssueTypeList) {
1516: this.showOtherModulesInIssueTypeList = newShowOtherModulesInIssueTypeList;
1517: }
1518: }
|