org.romaframework.aspect.view.ViewAspectAbstract.java Source code

Java tutorial

Introduction

Here is the source code for org.romaframework.aspect.view.ViewAspectAbstract.java

Source

/*
 * 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;
    }
}