View Javadoc

1   /* ===================================================================
2    * Copyright 2002-04 SRI International.
3    * Released under the MOZILLA PUBLIC LICENSE Version 1.1
4    * which can be obtained at http://www.mozilla.org/MPL/MPL-1.1.html
5    * This software is distributed on an "AS IS"
6    * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
7    * See the License for the specific language governing rights and
8    * limitations under the License.
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         // remember params; by default, they are cleared
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 }