001: /*
002: * Copyright 2006 Luca Garulli (luca.garulli@assetdata.it)
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:
017: package org.romaframework.core.flow;
018:
019: import java.lang.reflect.InvocationTargetException;
020: import java.util.Collection;
021: import java.util.List;
022:
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025: import org.romaframework.aspect.i18n.I18NAspect;
026: import org.romaframework.aspect.session.SessionAspect;
027: import org.romaframework.aspect.session.SessionInfo;
028: import org.romaframework.aspect.view.ViewAspect;
029: import org.romaframework.aspect.view.ViewConstants;
030: import org.romaframework.aspect.view.feature.ViewBaseFeatures;
031: import org.romaframework.aspect.view.form.ContentForm;
032: import org.romaframework.aspect.view.form.FormPool;
033: import org.romaframework.core.entity.EntityHelper;
034: import org.romaframework.core.exception.ConfigurationException;
035: import org.romaframework.core.exception.UserException;
036: import org.romaframework.core.schema.SchemaAction;
037: import org.romaframework.core.schema.SchemaClass;
038: import org.romaframework.core.schema.SchemaElement;
039: import org.romaframework.core.schema.SchemaField;
040: import org.romaframework.core.schema.SchemaHelper;
041: import org.romaframework.core.schema.SchemaManager;
042: import org.romaframework.core.schema.SchemaObject;
043: import org.romaframework.core.util.ListenerManager;
044:
045: public class Controller extends ListenerManager {
046:
047: private static Log log = LogFactory.getLog(Controller.class);
048: private static final Controller instance = new Controller();
049:
050: private static final String ERROR_LABEL = ".error";
051: public static final String CONTEXT_ATTR = "roma.controller.context";
052:
053: protected Controller() {
054: }
055:
056: public void executeAction(Object iContent, SchemaAction iAction)
057: throws Throwable {
058: if (iContent == null || iAction == null)
059: return;
060:
061: if (log.isInfoEnabled())
062: log.info("[Controller.executeAction] Executing action: "
063: + iAction + " on object " + iContent.toString()
064: + "...");
065:
066: if (!invokeBeforeActionCallbacks(iContent, iAction)) {
067: // JUMP EXECUTION
068: log
069: .info("[Controller.executeAction] Execution broken by a registered callback");
070: return;
071: }
072:
073: try {
074: iAction.getMethod().invoke(iContent, (Object[]) null);
075: } catch (InvocationTargetException ex) {
076: Throwable nestedExc = ex.getTargetException();
077:
078: if (nestedExc == null
079: || !(nestedExc instanceof UserException)) {
080: String errorLabel = I18NAspect.VARNAME_PREFIX
081: + iAction.getName() + ERROR_LABEL;
082:
083: log.warn(
084: "[Controller.executeAction] error on execution of method: "
085: + iAction.getName(), nestedExc);
086:
087: // WRAP THE EXCEPTION IN A NEW USER EXCEPTION TAKING THE ACTION NAME
088: throw new UserException(iContent, errorLabel, nestedExc);
089: }
090: // THROW THE NESTED EXCEPTION (BYPASS THE REFLECTION)
091: throw nestedExc;
092: } finally {
093: invokeAfterActionCallbacks(iContent, iAction);
094: }
095: }
096:
097: /**
098: * Invoke the before-action callback on every single one registered listener.
099: *
100: * @param iContent
101: * User Object
102: * @param iAction
103: * Target Action
104: */
105: public boolean invokeBeforeActionCallbacks(Object iContent,
106: SchemaElement iAction) {
107: List<UserObjectEventListener> listeners = getListeners(UserObjectEventListener.class);
108: boolean result = true;
109: for (UserObjectEventListener listener : listeners) {
110: result = listener
111: .onBeforeActionExecution(iContent, iAction);
112: if (!result)
113: break;
114: }
115: return result;
116: }
117:
118: /**
119: * Invoke the after-action callback on every single one registered listener.
120: *
121: * @param iContent
122: * User Object
123: * @param iAction
124: * Target Action
125: */
126: public void invokeAfterActionCallbacks(Object iContent,
127: SchemaElement iAction) {
128: List<UserObjectEventListener> listeners = getListeners(UserObjectEventListener.class);
129: for (UserObjectEventListener listener : listeners) {
130: try {
131: listener.onAfterActionExecution(iContent, iAction);
132: } catch (Throwable t) {
133: log.error(
134: "[Controller.invokeAfterActionCallbacks] listener: "
135: + listener, t);
136: }
137: }
138: }
139:
140: /**
141: * Flush all objects of a class.
142: *
143: * @param iEntityClassName
144: * Class name of objects to flush
145: */
146: public void flushObjectsOfClass(String iEntityClassName) {
147: Collection<SessionInfo> sessions = ObjectContext.getInstance()
148: .getComponent(SessionAspect.class).getSessionInfos();
149: for (SessionInfo sess : sessions) {
150: ControllerContext ctx = (ControllerContext) ObjectContext
151: .getInstance().getComponent(SessionAspect.class)
152: .getProperty(sess.getSystemSession(), CONTEXT_ATTR);
153: ctx.removeObject(iEntityClassName);
154: }
155: }
156:
157: /**
158: * Get the instance of user class iNextClass. If the instance is in the user session's pool then recycle it, otherwise create a
159: * new one and insert in to the user session's pool.
160: *
161: * @param iEntityClass
162: * User Class of requested object
163: * @param iEntityInstance
164: * Entity instance to set inside the object requested in case of ComposedEntity
165: * @return instance of class requested
166: */
167: public <T> T getObject(Class<T> iEntityClass, Object iEntityInstance) {
168: return (T) getObject(iEntityClass.getSimpleName(),
169: iEntityInstance);
170: }
171:
172: /**
173: * Get the instance of user class iEntityClassName. If the instance is in the user session's pool then recycle it, otherwise
174: * create a new one and insert in to the user session's pool.
175: *
176: * @param iEntityClassName
177: * User Class name of requested object
178: * @param iEntityInstance
179: * Entity instance to set inside the object requested in case of ComposedEntity
180: * @return instance of class requested
181: */
182: public <T> T getObject(String iEntityClassName,
183: Object iEntityInstance) {
184: ControllerContext context = getContext();
185:
186: T obj = null;
187: synchronized (context.getObjects()) {
188: obj = (T) context.getObjects().get(iEntityClassName);
189: if (obj == null) {
190: // FORM INSTANCE NOT YET CREATED, DO IT NOW AND SAVE IN SESSION
191: Class<T> objClass = (Class<T>) ObjectContext
192: .getInstance()
193: .getComponent(SchemaManager.class)
194: .getClassInfo(iEntityClassName).getClazz();
195: try {
196: obj = (T) EntityHelper.createObject(
197: iEntityInstance, objClass);
198: } catch (Exception e) {
199: throw new ConfigurationException(
200: "Cannot create instance for class "
201: + iEntityClassName, e);
202: }
203: context.getObjects().put(iEntityClassName, obj);
204: } else if (iEntityInstance != null)
205: // OBJECT ALREADY EXISTENT, SO UPDATE INTERNAL ENTITY
206: EntityHelper.assignEntity(obj, iEntityInstance);
207: }
208:
209: return obj;
210: }
211:
212: public ContentForm showField(Object content, SchemaField field,
213: ContentForm iParentForm) throws Exception {
214: Object fieldValue = SchemaHelper.getFieldValue(field, content);
215:
216: if (fieldValue == null) {
217: if (field.getFeature(ViewAspect.ASPECT_NAME,
218: ViewBaseFeatures.RENDER).equals(
219: ViewConstants.RENDER_OBJECTEMBEDDED)) {
220: // CREATE NEW OBJECT AND BIND IT
221: fieldValue = EntityHelper.createObject(null, field
222: .getTypeClass());
223: iParentForm.bind(field, fieldValue);
224: } else
225: // NULL VALUE: DO NOTHING
226: return null;
227: }
228:
229: SchemaClass linkedObjSchema = field.getClassInfo();
230:
231: // CREATE THE CHILD FORM FOR THE FIELD
232: ContentForm childForm = ObjectContext.getInstance()
233: .getComponent(FormPool.class).getForm(
234: new SchemaObject(linkedObjSchema), field,
235: fieldValue);
236:
237: return childForm;
238: }
239:
240: /**
241: * Return the context for current user.
242: *
243: * @return ControllerContext object
244: */
245: public ControllerContext getContext() {
246: return (ControllerContext) ObjectContext.getInstance()
247: .getComponent(SessionAspect.class).getProperty(
248: CONTEXT_ATTR);
249: }
250:
251: /**
252: * Create an empty context for current user.
253: */
254: public void createContext() {
255: ObjectContext.getInstance().getComponent(SessionAspect.class)
256: .setProperty(Controller.CONTEXT_ATTR,
257: new ControllerContext());
258: }
259:
260: public static Controller getInstance() {
261: return instance;
262: }
263: }
|