Java tutorial
/* * Copyright 2006-2007 Luca Garulli (luca.garulli--at--assetdata.it) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.romaframework.aspect.view; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.romaframework.aspect.core.feature.CoreFieldFeatures; import org.romaframework.aspect.session.SessionAspect; import org.romaframework.aspect.session.SessionInfo; import org.romaframework.aspect.session.SessionListener; import org.romaframework.aspect.view.command.impl.ChangeScreenViewCommand; import org.romaframework.aspect.view.command.impl.RefreshViewCommand; import org.romaframework.aspect.view.command.impl.ShowViewCommand; import org.romaframework.aspect.view.event.SchemaEventAdd; import org.romaframework.aspect.view.event.SchemaEventAddInline; import org.romaframework.aspect.view.event.SchemaEventDown; import org.romaframework.aspect.view.event.SchemaEventEdit; import org.romaframework.aspect.view.event.SchemaEventOpen; import org.romaframework.aspect.view.event.SchemaEventRemove; import org.romaframework.aspect.view.event.SchemaEventReset; import org.romaframework.aspect.view.event.SchemaEventSearch; import org.romaframework.aspect.view.event.SchemaEventUp; import org.romaframework.aspect.view.event.SchemaEventView; import org.romaframework.aspect.view.feature.ViewActionFeatures; import org.romaframework.aspect.view.feature.ViewClassFeatures; import org.romaframework.aspect.view.feature.ViewFieldFeatures; import org.romaframework.aspect.view.form.ContentForm; import org.romaframework.aspect.view.form.FormViewer; import org.romaframework.aspect.view.form.ViewComponent; import org.romaframework.aspect.view.screen.Screen; import org.romaframework.core.Roma; import org.romaframework.core.Utility; import org.romaframework.core.exception.UserException; import org.romaframework.core.flow.Controller; import org.romaframework.core.flow.ObjectRefreshListener; import org.romaframework.core.module.SelfRegistrantConfigurableModule; import org.romaframework.core.schema.SchemaAction; import org.romaframework.core.schema.SchemaClass; import org.romaframework.core.schema.SchemaClassDefinition; import org.romaframework.core.schema.SchemaClassResolver; import org.romaframework.core.schema.SchemaField; import org.romaframework.core.schema.SchemaHelper; import org.romaframework.core.schema.SchemaObject; import org.romaframework.core.schema.SchemaReloadListener; import org.romaframework.core.schema.config.SchemaConfiguration; import org.romaframework.core.schema.reflection.SchemaClassReflection; import org.romaframework.core.schema.xmlannotations.XmlAspectAnnotation; import org.romaframework.core.schema.xmlannotations.XmlClassAnnotation; import org.romaframework.core.schema.xmlannotations.XmlFormAnnotation; /** * View Aspect abstract implementation. It configures the ViewAspect from Java5 and XML annotations. This is a good starting point * for all View aspect implementations by extending this. * * @author Luca Garulli (luca.garulli--at--assetdata.it) * */ public abstract class ViewAspectAbstract extends SelfRegistrantConfigurableModule<String> implements ViewAspect, SessionListener, SchemaReloadListener, ObjectRefreshListener { protected Map<SessionInfo, Map<Object, ViewComponent>> objectsForms; private static Log log = LogFactory.getLog(ViewAspectAbstract.class); public ViewAspectAbstract() { Controller.getInstance().registerListener(SessionListener.class, this); Controller.getInstance().registerListener(SchemaReloadListener.class, this); objectsForms = Collections.synchronizedMap(new HashMap<SessionInfo, Map<Object, ViewComponent>>()); } @Override public void startup() { // REGISTER THE VIEW DOMAIN TO SCHEMA CLASS RESOLVER Roma.component(SchemaClassResolver.class) .addDomainPackage(Utility.getApplicationAspectPackage(aspectName())); } @Override public void shutdown() { objectsForms.clear(); } public void beginConfigClass(SchemaClassDefinition iClass) { } public void endConfigClass(SchemaClassDefinition iClass) { updateFieldDependencies(iClass); } protected void updateFieldDependencies(SchemaClassDefinition iClass) { Iterator<SchemaField> iterator = iClass.getFieldIterator(); while (iterator.hasNext()) { SchemaField iField = iterator.next(); String[] dependsOnList = iField.getFeature(ViewFieldFeatures.DEPENDS_ON); if (dependsOnList != null) { for (String fieldName : dependsOnList) { SchemaField dependsFieldSchema = iClass.getField(fieldName); if (dependsFieldSchema == null) continue; String[] fieldDepends = dependsFieldSchema.getFeature(ViewFieldFeatures.DEPENDS); if (fieldDepends == null) fieldDepends = new String[0]; Set<String> fieldDependsList = new HashSet<String>(Arrays.asList(fieldDepends)); fieldDependsList.add(iField.getName()); dependsFieldSchema.setFeature(ViewFieldFeatures.DEPENDS, fieldDependsList.toArray(new String[] {})); } } } } public void configClass(SchemaClassDefinition iClass) { XmlClassAnnotation xmlNode = null; if (iClass instanceof SchemaClassReflection) { SchemaConfiguration conf = ((SchemaClassReflection) iClass).getDescriptor(); if (conf != null) xmlNode = conf.getType(); } if (xmlNode == null || xmlNode.aspect(ASPECT_NAME) == null) return; XmlAspectAnnotation featureDescriptor = xmlNode.aspect(ASPECT_NAME); if (featureDescriptor != null) { XmlFormAnnotation layout = featureDescriptor.getForm(); if (layout != null && layout.getRootArea() != null) iClass.setFeature(ViewClassFeatures.FORM, layout.getRootArea()); } } public void configField(SchemaField iField) { if (iField.getFeature(CoreFieldFeatures.EXPAND)) { iField.setFeature(ViewFieldFeatures.VISIBLE, false); } if (iField.getEntity().getFeature(ViewClassFeatures.EXPLICIT_ELEMENTS)) { if (!iField.isSettedFeature(ViewFieldFeatures.VISIBLE) && iField.getDescriptorInfo() == null) { iField.setFeature(ViewFieldFeatures.VISIBLE, false); } } if (iField.getFeature(CoreFieldFeatures.EMBEDDED)) { if (iField.getFeature(ViewFieldFeatures.RENDER) == null && !SchemaHelper.isMultiValueObject(iField)) // IF THE FIELD IS EMBEDDED, THEN THE DEFAULT RENDER IS OBJECTEMBEDDED iField.setFeature(ViewFieldFeatures.RENDER, ViewConstants.RENDER_OBJECTEMBEDDED); } String classRender = iField.getEntity().getFeature(ViewClassFeatures.RENDER); if (classRender != null) if (classRender.equals(ViewConstants.RENDER_MENU)) { // INSIDE A MENU: FORCE MENU RENDERING AND LAYOUT iField.setFeature(ViewFieldFeatures.RENDER, ViewConstants.RENDER_MENU); } else if (classRender.equals(ViewConstants.RENDER_ACCORDION)) { // INSIDE AN ACCORDITION: FORCE ACCORDITION LAYOUT iField.setFeature(ViewFieldFeatures.RENDER, ViewConstants.RENDER_ACCORDION); } if (SchemaHelper.isMultiValueObject(iField)) { iField.setEvent(new SchemaEventAddInline(iField)); iField.setEvent(new SchemaEventAdd(iField)); iField.setEvent(new SchemaEventView(iField)); iField.setEvent(new SchemaEventEdit(iField)); iField.setEvent(new SchemaEventRemove(iField)); iField.setEvent(new SchemaEventUp(iField)); iField.setEvent(new SchemaEventDown(iField)); } else if (iField.getType() != null && !SchemaHelper.isJavaType(iField.getType().getName())) { iField.setEvent(new SchemaEventOpen(iField)); iField.setEvent(new SchemaEventReset(iField)); iField.setEvent(new SchemaEventSearch(iField)); } } public void configAction(SchemaAction iAction) { if (((SchemaAction) iAction).getParameterNumber() > 0) iAction.setFeature(ViewActionFeatures.VISIBLE, Boolean.FALSE); iAction.toString(); if (iAction.getEntity().getFeature(ViewClassFeatures.EXPLICIT_ELEMENTS)) { if (!iAction.isSettedFeature(ViewActionFeatures.VISIBLE) && iAction.getDescriptorInfo() == null) { iAction.setFeature(ViewActionFeatures.VISIBLE, false); } } // CHECK RENDER AND LAYOUT MODES String classRender = iAction.getEntity().getFeature(ViewClassFeatures.RENDER); if (classRender != null) if (classRender.equals(ViewConstants.RENDER_MENU)) { // INSIDE A MENU: FORCE MENU RENDERING AND LAYOUT iAction.setFeature(ViewActionFeatures.RENDER, ViewConstants.RENDER_MENU); } } /** * Display the form reading information from POJO received in the current desktop, in default position. * * @param iContent * Object instance to display */ public void show(Object iContent) throws ViewException { show(iContent, null); } /** * Display the form reading information from POJO received following the layout rules. Display the object on iWhere position in * the current desktop. * * @param iContent * @param iPosition * @throws ViewException */ public void show(Object iContent, String iPosition) throws ViewException { show(iContent, iPosition, null, null); } /** * Display the form reading information from POJO received following the layout rules. Display the object on iWhere position in * the current desktop. * * @param iContent * @param iPosition * @throws ViewException */ public void show(Object iContent, String iPosition, Screen iScreen, SessionInfo iSession) throws ViewException { show(iContent, iPosition, iScreen, iSession, null); } /** * Display the form reading information from POJO received following the layout rules. Display the object on iWhere position in * the desktop received as the argument iDesktop. * * @param iContent * Object instance to display * @param iPosition * Desktop position where render the object * @param iScreen * Desktop instance to use * @throws Exception */ public void show(Object iContent, String iPosition, Screen iScreen, SessionInfo iSession, SchemaObject iSchema) throws ViewException { if (iScreen == null) // GET THE CURRENT ONE iScreen = getScreen(); if (iContent == null) { if (iPosition == null) // GET CURRENT AREA FOR OBJECT iPosition = getScreen().getActiveArea(); Roma.view().getScreen().getArea(iPosition).clear(); return; } boolean currentSession = iSession == null || iSession.equals(Roma.session().getActiveSessionInfo()); if (iSchema == null && iContent != null) { iSchema = Roma.session().getSchemaObject(iContent); } // SEARCH THE FORM TO VIEW BY ENTITY ContentForm form = (ContentForm) getFormByObject(iSession, iContent); if (form == null) { // CREATE IT form = ViewHelper.createForm(iSchema, null, iContent, iSession); } else { ViewHelper.invokeOnShow(iContent); iPosition = form.getScreenArea(); } if (iPosition == null) { iPosition = getScreen().getActiveArea(); } if (currentSession) // DISPLAY NOW showForm(form, iPosition, iScreen); else // PUSH CHANGES pushCommand(new ShowViewCommand(iSession, iScreen, form, iPosition)); } /** * Shows a form component * * @param iForm * The form to be showed * @param iWhere * The area where the form must be showed * @param iDesktop * The Screen where to show the form * @return */ public abstract String showForm(ContentForm iForm, String iWhere, Screen iDesktop); /** * Create a form instance * * @param iSchemaClass * the schema class for the form creation * @param iSchemaField * the schema field of the object, null if the form is not part of another form * @param iParent * the parent form * @return */ public abstract ContentForm createForm(SchemaObject iSchemaClass, SchemaField iSchemaField, ViewComponent iParent); /** * Return the desktop for the current user. * * @return Screen instance */ public Screen getScreen() { return FormViewer.getInstance().getScreen(); } /** * Return the screen for the user. * * @param iUserSession * User session * @return Screen instance */ public Screen getScreen(Object iUserSession) { return FormViewer.getInstance().getScreen(iUserSession); } /** * Set the current screen. * * @param iScreen * Screen instance to set for the current user. */ public void setScreen(Screen iScreen) { if (iScreen != null) FormViewer.getInstance().setScreen(iScreen); } /** * Set the current screen. * * @param iScreen * Screen instance to set for the current user. */ public void setScreen(Screen iScreen, SessionInfo iSession) { if (iScreen != null) pushCommand(new ChangeScreenViewCommand(iSession, iScreen)); } /** * Close the current form displayed. It applies only on Pop-up windows. * * @param iUserObject * User Object to close */ public boolean close(Object iUserObject) { // TODO:delete return true; } public void onSessionCreating(SessionInfo iSession) { objectsForms.put(iSession, new IdentityHashMap<Object, ViewComponent>()); } public void onSessionDestroying(SessionInfo iSession) { // REMOVE OBJECTS-AREA/COMPONENTS ASSOCIATION FOR CURRENT SESSION Map<Object, ViewComponent> forms = objectsForms.remove(iSession); if (forms != null) { if (log.isDebugEnabled()) log.debug("[ObjectContext.onSessionDestroying] Removing components " + forms.values().size()); for (ViewComponent c : forms.values()) { c.destroy(); } if (log.isDebugEnabled()) log.debug("[ObjectContext.onSessionDestroying] Removed " + forms.size() + " forms for session=" + iSession); } } /** * Create an association between a User Object and a ContentForm. This association is useful to gather custom form information. * * @param iUserObject * @param iForm */ public void createObjectFormAssociation(Object iUserObject, ViewComponent iForm, SessionInfo iSession) { if (iSession == null) iSession = Roma.session().getActiveSessionInfo(); if (iSession == null) throw new UserException(iForm.getContent(), "Cannot display the form since there is no active session"); Map<Object, ViewComponent> userForms = objectsForms.get(iSession); userForms.put(iUserObject, iForm); } public void removeObjectFormAssociation(Object iUserObject, SessionInfo iSession) { if (iSession == null) if (iSession == null) iSession = Roma.session().getActiveSessionInfo(); // REMOVE OBJECT-FORM ASSOCIATION Map<Object, ViewComponent> userForms = objectsForms.get(iSession); if (userForms != null) { if (log.isDebugEnabled()) log.debug("[ViewAspectAbstract.removeObjectFormAssociation] Flushing form: " + iUserObject); userForms.remove(iUserObject); } } /** * Return the form associated to a User Object. * * @param iUserObject * @return ContentComponent instance if any, otherwise null */ public ViewComponent getFormByObject(Object iUserObject) { return getFormByObject(null, iUserObject); } /** * Return the form associated to a User Object. * * @param iSession * User session, null to get the current active * @param iUserObject * @return ContentComponent instance if any, otherwise null */ public ViewComponent getFormByObject(Object iSession, Object iUserObject) { if (iSession == null) iSession = Roma.component(SessionAspect.class).getActiveSessionInfo(); Map<Object, ViewComponent> userForms = objectsForms.get(iSession); if (userForms == null) return null; return userForms.get(iUserObject); } /** * Return the first form of the declaring Class iClassOfObject. * * @param iSession * User session, null to get the current active * @param iClassOfObject * The Class of the object * @return ContentComponent instance if any, otherwise null */ public List<ViewComponent> getFormsByClass(Object iSession, SchemaClass iClassOfObject) { if (iSession == null) iSession = Roma.component(SessionAspect.class).getActiveSessionInfo(); Map<Object, ViewComponent> userForms = objectsForms.get(iSession); if (userForms == null) return null; List<ViewComponent> result = new ArrayList<ViewComponent>(); for (Map.Entry<Object, ViewComponent> entry : userForms.entrySet()) { if (entry.getValue().getSchemaObject().getSchemaClass().equals(iClassOfObject)) result.add(entry.getValue()); } return result; } /** * Return all the forms for all the active session that render POJOs of class iClass. * * @param iClass * Class to search * @return Map<SessionInfo, ContentComponent> with all entries that are handling POJOs of class iClass */ public Map<SessionInfo, ViewComponent> getFormsByClass(SchemaClass iClass) { Map<SessionInfo, ViewComponent> result = new HashMap<SessionInfo, ViewComponent>(); Map<Object, ViewComponent> perSessionObjects; SchemaClass cls; for (Map.Entry<SessionInfo, Map<Object, ViewComponent>> entry : objectsForms.entrySet()) { perSessionObjects = entry.getValue(); for (Map.Entry<Object, ViewComponent> formEntry : perSessionObjects.entrySet()) { if (formEntry.getKey() == null) continue; try { cls = Roma.schema().getSchemaClass(formEntry.getKey()); if (cls.extendsClass(iClass)) result.put(entry.getKey(), formEntry.getValue()); } catch (Exception e) { } } } return result; } /** * Refresh the changed objects. */ public void signalUpdatedClass(SchemaClass iSchemaClass, File iFile) { // OVERWRITE LIVING OBJECT SCHEMA OBJECTS BY COPYING NEW DEFINITION AND REFRESH ITS Map<SessionInfo, ViewComponent> forms = getFormsByClass(iSchemaClass); for (Map.Entry<SessionInfo, ViewComponent> entry : forms.entrySet()) { // entry.getValue().getSchemaObject().copyDefinition(iSchemaClass); Roma.aspect(ViewAspect.class) .pushCommand(new RefreshViewCommand(entry.getKey(), (ViewComponent) entry.getValue())); } } @Override public void onObjectRefresh(SessionInfo iSession, Object iContent) { ViewComponent handler = getFormByObject(iContent); if (handler == null) return; if (handler.getContainerComponent() != null) { // OBJECT INSIDE ANOTHER ONE: REFRESH USING ITS CONTAINER Object parentObject = handler.getContainerComponent().getContent(); String parentFieldName = handler.getSchemaField().getName(); Roma.fieldChanged(parentObject, parentFieldName); } else { // OBJECT INSIDE ANOTHER ONE: REFRESH USING ITS CONTAINER Roma.fieldChanged(iContent); } } public String aspectName() { return ASPECT_NAME; } }