001: package org.tigris.scarab.om;
002:
003: /* ================================================================
004: * Copyright (c) 2000-2005 CollabNet. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions are
008: * met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: *
017: * 3. The end-user documentation included with the redistribution, if
018: * any, must include the following acknowlegement: "This product includes
019: * software developed by Collab.Net <http://www.Collab.Net/>."
020: * Alternately, this acknowlegement may appear in the software itself, if
021: * and wherever such third-party acknowlegements normally appear.
022: *
023: * 4. The hosted project names must not be used to endorse or promote
024: * products derived from this software without prior written
025: * permission. For written permission, please contact info@collab.net.
026: *
027: * 5. Products derived from this software may not use the "Tigris" or
028: * "Scarab" names nor may "Tigris" or "Scarab" appear in their names without
029: * prior written permission of Collab.Net.
030: *
031: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
032: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
033: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
034: * IN NO EVENT SHALL COLLAB.NET OR ITS CONTRIBUTORS BE LIABLE FOR ANY
035: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
036: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
037: * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
038: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
039: * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
040: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
041: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
042: *
043: * ====================================================================
044: *
045: * This software consists of voluntary contributions made by many
046: * individuals on behalf of Collab.Net.
047: */
048:
049: import java.util.ArrayList;
050: import java.util.List;
051:
052: import org.apache.fulcrum.cache.CachedObject;
053: import org.apache.fulcrum.cache.GlobalCacheService;
054: import org.apache.fulcrum.cache.ObjectExpiredException;
055: import org.apache.fulcrum.intake.Retrievable;
056: import org.apache.torque.TorqueException;
057: import org.tigris.scarab.services.ServiceManager;
058: import org.tigris.scarab.tools.localization.L10NKey;
059: import org.tigris.scarab.tools.localization.L10NKeySet;
060: import org.tigris.scarab.util.ScarabException;
061: import org.tigris.scarab.util.ScarabRuntimeException;
062:
063: /**
064: * This class is used by Intake on the GlobalAttributeEdit page
065: * to create combination of a ROptionOption and a AttributeOption
066: *
067: * @author <a href="mailto:jon@collab.net">Jon S. Stevens</a>
068: * @version $Id: ParentChildAttributeOption.java 10193 2006-06-30 12:49:42Z dabbous $
069: */
070: public class ParentChildAttributeOption implements Retrievable,
071: java.io.Serializable {
072: /** the name of this class */
073: private static final String CLASS_NAME = "ParentChildAttributeOption";
074:
075: private Integer attributeId = null;
076: private Integer optionId = null;
077: private Integer parentId = null;
078: private boolean deleted = false;
079: private String name = null;
080: private int preferredOrder = 0;
081: private int weight = 0;
082: private List ancestors = null;
083: private static final Integer ROOT_ID = new Integer(0);
084:
085: /**
086: * Must call getInstance()
087: */
088: protected ParentChildAttributeOption() {
089: }
090:
091: /**
092: * Creates a key for use in caching AttributeOptions
093: */
094: static String getCacheKey(Integer option1, Integer option2) {
095: String keyStringA = option1.toString();
096: String keyStringB = option2.toString();
097: String output = new StringBuffer(CLASS_NAME.length()
098: + keyStringA.length() + keyStringB.length()).append(
099: CLASS_NAME).append(keyStringA).append(keyStringB)
100: .toString();
101: return output;
102: }
103:
104: /**
105: * Gets an instance of a new ParentChildAttributeOption
106: */
107: public static ParentChildAttributeOption getInstance() {
108: return new ParentChildAttributeOption();
109: }
110:
111: /**
112: * Gets an instance of a new ROptionOption
113: */
114: public static ParentChildAttributeOption getInstance(
115: Integer parent, Integer child) {
116: GlobalCacheService tgcs = getGlobalCacheService();
117:
118: String key = getCacheKey(parent, child);
119: ParentChildAttributeOption pcao = null;
120: try {
121: pcao = (ParentChildAttributeOption) tgcs.getObject(key)
122: .getContents();
123: } catch (ObjectExpiredException oee) {
124: pcao = getInstance();
125: pcao.setParentId(parent);
126: pcao.setOptionId(child);
127: tgcs.addObject(key, new CachedObject(pcao));
128: }
129: return pcao;
130: }
131:
132: /**
133: * Implementation of the Retrievable interface because this object
134: * is used with Intake
135: */
136: public String getQueryKey() {
137: if (parentId == null || optionId == null) {
138: return "";
139: }
140: return getParentId().toString() + ":"
141: + getOptionId().toString();
142: }
143:
144: /**
145: * Implementation of the Retrievable interface because this object
146: * is used with Intake
147: */
148: public void setQueryKey(String key) throws TorqueException {
149: int index = key.indexOf(":");
150: String a = key.substring(0, index);
151: String b = key.substring(index, key.length());
152: setParentId(new Integer(a));
153: setOptionId(new Integer(b));
154: }
155:
156: public Integer getAttributeId() {
157: return attributeId;
158: }
159:
160: public void setAttributeId(Integer attributeId) {
161: this .attributeId = attributeId;
162: }
163:
164: /**
165: * The 'child' optionid
166: */
167: public Integer getOptionId() {
168: return this .optionId;
169: }
170:
171: /**
172: * The 'child' optionid
173: */
174: public void setOptionId(Integer key) {
175: this .optionId = key;
176: }
177:
178: /**
179: * The 'child' AttributeOption
180: */
181: public AttributeOption getChildOption() throws TorqueException {
182: return AttributeOptionManager.getInstance(getOptionId());
183: }
184:
185: public Integer getParentId() {
186: if (this .parentId == null) {
187: return new Integer(0);
188: }
189: return this .parentId;
190: }
191:
192: public void setParentId(Integer id) {
193: this .parentId = id;
194: }
195:
196: public AttributeOption getParentOption() throws TorqueException {
197: return AttributeOptionManager.getInstance(getParentId());
198: }
199:
200: public List getAncestors() throws TorqueException, Exception {
201: ancestors = new ArrayList();
202: AttributeOption parent = getParentOption();
203: if (!ROOT_ID.equals(parent.getOptionId())) {
204: addAncestors(parent);
205: }
206: return ancestors;
207: }
208:
209: /**
210: * recursive helper method for getAncestors()
211: */
212: private void addAncestors(AttributeOption option)
213: throws TorqueException, Exception {
214: if (!ROOT_ID.equals(option.getParent().getOptionId())) {
215: if (ancestors.contains(option.getParent())) {
216: throw new TorqueException(
217: "Tried to add a recursive parent-child "
218: + "attribute option relationship."); //EXCEPTION
219: } else {
220: addAncestors(option.getParent());
221: }
222: }
223: ancestors.add(option.getOptionId());
224: }
225:
226: public boolean getDeleted() {
227: return this .deleted;
228: }
229:
230: public void setDeleted(boolean deleted) {
231: this .deleted = deleted;
232: }
233:
234: public String getName() {
235: if (this .name == null) {
236: return "";
237: }
238: return this .name;
239: }
240:
241: public void setName(String name) {
242: this .name = name;
243: }
244:
245: public int getPreferredOrder() {
246: return this .preferredOrder;
247: }
248:
249: public void setPreferredOrder(int preferredOrder) {
250: this .preferredOrder = preferredOrder;
251: }
252:
253: public int getWeight() {
254: return this .weight;
255: }
256:
257: public void setWeight(int weight) {
258: this .weight = weight;
259: }
260:
261: /**
262: * Removes the object from the cache
263: */
264: public static void doRemoveFromCache(Integer parent, Integer child) {
265: GlobalCacheService tgcs = getGlobalCacheService();
266:
267: String key = getCacheKey(parent, child);
268: tgcs.removeObject(key);
269: }
270:
271: public String toString() {
272: return getParentId() + ":" + getOptionId() + " -> " + getName();
273: }
274:
275: public void save() throws TorqueException, ScarabException {
276: AttributeOption ao = null;
277: ROptionOption roo = null;
278:
279: final Attribute tmpAttr = AttributeManager
280: .getInstance(getAttributeId());
281:
282: // if it is new, it won't already have an optionId
283: if (getOptionId() == null) {
284: // if it is new, check for duplicates.
285: final AttributeOption duplicate = AttributeOptionManager
286: .getInstance(tmpAttr, getName().trim());
287: final AttributeOption parent = AttributeOptionManager
288: .getInstance(getParentId());
289: if (duplicate != null) {
290: throw new ScarabException(new L10NKey(
291: "CannotCreateDuplicateOption")); //EXCEPTION
292: } else if (parent.getDeleted()) {
293: throw new ScarabException(new L10NKey(
294: "CannotCreateChild")); //EXCEPTION
295: }
296: }
297:
298: // if getOptionId() is null, then it will just create a new instance
299: final Integer optionId = getOptionId();
300: if (optionId == null) {
301: ao = AttributeOptionManager.getInstance();
302: } else {
303: ao = AttributeOptionManager.getInstance(getOptionId());
304: }
305:
306: ao.setName(getName());
307: ao.setDeleted(getDeleted());
308: ao.setAttribute(tmpAttr);
309: ao.save();
310:
311: // clean out the caches for the AO
312: tmpAttr.doRemoveCaches();
313:
314: // now set our option id from the saved AO
315: this .setOptionId(ao.getOptionId());
316:
317: // now create the ROO mapping
318: try {
319: // look for a cached ROptionOption
320: roo = ROptionOption.getInstance(getParentId(),
321: getOptionId());
322: } catch (ScarabException se) {
323: // could not find a cached instance create new one
324: roo = ROptionOption.getInstance();
325: roo.setOption1Id(getParentId());
326: roo.setOption2Id(getOptionId());
327: }
328: roo.setPreferredOrder(getPreferredOrder());
329: roo.setWeight(getWeight());
330: roo.setRelationshipId(OptionRelationship.PARENT_CHILD);
331: roo.save();
332: }
333:
334: /**
335: * Gets the <code>GlobalCacheService</code> implementation.
336: *
337: * @return the GlobalCacheService implementation.
338: */
339: protected static final GlobalCacheService getGlobalCacheService() {
340: try {
341: ServiceManager sm = ServiceManager.getInstance();
342: return (GlobalCacheService) sm
343: .lookup(GlobalCacheService.class);
344: } catch (Exception e) {
345: throw new ScarabRuntimeException(
346: L10NKeySet.ExceptionLookupGlobalCache, e);
347: }
348: }
349: }
|