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: // JDK classes
050: import java.util.List;
051: import java.util.ArrayList;
052: import java.util.Locale;
053: import java.sql.Connection;
054:
055: import org.apache.commons.lang.ObjectUtils;
056:
057: // Turbine classes
058: import org.apache.torque.TorqueException;
059: import org.apache.torque.om.Persistent;
060: import org.apache.fulcrum.localization.Localization;
061:
062: import org.tigris.scarab.tools.localization.L10NKeySet;
063: import org.tigris.scarab.tools.localization.LocalizationKey;
064: import org.tigris.scarab.util.ScarabConstants;
065: import org.tigris.scarab.util.ScarabException;
066: import org.tigris.scarab.util.Log;
067: import org.tigris.scarab.notification.ActivityType;
068: import org.tigris.scarab.om.ScarabUserManager;
069: import org.tigris.scarab.om.Module;
070:
071: /**
072: * This class is for dealing with Issue Attribute Values
073: *
074: * @author <a href="mailto:jmcnally@collab.net">John McNally</a>
075: * @author <a href="mailto:jon@collab.net">Jon S. Stevens</a>
076: * @author <a href="mailto:elicia@collab.net">Elicia David</a>
077: * @version $Id: AttributeValue.java 10131 2006-06-01 13:50:56Z dabbous $
078: */
079: public abstract class AttributeValue extends BaseAttributeValue
080: implements Persistent {
081: private ActivitySet activitySet;
082: private Integer oldOptionId;
083: private Integer oldUserId;
084: private String oldValue;
085: private Integer oldNumericValue;
086: private boolean oldOptionIdIsSet;
087: private boolean oldUserIdIsSet;
088: private boolean oldValueIsSet;
089: private boolean oldNumericValueIsSet;
090: private AttributeValue chainedValue;
091:
092: private String activityDescription = null;
093: private Activity saveActivity = null;
094:
095: private static String className = "AttributeValue";
096:
097: /** Creates a new attribute. Do not do anything here.
098: * All initialization should be performed in init().
099: */
100: protected AttributeValue() {
101: oldOptionIdIsSet = false;
102: oldUserIdIsSet = false;
103: oldValueIsSet = false;
104: oldNumericValueIsSet = false;
105: }
106:
107: /**
108: * Get the value of chainedValue.
109: * @return value of chainedValue.
110: */
111: public AttributeValue getChainedValue() {
112: return chainedValue;
113: }
114:
115: /**
116: * Set the value of chainedValue.
117: * @param v Value to assign to chainedValue.
118: */
119: public void setChainedValue(final AttributeValue v)
120: throws TorqueException, ScarabException {
121: if (v == null) {
122: this .chainedValue = null;
123: } else {
124: if (v.getAttributeId() == null && getAttributeId() != null) {
125: v.setAttributeId(getAttributeId());
126: } else if (v.getAttribute() != null
127: && !v.getAttribute().equals(getAttribute())) {
128: throw new ScarabException(
129: L10NKeySet.ExceptionCantChainAttributeValues, v
130: .getAttributeId(), getAttributeId());
131: }
132:
133: if (v.getIssueId() == null && getIssueId() != null) {
134: v.setIssueId(getIssueId());
135: } else if (v.getIssue() != null
136: && !v.getIssue().equals(getIssue())) {
137: throw new ScarabException(
138: L10NKeySet.ExceptionCantChainIssues, v
139: .getIssueId(), getIssueId());
140: }
141:
142: if (this .chainedValue == null) {
143: this .chainedValue = v;
144: } else {
145: chainedValue.setChainedValue(v);
146: }
147:
148: if (activitySet != null) {
149: v.startActivitySet(activitySet);
150: }
151: }
152: }
153:
154: /**
155: * This method returns a flat List of all AttributeValues that might
156: * be chained to this one. This AttributeValue will be first in the List.
157: *
158: * @return a <code>List</code> of AttributeValue's
159: */
160: public List getValueList() {
161: List list = new ArrayList();
162: list.add(this );
163: AttributeValue av = getChainedValue();
164: while (av != null) {
165: list.add(av);
166: av = av.getChainedValue();
167: }
168: return list;
169: }
170:
171: /**
172: * sets the AttributeId for this as well as any chained values.
173: */
174: public void setAttributeId(Integer nk) throws TorqueException {
175: super .setAttributeId(nk);
176: if (chainedValue != null) {
177: chainedValue.setAttributeId(nk);
178: }
179: }
180:
181: /**
182: * sets the IssueId for this as well as any chained values.
183: */
184: public void setIssueId(Long nk) throws TorqueException {
185: super .setIssueId(nk);
186: if (chainedValue != null) {
187: chainedValue.setIssueId(nk);
188: }
189: }
190:
191: /**
192: * Enters this attribute value into a activitySet. All changes to a
193: * value must occur within a activitySet. The activitySet is cleared
194: * once the attribute value is saved.
195: *
196: * @param activitySet a <code>ActivitySet</code> value
197: * @exception ScarabException if a new activitySet is set before
198: * the value is saved.
199: */
200: public void startActivitySet(ActivitySet activitySet)
201: throws ScarabException, TorqueException {
202: if (activitySet == null) {
203: throw new ScarabException(
204: L10NKeySet.ExceptionCanNotStartActivitySet);
205: }
206:
207: if (this .activitySet == null) {
208: this .activitySet = activitySet;
209: } else {
210: throw new ScarabException(
211: L10NKeySet.ExceptionActivitySetInProgress);
212: }
213: /*
214: This is wrong. It prevented the old/new value stuff from working properly!
215: If we have an existing issue and we change some attributes, then when the
216: history was created, the data was not valid in it for some reason. I'm not
217: quite sure why this was added. (JSS)
218:
219: Leaving here so that John can remove or fix.
220:
221: oldOptionIdIsSet = false;
222: oldValueIsSet = false;
223: oldOptionId = null;
224: oldValue = null;
225: */
226:
227: // Check for previous active activities on this attribute
228: // If they exist, set old value for this activity
229: List result = null;
230: final Issue issue = getIssue();
231: if (issue != null) {
232: result = issue.getActivitiesWithNullEndDate(getAttribute());
233: }
234: if (result != null && result.size() > 0) {
235: for (int i = 0; i < result.size(); i++) {
236: final Activity a = (Activity) result.get(i);
237: oldOptionId = a.getNewOptionId();
238: oldValue = a.getNewValue();
239: }
240: }
241: if (chainedValue != null) {
242: chainedValue.startActivitySet(activitySet);
243: }
244: }
245:
246: private void endActivitySet() {
247: this .activitySet = null;
248: this .saveActivity = null;
249: oldOptionId = null;
250: oldValue = null;
251: oldOptionIdIsSet = false;
252: oldValueIsSet = false;
253: if (chainedValue != null) {
254: chainedValue.endActivitySet();
255: }
256: }
257:
258: private void checkActivitySet(LocalizationKey l10nKey)
259: throws ScarabException {
260: if (activitySet == null) {
261: throw new ScarabException(l10nKey);
262: }
263: }
264:
265: public String getQueryKey() {
266: String key = super .getQueryKey();
267: if (key == null || key.length() == 0) {
268: try {
269: key = "__" + getAttribute().getQueryKey();
270: } catch (Exception e) {
271: key = "";
272: }
273: }
274:
275: return key;
276: }
277:
278: public boolean equals(Object obj) {
279: boolean b = false;
280: if (obj instanceof AttributeValue) {
281: b = super .equals(obj);
282: if (!b) {
283: //FIXME! this code will equate 2 AttributeValues that are
284: // multivalued, but are in a flat list.
285: AttributeValue aval = (AttributeValue) obj;
286: b = (getChainedValue() == null)
287: && ObjectUtils.equals(aval.getAttributeId(),
288: getAttributeId())
289: && ObjectUtils.equals(aval.getIssueId(),
290: getIssueId());
291: }
292: }
293: return b;
294: }
295:
296: public int hashCode() {
297: int retVal = 0;
298:
299: if (getChainedValue() != null || getPrimaryKey() != null) {
300: // get the hash code from the primary key
301: // field from BaseObject
302: retVal = super .hashCode();
303: } else {
304: int issueHashCode = 0;
305: if (getIssueId() != null) {
306: issueHashCode = getIssueId().hashCode();
307: }
308: retVal = getAttributeId().hashCode() ^ issueHashCode;
309: }
310: return retVal;
311: }
312:
313: public String toString() {
314: try {
315: String s = '{' + super .toString() + ": "
316: + getAttribute().getName();
317: if (getOptionId() != null) {
318: s += " optionId=" + getOptionId();
319: }
320: if (getUserId() != null) {
321: s += " userId=" + getUserId();
322: }
323: if (getValue() != null) {
324: s += " value=" + getValue();
325: }
326:
327: return s + '}';
328: } catch (Exception e) {
329: return super .toString();
330: }
331: }
332:
333: /**
334: * Get the OptionId
335: * @return String
336: */
337: public String getOptionIdAsString() {
338: String optionIdString = "";
339: if (getOptionId() != null) {
340: optionIdString = getOptionId().toString();
341: }
342: return optionIdString;
343: }
344:
345: /**
346: * Makes sure to set the Value as well, to make display of the
347: * option easier
348: *
349: * @param optionId a <code>Integer</code> value
350: */
351: public void setOptionId(Integer optionId) throws TorqueException {
352: if (optionId != null) {
353: Module module = getIssue().getModule();
354: IssueType issueType = getIssue().getIssueType();
355: if (module == null || issueType == null) {
356: AttributeOption option = AttributeOptionManager
357: .getInstance(optionId);
358: setValueOnly(option.getName());
359: } else {
360: // FIXME! create a key and get the instance directly from
361: // the manager.
362: List options = null;
363: try {
364: options = module.getRModuleOptions(getAttribute(),
365: issueType);
366: } catch (Exception e) {
367: if (e instanceof TorqueException) {
368: throw (TorqueException) e; //EXCEPTION
369: } else {
370: throw new TorqueException(e); //EXCEPTION
371: }
372: }
373: if (options != null) {
374: for (int i = options.size() - 1; i >= 0; i--) {
375: RModuleOption option = (RModuleOption) options
376: .get(i);
377: if (option.getOptionId().equals(optionId)) {
378: setValueOnly(option.getDisplayValue());
379: break;
380: }
381: }
382: }
383: }
384: } else {
385: // any reason to set a option_id to null, once its already set?
386: setValueOnly(null);
387: }
388:
389: setOptionIdOnly(optionId);
390: }
391:
392: /**
393: * Makes sure to set the Value as well
394: *
395: * @param v
396: */
397: public void setNumericValue(Integer v) {
398: setValueOnly(String.valueOf(v));
399: if (v != getNumericValue()) {
400: // if the value is set multiple times before saving only
401: // save the last saved value
402: if (!isNew() && !oldNumericValueIsSet) {
403: oldNumericValue = getNumericValue();
404: oldNumericValueIsSet = true;
405: }
406: super .setNumericValue(v);
407: }
408: }
409:
410: protected void setOptionIdOnly(Integer optionId)
411: throws TorqueException {
412: if (!ObjectUtils.equals(optionId, getOptionId())) {
413: // if the value is set multiple times before saving only
414: // save the last saved value
415: if (!isNew() && !oldOptionIdIsSet && getOptionId() != null) {
416: oldOptionId = getOptionId();
417: oldOptionIdIsSet = true;
418: }
419: super .setOptionId(optionId);
420: }
421: }
422:
423: /**
424: * Makes sure to set the Value as well, to make display of the
425: * user easier
426: *
427: * @param userId a <code>Integer</code> value
428: */
429: public void setUserId(Integer userId) throws TorqueException {
430: if (userId != null) {
431: ScarabUser user = ScarabUserManager.getInstance(userId);
432: setValueOnly(user.getUserName());
433: } else {
434: // any reason to set a user_id to null, once its already set?
435: setValueOnly(null);
436: }
437:
438: setUserIdOnly(userId);
439: }
440:
441: protected void setUserIdOnly(Integer value) throws TorqueException {
442: if (!ObjectUtils.equals(value, getUserId())) {
443: // if the value is set multiple times before saving only
444: // save the last saved value
445: if (!isNew() && !oldUserIdIsSet) {
446: oldUserId = getUserId();
447: oldUserIdIsSet = true;
448: }
449: super .setUserId(value);
450: }
451: }
452:
453: /**
454: * Not implemented always throws an exception
455: *
456: * @return a <code>Integer[]</code> value
457: * @exception Exception if an error occurs
458: */
459: public Integer[] getOptionIds() throws TorqueException {
460: List optionIds = new ArrayList();
461: if (getOptionId() != null) {
462: optionIds.add(getOptionId());
463: }
464: AttributeValue chainedAV = getChainedValue();
465: while (chainedAV != null) {
466: if (chainedAV.getOptionId() != null) {
467: optionIds.add(chainedAV.getOptionId());
468: }
469: chainedAV = chainedAV.getChainedValue();
470: }
471: if (Log.get().isDebugEnabled()) {
472: Log.get().debug(this + " optionIds: " + optionIds);
473: }
474:
475: return (Integer[]) optionIds.toArray(new Integer[optionIds
476: .size()]);
477: }
478:
479: public void setOptionIds(final Integer[] ids)
480: throws TorqueException, ScarabException {
481: if (ids != null && ids.length > 0) {
482: setOptionId(ids[0]);
483: }
484: if (ids != null && ids.length > 1) {
485: for (int i = 1; i < ids.length; i++) {
486: final AttributeValue av = AttributeValue
487: .getNewInstance(getAttributeId(), getIssue());
488: setChainedValue(av);
489: av.setOptionId(ids[i]);
490: }
491: }
492: }
493:
494: /**
495: * Not implemented always throws an exception
496: *
497: * @return a <code>Integer[]</code> value
498: * @exception Exception if an error occurs
499: */
500: public Integer[] getUserIds() throws TorqueException,
501: ScarabException {
502: throw new ScarabException(
503: L10NKeySet.ExceptionGetUserIdsNotImplemented);
504: }
505:
506: public void setUserIds(final Integer[] ids) throws TorqueException,
507: ScarabException {
508: if (ids != null && ids.length > 0) {
509: setUserId(ids[0]);
510: }
511: if (ids != null && ids.length > 1) {
512: for (int i = 1; i < ids.length; i++) {
513: final AttributeValue av = AttributeValue
514: .getNewInstance(getAttributeId(), getIssue());
515: setChainedValue(av);
516: av.setUserId(ids[i]);
517: }
518: }
519: }
520:
521: public void setValue(String value) {
522: setValueOnly(value);
523: }
524:
525: protected void setValueOnly(String value) {
526: if (!ObjectUtils.equals(value, getValue())) {
527: // if the value is set multiple times before saving only
528: // save the last saved value
529: if (!isNew() && !oldValueIsSet) {
530: oldValue = getValue();
531: oldValueIsSet = true;
532: }
533: super .setValue(value);
534: }
535: }
536:
537: public boolean isSet() {
538: return !(getOptionId() == null && getValue() == null && getUserId() == null);
539: }
540:
541: public boolean isRequired() throws TorqueException, ScarabException {
542: return getRModuleAttribute().getRequired();
543: }
544:
545: public RModuleAttribute getRModuleAttribute()
546: throws TorqueException, ScarabException {
547: final Issue issue = getIssue();
548: RModuleAttribute rma = null;
549: if (issue != null) {
550: final Module module = issue.getModule();
551: if (module != null) {
552: rma = module.getRModuleAttribute(getAttribute(),
553: getIssue().getIssueType());
554: } else {
555: throw new ScarabException(L10NKeySet.ExceptionGeneral,
556: "Module is null: Please report this issue."); //EXCEPTION
557: }
558: } else {
559: throw new ScarabException(L10NKeySet.ExceptionGeneral,
560: "Issue is null: Please report this issue."); //EXCEPTION
561: }
562: return rma;
563: }
564:
565: public AttributeOption getAttributeOption() throws TorqueException {
566: return getAttribute().getAttributeOption(getOptionId());
567: }
568:
569: /**
570: * if the Attribute related to this value is marked as relevant
571: * to quick search in the module related to the Issue
572: * related to this value.
573: *
574: * @return a <code>boolean</code> value
575: */
576: public boolean isQuickSearchAttribute() throws TorqueException {
577: boolean result = false;
578: List qsAttributes = getIssue().getIssueType()
579: .getQuickSearchAttributes(getIssue().getModule());
580: for (int i = qsAttributes.size() - 1; i >= 0; i--) {
581: if (((Attribute) qsAttributes.get(i))
582: .equals(getAttribute())) {
583: result = true;
584: break;
585: }
586: }
587: return result;
588: }
589:
590: /**
591: * Creates, initializes and returns a new AttributeValue.
592: * @return new Attribute instance
593: * @param rma the Attribute's rma
594: * @param issue Issue object which this attribute is associated with
595: */
596: public static AttributeValue getNewInstance(RModuleAttribute rma,
597: Issue issue) throws TorqueException {
598: return getNewInstance(rma.getAttributeId(), issue);
599: }
600:
601: /**
602: * Creates, initializes and returns a new AttributeValue.
603: * @return new AttributeValue instance
604: * @param issue Issue object which this attributeValue is associated
605: * @param attId the Attribute's Id
606: */
607: public static AttributeValue getNewInstance(Integer attId,
608: Issue issue) throws TorqueException {
609: Attribute attribute = AttributeManager.getInstance(attId);
610: return getNewInstance(attribute, issue);
611: }
612:
613: /**
614: * Creates, initializes and returns a new AttributeValue.
615: * @return new AttributeValue instance
616: * @param attribute the Attribute
617: * @param issue Issue object which this attributeValue is associated
618: */
619: public static synchronized AttributeValue getNewInstance(
620: Attribute attribute, Issue issue) throws TorqueException {
621: AttributeValue attv = null;
622: try {
623: String className = attribute.getAttributeType()
624: .getJavaClassName();
625: attv = (AttributeValue) Class.forName(className)
626: .newInstance();
627: attv.setAttribute(attribute);
628: attv.setIssue(issue);
629:
630: attv.init();
631: } catch (Exception e) {
632: throw new TorqueException(e); //EXCEPTION
633: }
634: return attv;
635: }
636:
637: /**
638: * Loads from database data specific for this Attribute including Name.
639: * These are data common to all Attribute instances with same id.
640: * Data retrieved here will then be used in setResources.
641: * @return Object containing Attribute resources which will be
642: * used in setResources.
643: */
644: protected abstract Object loadResources() throws TorqueException;
645:
646: /**
647: * This method is used by an Attribute instance to obtain
648: * specific resources such as option list for SelectOneAttribute.
649: * It may, for example put them into instance variables. Attributes
650: * may use common resources as-is or create it's own resources
651: * based on common, it should not, however, modify common resources
652: * since they will be used by other Attribute instances.
653: *
654: * @param resources Resources common for Attributes with the specified id.
655: */
656: protected abstract void setResources(Object resources);
657:
658: /** Override this method if you need any initialization for this attr.
659: * @throws TorqueException Generic Exception
660: */
661: public abstract void init() throws TorqueException;
662:
663: public boolean supportsVoting() {
664: return false;
665: }
666:
667: public AttributeValue copy() throws TorqueException {
668: AttributeValue copyObj = AttributeValue.getNewInstance(
669: getAttributeId(), getIssue());
670: return copyInto(copyObj);
671: }
672:
673: public void save(Connection dbcon) throws TorqueException {
674: if (isModified() && !getAttribute().isUserAttribute()) {
675: String desc = null;
676: try {
677: checkActivitySet(L10NKeySet.ExceptionCanNotSaveAttributeValue);
678: desc = getActivityDescription();
679: } catch (Exception e) {
680: throw new TorqueException(e); //EXCEPTION
681: }
682: // Save activity record
683: // Save new activity record, if activity has not been set
684: if (saveActivity == null) {
685: if (getDeleted()) {
686: saveActivity = ActivityManager.create(getIssue(),
687: getAttribute(), activitySet,
688: ActivityType.ATTRIBUTE_CHANGED, null, null,
689: getNumericValue(),
690: ScarabConstants.INTEGER_0, getUserId(),
691: null, getOptionId(), null, getValue(),
692: null, dbcon);
693: } else {
694: saveActivity = ActivityManager.create(getIssue(),
695: getAttribute(), activitySet,
696: ActivityType.ATTRIBUTE_CHANGED, null, null,
697: oldNumericValue, getNumericValue(),
698: oldUserId, getUserId(), oldOptionId,
699: getOptionId(), oldValue, getValue(), dbcon);
700: }
701: }
702: }
703: super .save(dbcon);
704: if (chainedValue != null) {
705: chainedValue.save(dbcon);
706: }
707: endActivitySet();
708: }
709:
710: /**
711: * Gets the Activity record associated with this AttributeValue
712: * It can only be retrieved after the save() method has been called
713: * since that is when it is generated.
714: */
715: public Activity getActivity() {
716: return this .saveActivity;
717: }
718:
719: public void setActivity(Activity activity) {
720: this .saveActivity = activity;
721: }
722:
723: /**
724: * Allows you to override the description for
725: * the activity that is generated when this attributevalue
726: * is saved.
727: */
728: public void setActivityDescription(String string) {
729: this .activityDescription = string;
730: }
731:
732: /**
733: * Not sure it is a good idea to save description in activity record
734: * the description can be generated from the other data.
735: */
736: private String getActivityDescription() throws TorqueException,
737: ScarabException {
738: if (activityDescription != null) {
739: return activityDescription;
740: }
741: final String attributeName = getRModuleAttribute()
742: .getDisplayValue();
743: String newValue = getValue();
744:
745: String result = null;
746: if (getDeleted()) {
747: result = Localization.format(
748: ScarabConstants.DEFAULT_BUNDLE_NAME, getLocale(),
749: "AttributeHasBeenUndefined", attributeName);
750: } else {
751: if (newValue.length() > 30) {
752: newValue = newValue.substring(0, 30) + "...";
753: }
754: if (oldValue == null) {
755: final Object[] args = { attributeName, newValue };
756: result = Localization.format(
757: ScarabConstants.DEFAULT_BUNDLE_NAME,
758: getLocale(), "AttributeSetToNewValue", args);
759: } else {
760: // so that we don't modify the existing oldValue
761: String tmpOldValue = null;
762: if (oldValue.length() > 30) {
763: tmpOldValue = oldValue.substring(0, 30) + "...";
764: } else {
765: tmpOldValue = oldValue;
766: }
767: final Object[] args = { attributeName, tmpOldValue,
768: newValue };
769: result = Localization.format(
770: ScarabConstants.DEFAULT_BUNDLE_NAME,
771: getLocale(), "AttributeChangedFromToNewValue",
772: args);
773: }
774: }
775: return result;
776: }
777:
778: /**
779: * Sets the properties of one attribute value based on another
780: * NOTE: Does not copy the deleted field
781: */
782: public void setProperties(final AttributeValue attVal1)
783: throws TorqueException {
784: setAttribute(attVal1.getAttribute());
785: setIssue(attVal1.getIssue());
786: setNumericValue(attVal1.getNumericValue());
787: setOptionId(attVal1.getOptionId());
788: setUserId(attVal1.getUserId());
789: setValue(attVal1.getValue());
790: }
791:
792: /**
793: * Returns a (possibly user-specific) locale.
794: *
795: * @return a Locale selected for the Fulcrum Localization context
796: */
797: private Locale getLocale() {
798: return ScarabConstants.DEFAULT_LOCALE;
799: }
800: }
|