001: package org.tigris.scarab.da;
002:
003: /* ================================================================
004: * Copyright (c) 2000 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 CollabNet (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" name
028: * nor may "Tigris" appear in their names without prior written
029: * permission of CollabNet.
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 CollabNet.
047: */
048:
049: import java.io.Serializable;
050: import java.util.ArrayList;
051: import java.util.Collection;
052: import java.util.HashSet;
053: import java.util.Iterator;
054: import java.util.List;
055: import java.util.Set;
056:
057: import org.apache.torque.util.Criteria;
058: import com.workingdogs.village.Record;
059:
060: import org.tigris.scarab.om.AttributePeer;
061: import org.tigris.scarab.om.AttributeGroupPeer;
062: import org.tigris.scarab.om.RAttributeAttributeGroupPeer;
063: import org.tigris.scarab.om.RModuleAttributePeer;
064: import org.tigris.scarab.om.RModuleUserAttributePeer;
065: import org.tigris.scarab.services.cache.ScarabCache;
066: import org.tigris.scarab.tools.localization.L10NKeySet;
067:
068: /**
069: * Access to data relating to attributes.
070: *
071: * @see org.tigris.scarab.da.AttributeAccess
072: * @author <a href="mailto:jmcnally@collab.net">John McNally</a>
073: * @author <a href="mailto:dlr@collab.net">Daniel Rall</a>
074: * @since Scarab 0.17
075: */
076: public class AttributeAccess {
077: /** Method name used as part of a cache key. */
078: private static final String RETRIEVE_QUERY_COLUMN_IDS = "retrieveQueryColumnIDs";
079: private static final String RETRIEVE_QUICK_SEARCH_ATTRIBUTES = "retrieveQuickSearchAttributeIDs";
080: private static final String RETRIEVE_REQUIRED_ATTRIBUTES = "retrieveRequiredAttributeIDs";
081: private static final String RETRIEVE_ACTIVE_ATTRIBUTES = "retrieveActiveAttributes";
082: private static final String RETRIEVE_DEFAULT_TEXT_ATTRIBUTE = "retrieveDefaultTextAttributeID";
083: private static final String RETRIEVE_FIRST_ACTIVE_TEXT_ATTRIBUTE = "retrieveFirstActiveTextAttributeID";
084:
085: private Serializable this Key = AttributeAccess.class;
086:
087: /**
088: * Constructor used by {@link org.tigris.scarab.da.DAFactory}.
089: */
090: public AttributeAccess() {
091: }
092:
093: /**
094: * Retrieves a list of attribute identifiers for use in
095: * determining which columns to display for a user's query
096: * results.
097: *
098: * @param userID The associated user (must be
099: * non-<code>null</code>).
100: * @param listID The associated artifact type list (can be
101: * <code>null</code>).
102: * @param moduleID The associated module (ignored if <code>null</code>).
103: * @param artifactTypeID The associated artifact type (ignored if
104: * <code>null</code>).
105: * @return A list of attribute identifiers.
106: * @throws DAException If any problems are encountered.
107: */
108: public List retrieveQueryColumnIDs(String userID, String listID,
109: String moduleID, String artifactTypeID) throws DAException {
110: List result = null;
111: Object obj = ScarabCache.get(this Key,
112: RETRIEVE_QUERY_COLUMN_IDS, userID, moduleID,
113: artifactTypeID);
114: if (obj == null) {
115: Criteria crit = new Criteria();
116: crit.addSelectColumn(RModuleUserAttributePeer.ATTRIBUTE_ID);
117: crit.add(RModuleUserAttributePeer.USER_ID, userID);
118: if (moduleID != null) {
119: crit.add(RModuleUserAttributePeer.MODULE_ID, moduleID);
120: }
121: if (artifactTypeID != null) {
122: crit.add(RModuleUserAttributePeer.ISSUE_TYPE_ID,
123: artifactTypeID);
124: }
125: // null should be added to criteria for listID
126: crit.add(RModuleUserAttributePeer.LIST_ID, listID)
127: .addAscendingOrderByColumn(
128: RModuleUserAttributePeer.PREFERRED_ORDER);
129:
130: try {
131: List records = RModuleUserAttributePeer
132: .doSelectVillageRecords(crit);
133: result = new ArrayList(records.size());
134: for (Iterator i = records.iterator(); i.hasNext();) {
135: result.add(((Record) i.next()).getValue(1)
136: .asString());
137: }
138: } catch (Exception e) {
139: throw new DAException(
140: L10NKeySet.ExceptionFailedToReadIdentifierList,
141: e);
142: }
143: ScarabCache.put(result, AttributeAccess.class,
144: RETRIEVE_QUERY_COLUMN_IDS, userID, moduleID,
145: artifactTypeID);
146: } else {
147: result = (List) obj;
148: }
149: return result;
150: }
151:
152: /**
153: * Deletes the persisted choice of issue list display columns for
154: * the given user and artifact type(s).
155: *
156: * @param userID The associated user (must be
157: * non-<code>null</code>).
158: * @param listID The associated artifact type list (can be
159: * <code>null</code>).
160: * @param moduleID The associated module (ignored if <code>null</code>).
161: * @param artifactTypeID The associated artifact type (ignored if
162: * <code>null</code>).
163: * @throws DAException If any problems are encountered.
164: */
165: public void deleteQueryColumnIDs(String userID, String listID,
166: String moduleID, String artifactTypeID) throws DAException {
167: Criteria crit = new Criteria();
168: crit.add(RModuleUserAttributePeer.USER_ID, userID);
169: if (moduleID != null) {
170: crit.add(RModuleUserAttributePeer.MODULE_ID, moduleID);
171: }
172: if (artifactTypeID != null) {
173: crit.add(RModuleUserAttributePeer.ISSUE_TYPE_ID,
174: artifactTypeID);
175: }
176: crit.add(RModuleUserAttributePeer.LIST_ID, listID);
177: try {
178: RModuleUserAttributePeer.doDelete(crit);
179: } catch (Exception e) {
180: throw new DAException(
181: L10NKeySet.ExceptionFailedToDeleteIdentifierList, e);
182: }
183: }
184:
185: /**
186: * Set of attributeIDs which are active and required within the given
187: * module for the given issue type and whose attribute group's are
188: * also active.
189: *
190: * @param moduleID The associated module (must be
191: * non-<code>null</code>).
192: * @param artifactTypeID The associated artifact type (must be
193: * non-<code>null</code>).
194: * @return an <code>String</code> of String attribute ids
195: */
196: public Set retrieveRequiredAttributeIDs(String moduleID,
197: String artifactTypeID) throws DAException {
198: Set attributes = null;
199: Object obj = ScarabCache.get(this Key,
200: RETRIEVE_REQUIRED_ATTRIBUTES, moduleID, artifactTypeID);
201: if (obj == null) {
202: Criteria crit = new Criteria(7).add(
203: RModuleAttributePeer.REQUIRED, true).add(
204: RModuleAttributePeer.ACTIVE, true).add(
205: RModuleAttributePeer.MODULE_ID, moduleID).add(
206: RModuleAttributePeer.ISSUE_TYPE_ID, artifactTypeID);
207: addGroupCriteria(crit, moduleID, artifactTypeID);
208: attributes = getRMAAttributeIdSet(crit);
209: ScarabCache.put(attributes, this Key,
210: RETRIEVE_REQUIRED_ATTRIBUTES, moduleID,
211: artifactTypeID);
212: } else {
213: attributes = (Set) obj;
214: }
215: return attributes;
216: }
217:
218: /**
219: * Set of attributeIDs which are active and marked for custom search
220: * within the given
221: * module for the given issue type and whose attribute group's are
222: * also active.
223: *
224: * @param moduleID The associated module (must be
225: * non-<code>null</code>).
226: * @param artifactTypeID The associated artifact type (must be
227: * non-<code>null</code>).
228: * @return an <code>Set</code> of String attribute ids
229: */
230: public Set retrieveQuickSearchAttributeIDs(String moduleID,
231: String artifactTypeID) throws DAException {
232: Set attributes = null;
233: Object obj = ScarabCache.get(this Key,
234: RETRIEVE_QUICK_SEARCH_ATTRIBUTES, moduleID,
235: artifactTypeID);
236: if (obj == null) {
237: Criteria crit = new Criteria(3).add(
238: RModuleAttributePeer.QUICK_SEARCH, true).add(
239: RModuleAttributePeer.MODULE_ID, moduleID).add(
240: RModuleAttributePeer.ISSUE_TYPE_ID, artifactTypeID);
241: attributes = getRMAAttributeIdSet(crit);
242: ScarabCache.put(attributes, this Key,
243: RETRIEVE_QUICK_SEARCH_ATTRIBUTES, moduleID,
244: artifactTypeID);
245: } else {
246: attributes = (Set) obj;
247: }
248: return attributes;
249: }
250:
251: private Set getRMAAttributeIdSet(Criteria crit) throws DAException {
252: crit.addSelectColumn(RModuleAttributePeer.ATTRIBUTE_ID);
253: Set attributes = null;
254: try {
255: List records = RModuleAttributePeer
256: .doSelectVillageRecords(crit);
257: attributes = new HashSet(records.size());
258: for (Iterator i = records.iterator(); i.hasNext();) {
259: attributes.add(((Record) i.next()).getValue(1)
260: .asString());
261: }
262: } catch (Exception e) {
263: throw new DAException(
264: L10NKeySet.ExceptionFailedToReadIdentifierList, e);
265: }
266: return attributes;
267: }
268:
269: private void addGroupCriteria(Criteria crit, String moduleID,
270: String artifactTypeID) {
271: crit.addJoin(RAttributeAttributeGroupPeer.ATTRIBUTE_ID,
272: RModuleAttributePeer.ATTRIBUTE_ID).addJoin(
273: RAttributeAttributeGroupPeer.GROUP_ID,
274: AttributeGroupPeer.ATTRIBUTE_GROUP_ID).add(
275: AttributeGroupPeer.MODULE_ID, moduleID).add(
276: AttributeGroupPeer.ISSUE_TYPE_ID, artifactTypeID).add(
277: AttributeGroupPeer.ACTIVE, true);
278: }
279:
280: /**
281: * Torque <code>Attribute</code>s which are active within the
282: * given module for the given issue type
283: * <strike>and whose attribute group's are also active</strike>.
284: *
285: * @param moduleID The associated module (must be
286: * non-<code>null</code>).
287: * @param artifactTypeID The associated artifact type (must be
288: * non-<code>null</code>).
289: * @param isOrdered indication whether an iterator over the Attributes
290: * should return them in their natural order.
291: * @return an <code>Collection</code> of torque Attribute objects. The
292: * collection will be a List if isOrdered is true, otherwise a Set is
293: * returned.
294: */
295: public Collection retrieveActiveAttributeOMs(String moduleID,
296: String artifactTypeID, boolean isOrdered)
297: throws DAException {
298: Collection attributes = null;
299: Boolean ordered = isOrdered ? Boolean.TRUE : Boolean.FALSE;
300: Object obj = ScarabCache.get(this Key,
301: RETRIEVE_ACTIVE_ATTRIBUTES, moduleID, artifactTypeID,
302: ordered);
303: if (obj == null) {
304: Criteria crit = new Criteria(2);
305: crit.add(RModuleAttributePeer.ACTIVE, true);
306: crit.add(RModuleAttributePeer.MODULE_ID, moduleID);
307: crit
308: .add(RModuleAttributePeer.ISSUE_TYPE_ID,
309: artifactTypeID);
310: // FIXME! would like to eliminate attributes that exist in
311: // inactive groups, but user attributes are not in groups, so
312: // this cannot be as simple as the required attributes which
313: // never include user attributes. Will probably require a left
314: // join. Leaving as it was for now. An attribute is active
315: // even if it is in an inactive group.
316: //addGroupCriteria(crit, moduleID, artifactTypeID);
317:
318: if (isOrdered) {
319: crit
320: .addAscendingOrderByColumn(RModuleAttributePeer.PREFERRED_ORDER);
321: crit
322: .addAscendingOrderByColumn(RModuleAttributePeer.DISPLAY_VALUE);
323: }
324:
325: crit.addJoin(AttributePeer.ATTRIBUTE_ID,
326: RModuleAttributePeer.ATTRIBUTE_ID);
327: List records = null;
328: try {
329: records = AttributePeer.doSelect(crit);
330: } catch (Exception e) {
331: throw new DAException(
332: L10NKeySet.ExceptionFailedToReadIdentifierList,
333: e);
334: }
335: if (isOrdered) {
336: attributes = new ArrayList(records.size());
337: } else {
338: attributes = new HashSet(records.size());
339: }
340:
341: for (Iterator i = records.iterator(); i.hasNext();) {
342: attributes.add(i.next());
343: }
344:
345: ScarabCache.put(attributes, this Key,
346: RETRIEVE_ACTIVE_ATTRIBUTES, moduleID,
347: artifactTypeID, ordered);
348: } else {
349: attributes = (Collection) obj;
350: }
351: return attributes;
352: }
353:
354: /**
355: * Retrieves the attribute ID which is active and marked as the
356: * default text attribute within the given
357: * module for the given issue type and whose attribute group is
358: * also active.
359: *
360: * @param moduleID The associated module (must be
361: * non-<code>null</code>).
362: * @param artifactTypeID The associated artifact type (must be
363: * non-<code>null</code>).
364: * @return an <code>String</code> attribute ID
365: */
366: public String retrieveDefaultTextAttributeID(String moduleID,
367: String artifactTypeID) throws DAException {
368: String result = null;
369: Object obj = ScarabCache.get(this Key,
370: RETRIEVE_DEFAULT_TEXT_ATTRIBUTE, moduleID,
371: artifactTypeID);
372: if (obj == null) {
373: Criteria crit = new Criteria(7);
374: crit.add(RModuleAttributePeer.DEFAULT_TEXT_FLAG, true).add(
375: RModuleAttributePeer.ACTIVE, true).add(
376: RModuleAttributePeer.MODULE_ID, moduleID).add(
377: RModuleAttributePeer.ISSUE_TYPE_ID, artifactTypeID);
378: addGroupCriteria(crit, moduleID, artifactTypeID);
379: result = getRMAAttributeId(crit);
380: ScarabCache.put(result, this Key,
381: RETRIEVE_DEFAULT_TEXT_ATTRIBUTE, moduleID,
382: artifactTypeID);
383: } else {
384: result = (String) obj;
385: }
386:
387: return result.length() == 0 ? null : result;
388: }
389:
390: private String getRMAAttributeId(Criteria crit) throws DAException {
391: String result = null;
392: crit.addSelectColumn(RModuleAttributePeer.ATTRIBUTE_ID);
393: try {
394: List records = RModuleAttributePeer
395: .doSelectVillageRecords(crit);
396: if (records.isEmpty()) {
397: result = ""; // for caching
398: } else {
399: result = ((Record) records.get(0)).getValue(1)
400: .asString();
401: }
402: } catch (Exception e) {
403: throw new DAException(
404: L10NKeySet.ExceptionFailedToReadIdentifierList, e);
405: }
406: return result;
407: }
408:
409: /**
410: * Retrieves the attribute ID which is active and is the first id returned
411: * when results are ordered based on numerical preferred order and/or
412: * alphabetical by name within the given
413: * module for the given issue type and whose attribute group is
414: * also active.
415: *
416: * @param moduleID The associated module (must be
417: * non-<code>null</code>).
418: * @param artifactTypeID The associated artifact type (must be
419: * non-<code>null</code>).
420: * @return An <code>String</code> attribute ID.
421: */
422: public String retrieveFirstActiveTextAttributeID(String moduleID,
423: String artifactTypeID) throws DAException {
424: String result = null;
425:
426: Object obj = ScarabCache.get(this Key,
427: RETRIEVE_FIRST_ACTIVE_TEXT_ATTRIBUTE, moduleID,
428: artifactTypeID);
429: if (obj == null) {
430: Criteria crit = new Criteria(7);
431: crit.add(RModuleAttributePeer.ACTIVE, true).add(
432: RModuleAttributePeer.MODULE_ID, moduleID).add(
433: RModuleAttributePeer.ISSUE_TYPE_ID, artifactTypeID);
434: addGroupCriteria(crit, moduleID, artifactTypeID);
435:
436: crit
437: .addAscendingOrderByColumn(RModuleAttributePeer.PREFERRED_ORDER);
438: crit
439: .addAscendingOrderByColumn(RModuleAttributePeer.DISPLAY_VALUE);
440:
441: result = getRMAAttributeId(crit);
442: ScarabCache.put(result, this Key,
443: RETRIEVE_FIRST_ACTIVE_TEXT_ATTRIBUTE, moduleID,
444: artifactTypeID);
445: } else {
446: result = (String) obj;
447: }
448:
449: return result.length() == 0 ? null : result;
450: }
451: }
|