001: /*
002: * Copyright 2005 jWic group (http://www.jwic.de)
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: *
016: * de.jwic.base.Control
017: * $Id: Control.java,v 1.7 2007/05/02 19:28:01 cosote Exp $
018: */
019: package de.jwic.base;
020:
021: import java.io.IOException;
022: import java.io.ObjectInputStream;
023: import java.io.Serializable;
024: import java.lang.reflect.InvocationTargetException;
025: import java.lang.reflect.Method;
026: import java.util.HashMap;
027: import java.util.Map;
028:
029: import org.apache.commons.logging.Log;
030: import org.apache.commons.logging.LogFactory;
031:
032: /**
033: * Superclass for jWic controls placed into an jWic container. A Control represents
034: * a part of an Application. All controls live in the SessionContext object, wich
035: * represents the application environment. A Control is connected to a
036: * {@link Container} object.
037: *
038: * It is recommend to create controls using the ControlFactory.
039: *
040: * Control objects live persistent until the application is closed or the control
041: * is removed from it's container.
042:
043: * @author Florian Lippisch
044: * @version $Revision: 1.7 $
045: */
046: public abstract class Control implements Serializable, IControl {
047:
048: protected final static String DEFAULT_RENDERER = "jwic.renderer.Default";
049: protected final static String DEFAULT_OUTER_RENDERER = "jwic.renderer.OuterContainer";
050:
051: private final static String ACTION_PREFIX = "action";
052:
053: /** Logger available to subclasses */
054: protected transient Log log = LogFactory.getLog(getClass());
055:
056: private boolean bolRequireRedraw = false;
057: private boolean bolVisible = true;
058:
059: private String name = null;
060: private IControlContainer objContainer = null;
061: private SessionContext objSessionContext = null;
062: private String strControlID = null;
063: private String rendererId = DEFAULT_RENDERER;
064:
065: protected Map fields = null;
066: protected String templateName = null;
067:
068: /**
069: * Constructs a new control instance and adds it to the specified
070: * container with the specified name. If the name is <code>null</code>,
071: * a unique name will be choosen by the container.
072: */
073: public Control(IControlContainer container, String name) {
074: container.registerControl(this , name);
075: }
076:
077: /**
078: * Get new logger after deserialization.
079: * @param s
080: * @throws IOException
081: */
082: private void readObject(ObjectInputStream s) throws IOException {
083: try {
084: s.defaultReadObject();
085: } catch (ClassNotFoundException e) {
086: throw new IOException("ClassNotFound in readObject");
087: }
088: log = LogFactory.getLog(getClass());
089: }
090:
091: /* (non-Javadoc)
092: * @see de.jwic.base.IControl#actionPerformed(java.lang.String, java.lang.String)
093: */
094: public void actionPerformed(String actionId, String parameter) {
095:
096: String methodName;
097: if (actionId.length() == 0) {
098: return;
099: } else if (actionId.length() == 1) {
100: methodName = ACTION_PREFIX + actionId.toUpperCase();
101: } else {
102: methodName = ACTION_PREFIX
103: + actionId.substring(0, 1).toUpperCase()
104: + actionId.substring(1);
105: }
106:
107: // try to find a method of the implementing control class that
108: // equals the actionId
109:
110: Method actionMethod = null;
111: Object[] arguments = new Object[] { parameter };
112: try {
113: actionMethod = getClass().getMethod(methodName,
114: new Class[] { String.class });
115: } catch (NoSuchMethodException e) {
116: // if the parameter is empty, try to find a method without arguments
117: if (parameter.length() == 0) {
118: arguments = null;
119: try {
120: actionMethod = getClass().getMethod(methodName,
121: null);
122: } catch (NoSuchMethodException e1) {
123: // no method exists -> will be handled later
124: }
125: }
126: }
127: if (actionMethod == null) {
128: // FLI: I do now throw an exception if the desired method was not found. It should
129: // not break existing applications because this method was abstract in earlier versions
130: // so it can not be called accidently.
131: log.error("A method to handle the action '" + actionId
132: + "' does not exist in this control. ("
133: + methodName + ")");
134: throw new IllegalArgumentException(
135: "A method to handle the action '" + actionId
136: + "' does not exist in this control. ("
137: + methodName + ")");
138: } else {
139: try {
140: actionMethod.invoke(this , arguments);
141: } catch (IllegalArgumentException e) {
142: log.error("Error invoking method "
143: + actionMethod.getName(), e);
144: } catch (IllegalAccessException e) {
145: log.error("Error invoking method "
146: + actionMethod.getName(), e);
147: } catch (InvocationTargetException e) {
148: Throwable t = e.getCause();
149: if (t instanceof RuntimeException) {
150: // forward the exception
151: throw (RuntimeException) t;
152: } else if (t != null) {
153: String msg = "Error during invocation of action method "
154: + actionMethod.getName();
155: log.error(msg, t);
156: throw new RuntimeException(msg, t);
157: }
158: String msg = "Unexpected InvocationTargetException";
159: log.error(msg, e);
160: throw new RuntimeException(msg);
161: }
162: }
163:
164: }
165:
166: /**
167: * Adds a field to the fieldlist.
168: * @param name
169: * @param field
170: */
171: void addField(Field field) {
172:
173: if (fields == null) {
174: fields = new HashMap();
175: }
176:
177: if (field.getName() == null) {
178: // generate a name.
179: int idx = 0;
180: String fName = Integer.toString(idx);
181: while (fields.containsKey(fName)) {
182: fName = Integer.toString(++idx);
183: }
184: field.setName(fName);
185: }
186: if (fields.containsKey(field.getName())) {
187: throw new IllegalArgumentException(
188: "A field with the name '" + field.getName()
189: + "' already exists in control '"
190: + getControlID() + "'.");
191: }
192: fields.put(field.getName(), field);
193: }
194:
195: /* (non-Javadoc)
196: * @see de.jwic.base.IControl#destroy()
197: */
198: public void destroy() {
199: if (objContainer != null
200: && objContainer.getControl(name) != null) {
201: // remove this control from container
202: objContainer.removeControl(name);
203: } else {
204: // do nothing by default.
205: log.debug("destroy() [" + getControlID() + "]");
206: // remove from top control
207: if (objSessionContext != null) {
208: objSessionContext.removeTopControl(this );
209: }
210: }
211: }
212:
213: /* (non-Javadoc)
214: * @see de.jwic.base.IControl#removeField(java.lang.String)
215: */
216: public void removeField(String fieldname) {
217: if (fields != null) {
218: fields.remove(fieldname);
219: }
220: }
221:
222: /* (non-Javadoc)
223: * @see de.jwic.base.IControl#removeField(de.jwic.base.Field)
224: */
225: public void removeField(Field field) {
226: if (fields != null) {
227: fields.remove(field.getName());
228: }
229: }
230:
231: /* (non-Javadoc)
232: * @see de.jwic.base.IControl#getField(java.lang.String)
233: */
234: public Field getField(String fieldname) {
235: if (fields != null) {
236: return (Field) fields.get(fieldname);
237: }
238: return null;
239: }
240:
241: /* (non-Javadoc)
242: * @see de.jwic.base.IControl#createActionURL(java.lang.String, java.lang.String)
243: */
244: public String createActionURL(String action, String acpara) {
245: StringBuffer sb = new StringBuffer();
246: sb.append("javascript:jWic().fireAction('");
247: sb.append(getControlID());
248: sb.append("', '");
249: sb.append(action);
250: sb.append("', '");
251: sb.append(acpara);
252: sb.append("');");
253:
254: return sb.toString();
255: }
256:
257: /**
258: * Returns a fieldname that may be used as name in an HTML form element.
259: * While the control can access the field by its name, it must have a
260: * different name on the HTML page where it is beeing displayed.
261: *
262: * @param name
263: * @return
264: * @deprecated use getField(name).getId() instead.
265: */
266: public String createFieldName(String fieldname) {
267: log
268: .warn("Usage of deprecated method Control.createFieldName()");
269: return "fld_" + getControlID() + "." + fieldname;
270: }
271:
272: /**
273: * Returns the value stored in the specified fieldname.
274: * If the field does not exist, an empty string is returned.
275: * @param fieldname
276: * @return String
277: * @deprecated use getField(name).getValue() instead.
278: */
279: public String getFieldValue(String fieldname) {
280: log.warn("Usage of deprecated method Control.getFieldValue()");
281: Field field = getField(fieldname);
282: if (field != null) {
283: String value = field.getValue();
284: return value != null ? value : "";
285: }
286: return "";
287: }
288:
289: /**
290: * Store a value that is displayed in an HTML form.</p>
291: *
292: * DEPRECATED: Fieldvalues have been replaced by the Field
293: * class. You must create a Field object for each HTML field
294: * representation. Fields that are not declared by the control
295: * will be ignored.
296: *
297: * @param fieldname
298: * @param value
299: * @deprecated use getField(name).setValue(value) instead.
300: */
301: public void setFieldValue(String fieldname, String value) {
302: log
303: .warn("Usage of deprecated method Control.setFieldValue(String, String)");
304: Field field = getField(fieldname);
305: if (field == null) {
306: field = new Field(this , fieldname);
307: }
308: field.setValue(value);
309: }
310:
311: /**
312: * Stores the values to the field. This method is invoked by the ActionController
313: * and will call the setFieldValue(String, String) method. If the values array contains
314: * just one element, the element is passed on. If it contains more then one elements,
315: * the elements are concated with a semicolon (;) as seperator. Controls that
316: * expect multiple values should override this method and handle the fields on their own.
317: *
318: * DEPRECATED: Fieldvalues have been replaced by the Field
319: * class. You must create a Field object for each HTML field
320: * representation. Fields that are not declared by the control
321: * will be ignored.
322: *
323: * @param fieldname
324: * @param value
325: * @deprecated use getField(name).setValues(values) instead.
326: */
327: public void setFieldValue(String fieldname, String[] values) {
328: log
329: .warn("Usage of deprecated method Control.setFieldValue(String, String[])");
330: Field field = getField(fieldname);
331: if (field == null) {
332: field = new Field(this , fieldname);
333: }
334: field.setValues(values);
335: }
336:
337: /* (non-Javadoc)
338: * @see de.jwic.base.IControl#getContainer()
339: */
340: public IControlContainer getContainer() {
341: return objContainer;
342: }
343:
344: /* (non-Javadoc)
345: * @see de.jwic.base.IControl#getControlID()
346: */
347: public java.lang.String getControlID() {
348: return strControlID;
349: }
350:
351: /* (non-Javadoc)
352: * @see de.jwic.base.IControl#getSessionContext()
353: */
354: public SessionContext getSessionContext() {
355: return objSessionContext;
356: }
357:
358: /* (non-Javadoc)
359: * @see de.jwic.base.IControl#isRequireRedraw()
360: */
361: public boolean isRequireRedraw() {
362: return bolRequireRedraw;
363: }
364:
365: /* (non-Javadoc)
366: * @see de.jwic.base.IControl#isVisible()
367: */
368: public boolean isVisible() {
369: return bolVisible;
370: }
371:
372: /**
373: * This method is used to give the control a connection to the Container object
374: * when it's added to a container.
375: */
376: void setContainer(IControlContainer newContainer) {
377: objContainer = newContainer;
378: }
379:
380: /**
381: * Set the ID of the control. Invoked when the control is added to a container.
382: * @param newControlID String
383: */
384: void setControlID(String newControlID) {
385: strControlID = newControlID;
386: }
387:
388: /**
389: * Flags the control that it must be rendered again to reflect its
390: * current state. Control implementors should use this method to
391: * let the framework render the control again when a page update
392: * occures.
393: */
394: protected void requireRedraw() {
395: setRequireRedraw(true);
396: }
397:
398: /* (non-Javadoc)
399: * @see de.jwic.base.IControl#setRequireRedraw(boolean)
400: */
401: public void setRequireRedraw(boolean requireRedraw) {
402: bolRequireRedraw = requireRedraw;
403: }
404:
405: /**
406: * This method is used to give the control a connection to the SessionContext object
407: * when it's added to a container.
408: */
409: void setSessionContext(SessionContext newSessionContext) {
410: objSessionContext = newSessionContext;
411: }
412:
413: /* (non-Javadoc)
414: * @see de.jwic.base.IControl#setVisible(boolean)
415: */
416: public void setVisible(boolean newVisible) {
417: if (bolVisible != newVisible) {
418: // JBO 2005-09-06: for nicer ajax support container is not updated anymore
419: setRequireRedraw(true);
420: }
421: bolVisible = newVisible;
422: }
423:
424: /* (non-Javadoc)
425: * @see de.jwic.base.IControl#getName()
426: */
427: public final String getName() {
428: return name;
429: }
430:
431: /**
432: * Sets the name of the Contorl.
433: * @param name The name to set.
434: */
435: void setName(String name) {
436: if (this .name != null && !this .name.equals(name)) {
437: throw new IllegalStateException(
438: "The name of a control can not be changed.");
439: }
440: this .name = name;
441: }
442:
443: /* (non-Javadoc)
444: * @see de.jwic.base.IControl#getRendererId()
445: */
446: public String getRendererId() {
447: return rendererId;
448: }
449:
450: /* (non-Javadoc)
451: * @see de.jwic.base.IControl#setRendererId(java.lang.String)
452: */
453: public void setRendererId(String rendererId) {
454: this .rendererId = rendererId;
455: }
456:
457: /* (non-Javadoc)
458: * @see de.jwic.base.IControl#getTemplateName()
459: */
460: public String getTemplateName() {
461: if (templateName == null) {
462: Class clazz = getClass();
463: for (String classname = clazz.getName(); classname
464: .indexOf("$") != -1;) {
465: clazz = clazz.getSuperclass();
466: classname = clazz.getName();
467: }
468: return clazz.getName();
469: }
470: return templateName;
471: }
472:
473: /* (non-Javadoc)
474: * @see de.jwic.base.IControl#setTemplateName(java.lang.String)
475: */
476: public void setTemplateName(String templateName) {
477: this.templateName = templateName;
478: }
479: }
|