1
2
3
4
5
6
7
8
9
10 package com.sri.emo.dbobj;
11
12 import com.jcorporate.expresso.core.controller.Input;
13 import com.jcorporate.expresso.core.controller.Output;
14 import com.jcorporate.expresso.core.controller.Transition;
15 import com.jcorporate.expresso.core.db.DBException;
16 import com.sri.emo.controller.AddNodeAction;
17 import org.apache.log4j.Category;
18 import org.apache.log4j.Logger;
19
20 import java.util.Hashtable;
21 import java.util.Iterator;
22 import java.util.Map;
23
24
25 /***
26 * base class for custom handler
27 *
28 * @author Larry Hamel
29 */
30 public abstract class AbstractAttributeHandler implements IPartHandler {
31 /***
32 * Creates and returns a copy of this object. The precise meaning
33 * of "copy" may depend on the class of the object. The general
34 * intent is that, for any object <tt>x</tt>, the expression:
35 * <blockquote>
36 * <pre>
37 * x.clone() != x</pre></blockquote>
38 * will be true, and that the expression:
39 * <blockquote>
40 * <pre>
41 * x.clone().getClass() == x.getClass()</pre></blockquote>
42 * will be <tt>true</tt>, but these are not absolute requirements.
43 * While it is typically the case that:
44 * <blockquote>
45 * <pre>
46 * x.clone().equals(x)</pre></blockquote>
47 * will be <tt>true</tt>, this is not an absolute requirement.
48 * <p/>
49 * By convention, the returned object should be obtained by calling
50 * <tt>super.clone</tt>. If a class and all of its superclasses (except
51 * <tt>Object</tt>) obey this convention, it will be the case that
52 * <tt>x.clone().getClass() == x.getClass()</tt>.
53 * <p/>
54 * By convention, the object returned by this method should be independent
55 * of this object (which is being cloned). To achieve this independence,
56 * it may be necessary to modify one or more fields of the object returned
57 * by <tt>super.clone</tt> before returning it. Typically, this means
58 * copying any mutable objects that comprise the internal "deep structure"
59 * of the object being cloned and replacing the references to these
60 * objects with references to the copies. If a class contains only
61 * primitive fields or references to immutable objects, then it is usually
62 * the case that no fields in the object returned by <tt>super.clone</tt>
63 * need to be modified.
64 * <p/>
65 * The method <tt>clone</tt> for class <tt>Object</tt> performs a
66 * specific cloning operation. First, if the class of this object does
67 * not implement the interface <tt>Cloneable</tt>, then a
68 * <tt>CloneNotSupportedException</tt> is thrown. Note that all arrays
69 * are considered to implement the interface <tt>Cloneable</tt>.
70 * Otherwise, this method creates a new instance of the class of this
71 * object and initializes all its fields with exactly the contents of
72 * the corresponding fields of this object, as if by assignment; the
73 * contents of the fields are not themselves cloned. Thus, this method
74 * performs a "shallow copy" of this object, not a "deep copy" operation.
75 * <p/>
76 * The class <tt>Object</tt> does not itself implement the interface
77 * <tt>Cloneable</tt>, so calling the <tt>clone</tt> method on an object
78 * whose class is <tt>Object</tt> will result in throwing an
79 * exception at run time.
80 *
81 * @return a clone of this instance.
82 * @throws CloneNotSupportedException if the object's class does not
83 * support the <code>Cloneable</code> interface. Subclasses
84 * that override the <code>clone</code> method can also
85 * throw this exception to indicate that an instance cannot
86 * be cloned.
87 * @see Cloneable
88 */
89 public Object clone() throws CloneNotSupportedException {
90 AbstractAttributeHandler result = (AbstractAttributeHandler) super.clone();
91 result.setParentAttrib(null);
92 return result;
93 }
94
95 public static final String OBSERVABLE_ID_XMLTAG = "OBSERVABLE_VARIABLE_ID";
96 private String mAttribName;
97 private Class mEditorClass;
98
99 private String mViewState;
100 private String mPromptEditState;
101 private Logger mlog;
102 private Attribute mParentAttrib;
103
104 public AbstractAttributeHandler(String attribName, Class editorClass,
105 String viewState, String promptEditState) {
106 mAttribName = attribName;
107 mEditorClass = editorClass;
108 mViewState = viewState;
109 mPromptEditState = promptEditState;
110 }
111
112 public String getAttribName() {
113 return mAttribName;
114 }
115
116 /***
117 * @return the transition for viewing
118 */
119 public Transition getViewTransition(Map params)
120 throws DBException {
121 Transition trans = new Transition(Attribute.CUSTOM_ATTRIBUTE,
122 "View Matrix", mEditorClass, mViewState);
123
124 if (params != null) {
125 copyParams(trans, params);
126 }
127
128 addIDs(trans, params);
129
130 return trans;
131 }
132
133 /***
134 * @param reqParams parameters from request; can be null
135 */
136 public void copyParams(Transition trans, Map reqParams) {
137
138 Map transparams = trans.getAllParameters();
139 if (reqParams != null) {
140 reqParams.remove("controller");
141 reqParams.remove("state");
142 trans.setParams(new Hashtable(reqParams));
143
144 for (Iterator iterator = transparams.keySet().iterator();
145 iterator.hasNext();) {
146 String key = (String) iterator.next();
147 trans.addParam(key, (String) transparams.get(key));
148 }
149 }
150 }
151
152 public void addIDs(Transition trans, Map reqParams) throws DBException {
153
154 if (mParentAttrib != null) {
155 trans.addParam(Node.NODE_ID, mParentAttrib.getParentNode().getNodeId());
156 trans.addParam(Attribute.ATTRIBUTE_ID, mParentAttrib.getAttribId());
157 } else if (reqParams != null) {
158 Node node = new Node();
159 node.setNodeId((String) reqParams.get(Node.NODE_ID));
160 node.retrieve();
161 Attribute[] attribs = node.getAttributes(getAttribName());
162
163 trans.addParam(Node.NODE_ID, node.getNodeId());
164
165 if (attribs.length > 0) {
166 trans.addParam(Attribute.ATTRIBUTE_ID, attribs[0].getAttribId());
167 }
168
169 }
170 }
171
172 /***
173 * get transition for editing
174 *
175 * @return the transition for editing or null; null indicates no special handling--use default
176 */
177 public Transition getEditTransition(Map params) throws DBException {
178 Transition trans = new Transition("Edit", mEditorClass, mPromptEditState);
179 copyParams(trans, params);
180
181 addIDs(trans, params);
182
183 return trans;
184 }
185
186 public Output getViewComment(Map reqParams) throws DBException {
187 String nodeId = (String) reqParams.get(Node.NODE_ID);
188
189 String result = "";
190
191 Node node = new Node(nodeId);
192 node.retrieve();
193 Attribute[] attribs = node.getAttributes(getAttribName());
194
195 if (attribs.length > 0) {
196 result = attribs[0].getAttribComment();
197 }
198
199 return new Output(Attribute.ATTRIBUTE_COMMENT, AddNodeAction.str(result));
200 }
201
202 /***
203 * convenience for getting logger for current (sub) class
204 *
205 * @return Category for logging
206 */
207 public Category getLogger() {
208 if (mlog == null) {
209 mlog = Logger.getLogger(getClass().getName());
210 }
211
212 return mlog;
213 }
214
215
216 public Attribute getParentAttrib() {
217 return mParentAttrib;
218 }
219
220 public void setParentAttrib(Attribute parentAttrib) {
221 this.mParentAttrib = parentAttrib;
222 }
223
224 /***
225 * this default no-op implementation returns 'false' always; override in subclasses
226 *
227 * @return true if this value is correct with respect to menu (category) limitations
228 */
229 public boolean validate(String key, String value) {
230 return false;
231 }
232
233 public void saveInput(Input key) throws DBException {
234 throw new DBException("not implemented");
235 }
236
237 /***
238 * used especially with matrix items that need default values if not set
239 *
240 * @return true if this attribute should be included when an XML request is made for 'FULL_XML'
241 */
242 public boolean isNeededInFullXML() {
243 return false;
244 }
245 }