001: /**
002: * Copyright 2006 Webmedia Group Ltd.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: **/package org.araneaframework.backend;
016:
017: import java.io.Serializable;
018: import java.util.HashSet;
019: import java.util.Iterator;
020: import java.util.List;
021: import java.util.Set;
022: import org.apache.commons.logging.Log;
023: import org.apache.commons.logging.LogFactory;
024: import org.araneaframework.backend.util.BeanMapper;
025:
026: /**
027: * Base class for value objects. Implements some general properties and methods.
028: *
029: * @author Jevgeni Kabanov
030: * @since 1.4.1.20
031: */
032: public abstract class BaseBean implements Serializable, Cloneable {
033:
034: private static final Log log = LogFactory.getLog(BaseBean.class);
035:
036: //*******************************************************************
037: // FIELDS
038: //*******************************************************************
039:
040: /**
041: * Holds names of fields which are marked as changed. Is used for update/insert operations.
042: */
043: private Set changes = new HashSet();
044:
045: /**
046: * Private VoMapper, used for <code>toString</code> and <code>equals</code> methods.
047: */
048: private BeanMapper beanMapper;
049:
050: //*******************************************************************
051: // PUBLIC METHODS
052: //*******************************************************************
053:
054: /**
055: * Creates new instance of the GeneralVO.
056: */
057: protected BaseBean() {
058: beanMapper = new BeanMapper(getClass());
059: }
060:
061: /**
062: * Overrides default <code>toString</code> method.
063: * <P/>
064: *
065: * @return <code>java.lang.String</code> representation of this value object.
066: */
067: public String toString() {
068: StringBuffer result = new StringBuffer();
069: List voFields = beanMapper.getFields();
070: for (Iterator i = voFields.iterator(); i.hasNext();) {
071: String field = (String) i.next();
072: result.append(field);
073: result.append("=");
074: result.append("" + beanMapper.getFieldValue(this , field));
075: result.append("; ");
076: }
077: return result.toString();
078: }
079:
080: /**
081: * Compares Value Object for equality by their fields.
082: *
083: * @param otherVo
084: * Value Object to compare to.
085: * @return <code>boolean</code>- if Value Object are equal.
086: */
087: public boolean equals(Object otherVo) {
088: //In case other VO is null, or of other class.
089: if (otherVo == null
090: || (!this .getClass().equals(otherVo.getClass()))) {
091: return false;
092: }
093:
094: //Otherwise compare all fields
095: boolean result = true;
096: List voFields = beanMapper.getFields();
097: for (Iterator i = voFields.iterator(); i.hasNext() && result;) {
098: String field = (String) i.next();
099: result = valuesEqual(beanMapper.getFieldValue(this , field),
100: beanMapper.getFieldValue(otherVo, field));
101: }
102: return result;
103: }
104:
105: /**
106: * Implements hash using Value Object fields.
107: */
108: public int hashCode() {
109: int result = 17;
110: List voFields = beanMapper.getFields();
111: for (Iterator i = voFields.iterator(); i.hasNext();) {
112: String field = (String) i.next();
113: result = 37 * result
114: + beanMapper.getFieldValue(this , field).hashCode();
115: }
116: return result;
117: }
118:
119: /**
120: * Overrides default <code>clone()</code> operation.
121: * <P/>
122: *
123: * @return clone of this object.
124: */
125: public Object clone() {
126: try {
127: return super .clone();
128: } catch (CloneNotSupportedException e) {
129: log
130: .warn("BaseVO threw CloneNotSupportedException, check that everything is defined Cloneable");
131: return null;
132: }
133: }
134:
135: //*******************************************************************
136: // LEGACY PUBLIC METHODS
137: //*******************************************************************
138:
139: /**
140: * Getter for property changes.
141: * <P/>
142: *
143: * @return Value of property changes.
144: */
145: public Set getChanges() {
146: return changes;
147: }
148:
149: /**
150: * Marks field of the value object as changed eg this field was changed after loading it from the database.
151: * <P/>
152: * Useful when value objects are used for insert/update procedures written in PL/SQL instead of EJB methods.
153: * <P/>
154: *
155: * @param name
156: * name of the VO-s field which is being changed.
157: * @return <code>true</code> if such field does exist and was marked as chaned, <code>false</code> otherwise.
158: */
159: public boolean addChange(String name) {
160: log.debug("Adding changed field = " + name);
161: try {
162: this .getClass().getMethod(
163: "get" + name.substring(0, 1).toUpperCase()
164: + name.substring(1), (Class[]) null);
165: changes.add(name);
166: return true;
167: } catch (NoSuchMethodException ex) {
168: log.debug(ex);
169: return false;
170: }
171: }
172:
173: /**
174: * Changes all fields on this <i>value object</i> as changed.
175: */
176: public void changeAll() {
177: List voFields = beanMapper.getFields();
178: for (Iterator i = voFields.iterator(); i.hasNext();) {
179: String field = (String) i.next();
180: addChange(field);
181: }
182: }
183:
184: /**
185: * Marks all fields as unchanged.
186: */
187: public void clearChanges() {
188: changes = new HashSet();
189: }
190:
191: //*******************************************************************
192: // PRIVATE HELPER METHODS
193: //*******************************************************************
194:
195: /**
196: * Checks for object equality.
197: */
198: private boolean valuesEqual(Object value1, Object value2) {
199: return (value1 == null) ? value2 == null : value1
200: .equals(value2);
201: }
202: }
|