Package org.apache.isis.viewer.html.context

Source Code of org.apache.isis.viewer.html.context.Context

/*
*  Licensed to the Apache Software Foundation (ASF) under one
*  or more contributor license agreements.  See the NOTICE file
*  distributed with this work for additional information
*  regarding copyright ownership.  The ASF licenses this file
*  to you 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.apache.isis.viewer.html.context;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Stack;

import org.apache.log4j.Logger;

import org.apache.isis.core.commons.authentication.AuthenticationSession;
import org.apache.isis.core.commons.debug.DebugBuilder;
import org.apache.isis.core.commons.ensure.Assert;
import org.apache.isis.core.commons.exceptions.IsisException;
import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
import org.apache.isis.core.metamodel.spec.ObjectSpecification;
import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
import org.apache.isis.core.runtime.userprofile.UserProfile;
import org.apache.isis.runtimes.dflt.runtime.persistence.ConcurrencyException;
import org.apache.isis.runtimes.dflt.runtime.system.context.IsisContext;
import org.apache.isis.runtimes.dflt.runtime.system.persistence.AdapterManager;
import org.apache.isis.viewer.html.component.Block;
import org.apache.isis.viewer.html.component.ComponentFactory;
import org.apache.isis.viewer.html.crumb.CollectionCrumb;
import org.apache.isis.viewer.html.crumb.Crumb;
import org.apache.isis.viewer.html.crumb.ObjectCrumb;
import org.apache.isis.viewer.html.crumb.ObjectFieldCrumb;
import org.apache.isis.viewer.html.crumb.TaskCrumb;
import org.apache.isis.viewer.html.request.Request;
import org.apache.isis.viewer.html.task.Task;

public class Context {
    private static final Logger LOG = Logger.getLogger(Context.class);
    private final Map actionMap = new HashMap();
    private final ComponentFactory componentFactory;
    private final ObjectHistory history = new ObjectHistory();
    private boolean isValid;
    private int max;
    private final Map<String, CollectionMapping> collectionMap = new HashMap<String, CollectionMapping>();
    private final Map<String, ObjectMapping> objectMap = new HashMap<String, ObjectMapping>();
    private final Map<String, ObjectMapping> serviceMap = new HashMap<String, ObjectMapping>();
    private final Stack<Crumb> crumbs = new Stack<Crumb>();
    private final List<String> messages = new ArrayList<String>();
    private final List<String> warnings = new ArrayList<String>();

    private AuthenticationSession session;

    public Context(final ComponentFactory factory) {
        componentFactory = factory;
        isValid = true;
        clearMessagesAndWarnings();
        LOG.debug(this + " created with " + factory);
    }

    public void setObjectCrumb(final ObjectAdapter object) {
        while (crumbs.size() > 0 && !(crumbs.lastElement() instanceof TaskCrumb)) {
            crumbs.pop();
        }
        final String id = mapObject(object);
        crumbs.push(new ObjectCrumb(id, object));
    }

    public void addCollectionFieldCrumb(final String collectionFieldName) {
        crumbs.push(new ObjectFieldCrumb(collectionFieldName));
    }

    public void addCollectionCrumb(final String id) {
        while (crumbs.size() > 0 && !(crumbs.lastElement() instanceof TaskCrumb)) {
            crumbs.pop();
        }
        crumbs.push(new CollectionCrumb(id, getMappedCollection(id)));
    }

    public void addTaskCrumb(final Task task) {
        while (crumbs.size() > 1 && !(crumbs.lastElement() instanceof ObjectCrumb)) {
            crumbs.pop();
        }
        Assert.assertNotNull(task);
        Assert.assertTrue(!isTask());
        task.init(this);
        crumbs.push(new TaskCrumb(task));
    }

    public void debug(final DebugBuilder debug) {
        debug.startSection("Web Session Context");
        debug.appendAsHexln("hash", hashCode());
        debug.appendln("session", session);
        debug.appendln("is valid", isValid);
        debug.appendln("next id", max);
        debug.appendln("factory", componentFactory);
        debug.appendln("is task", isTask());

        debug.appendln("crumbs (" + crumbs.size() + ")");

        debug.indent();
        for (int i = 0; i < crumbs.size(); i++) {
            final Crumb crumb = crumbs.get(i);
            debug.appendln(i + 1 + ". " + crumb);
            debug.indent();
            crumb.debug(debug);
            debug.unindent();
        }
        debug.unindent();

        debug.startSection("Objects");
        for (final String id : objectMap.keySet()) {
            final ObjectMapping object = objectMap.get(id);
            debug.appendln(id + " -> " + object.getOid());
            debug.indent();
            object.debug(debug);
            debug.unindent();
        }
        debug.endSection();

        debug.startSection("Collections");
        for (final String id : collectionMap.keySet()) {
            final CollectionMapping coll = collectionMap.get(id);
            debug.appendln(id + " -> collection of " + coll.getElementSpecification().getPluralName());
            coll.debug(debug);
        }
        debug.endSection();

        debug.startSection("Actions");
        debugMap(debug, actionMap);
        debug.endSection();

        debug.startSection("History");
        history.debug(debug);
        debug.endSection();

        debug.endSection();
    }

    private void debugMap(final DebugBuilder debug, final Map map) {
        final Iterator names = map.keySet().iterator();
        while (names.hasNext()) {
            final String name = (String) names.next();
            debug.appendln(name + " -> " + map.get(name));
        }
    }

    public ObjectAction getMappedAction(final String id) {
        return (ObjectAction) getMappedInstance(actionMap, id);
    }

    public ComponentFactory getComponentFactory() {
        return componentFactory;
    }

    /**
     * Returns an array of instances of the specified type that are currently
     * known in the current context, ie have been recently seen by the user.
     *
     * <p>
     * These will be resolved if required, with a transaction created (and
     * ended) if required.
     */
    public ObjectAdapter[] getKnownInstances(final ObjectSpecification type) {

        final List<ObjectAdapter> instances = new ArrayList<ObjectAdapter>();

        for (final String id : objectMap.keySet()) {
            final ObjectAdapter adapter = getMappedObject(id);
            IsisContext.getPersistenceSession().resolveImmediately(adapter);
            if (adapter.getSpecification().isOfType(type)) {
                instances.add(adapter);
            }
        }

        final ObjectAdapter[] array = new ObjectAdapter[instances.size()];
        instances.toArray(array);
        return array;
    }

    private String addToMap(final Map map, final Object object) {
        Assert.assertNotNull(object);
        if (map.containsValue(object)) {
            return findExistingId(map, object);
        } else {
            return mapNewObject(map, object);
        }
    }

    private String mapNewObject(final Map map, final Object object) {
        max++;
        final String id = "" + max;
        map.put(id, object);

        final String mapName = map == objectMap ? "object" : (map == collectionMap ? "collection" : "action");
        LOG.debug("add " + object + " to " + mapName + " as #" + id);

        return id;
    }

    private String findExistingId(final Map<String, ?> map, final Object object) {
        for (final String id : map.keySet()) {
            if (object.equals(map.get(id))) {
                return id;
            }
        }
        throw new IsisException();
    }

    private Object getMappedInstance(final Map map, final String id) {
        final Object object = map.get(id);
        if (object == null) {
            final String mapName = (map == objectMap) ? "object" : (map == collectionMap ? "collection" : "action");
            throw new ObjectLookupException("No object in " + mapName + " map with id " + id);
        }
        return object;
    }

    public ObjectAdapter getMappedCollection(final String id) {
        final CollectionMapping map = (CollectionMapping) getMappedInstance(collectionMap, id);
        return map.getCollection(this);
    }

    public ObjectAdapter getMappedObject(final String id) {
        final ObjectMapping mappedObject = (ObjectMapping) getMappedInstance(objectMap, id);
        final ObjectAdapter object = mappedObject.getObject();

        // ensure resolved if currently a ghost;
        // start/end xactn if required
        if (object.isPersistent() && object.getResolveState().isGhost()) {
            IsisContext.getPersistenceSession().resolveImmediately(object);
        }

        try {
            mappedObject.checkVersion(object);
        } catch (final ConcurrencyException e) {
            LOG.info("concurrency conflict: " + e.getMessage());
            messages.clear();
            messages.add(e.getMessage());
            messages.add("Reloaded object " + object.titleString());
            updateVersion(object);
        }
        return object;
    }

    public Task getTask(final String taskId) {
        Task task = null;
        for (int i = crumbs.size() - 1; i >= 0; i--) {
            final Object crumb = crumbs.get(i);
            if (crumb instanceof TaskCrumb) {
                final TaskCrumb taskCrumb = (TaskCrumb) crumb;
                final String id = taskCrumb.getTask().getId();
                if (taskId.equals(id)) {
                    task = taskCrumb.getTask();
                    break;
                }
            }
        }
        return task;
    }

    public Request cancelTask(final Task task) {
        if (task != null) {
            endTask(task);
        }

        // REVIEW does this take us back to the right object?
        final Crumb crumb = crumbs.get(crumbs.size() - 1);
        return crumb.changeContext();
    }

    public void invalidate() {
        isValid = false;
    }

    public boolean isValid() {
        return isValid;
    }

    public boolean isLoggedIn() {
        return session != null;
    }

    public String mapAction(final ObjectAction action) {
        return addToMap(actionMap, action);
    }

    public String mapObject(final ObjectAdapter adapter) {
        final ObjectMapping mapping = objectMapping(adapter);
        return addToMap(objectMap, mapping);
    }

    private ObjectMapping objectMapping(final ObjectAdapter adapter) {
        ObjectMapping mapping;
        if (adapter.isTransient()) {
            mapping = new TransientObjectMapping(adapter);
        } else {
            mapping = new PersistentObjectMapping(adapter);
        }
        return mapping;
    }

    public String mapCollection(final ObjectAdapter collection) {
        final CollectionMapping map = new CollectionMapping(this, collection);
        return addToMap(collectionMap, map);
    }

    public void endTask(final Task task) {
        for (int i = crumbs.size() - 1; i >= 0; i--) {
            final Object crumb = crumbs.get(i);
            if (crumb instanceof TaskCrumb) {
                final TaskCrumb taskCrumb = (TaskCrumb) crumb;
                if (taskCrumb.getTask() == task) {
                    crumbs.remove(taskCrumb);
                    return;
                }
            }
        }
        throw new IsisException("No crumb found for " + task);
    }

    public Crumb[] getCrumbs() {
        final int size = crumbs.size();
        final Crumb[] taskList = new Crumb[size];
        for (int i = 0; i < crumbs.size(); i++) {
            taskList[i] = crumbs.get(i);
        }
        return taskList;
    }

    public boolean[] isLinked() {
        final int size = crumbs.size();
        final boolean[] isLinked = new boolean[size];
        for (int i = size - 1; i >= 0; i--) {
            final boolean isTask = crumbs.elementAt(i) instanceof TaskCrumb;
            isLinked[i] = i != size - 1;
            if (isTask) {
                break;
            }
        }
        return isLinked;
    }

    public List<String> getMessages() {
        return messages;
    }

    public String getMessage(final int i) {
        return messages.get(i);
    }

    public List<String> getWarnings() {
        return warnings;
    }

    public String getWarning(final int i) {
        return warnings.get(i);
    }

    public void setMessagesAndWarnings(final List<String> messages, final List<String> warnings) {
        this.messages.clear();
        this.messages.addAll(messages);
        this.warnings.clear();
        this.warnings.addAll(warnings);
    }

    public void clearMessagesAndWarnings() {
        messages.clear();
        warnings.clear();
    }

    private boolean isTask() {
        final int index = crumbs.size() - 1;
        return index >= 0 && crumbs.get(index) instanceof TaskCrumb;
    }

    public Request changeContext(final int id) {
        while (crumbs.size() - 1 > id) {
            crumbs.pop();
        }
        final Crumb c = crumbs.lastElement();
        return c.changeContext();
    }

    public void setSession(final AuthenticationSession currentSession) {
        this.session = currentSession;
    }

    public AuthenticationSession getSession() {
        return session;
    }

    public void purge() {
        actionMap.clear();
        clearMessagesAndWarnings();

        final Map newCollectionMap = new HashMap();
        final Map newObjectMap = new HashMap();

        final Iterator<HistoryEntry> elements = history.elements();
        while (elements.hasNext()) {
            final HistoryEntry entry = elements.next();
            if (entry.type == HistoryEntry.OBJECT) {
                final Object item = objectMap.get(entry.id);
                newObjectMap.put(entry.id, item);
                LOG.debug("copied object map " + entry.id + " for " + item);
                ((ObjectMapping) item).updateVersion();
            } else if (entry.type == HistoryEntry.COLLECTION) {
                final CollectionMapping coll = collectionMap.get(entry.id);
                newCollectionMap.put(entry.id, coll);
                LOG.debug("copied collection map for " + coll);
                final Enumeration e1 = coll.elements();
                while (e1.hasMoreElements()) {
                    final String id1 = (String) e1.nextElement();
                    final Object item = objectMap.get(id1);
                    if (item != null) {
                        newObjectMap.put(id1, item);
                        LOG.debug("copied object map " + id1 + " for " + item);
                        ((ObjectMapping) item).updateVersion();
                    }
                }
            }
        }

        collectionMap.clear();
        collectionMap.putAll(newCollectionMap);
        objectMap.clear();
        objectMap.putAll(newObjectMap);
        objectMap.putAll(serviceMap);
    }

    public void restoreAllObjectsToLoader() {
        final Set oidSet = objectMap.entrySet();
        for (final Iterator it = oidSet.iterator(); it.hasNext();) {
            final ObjectMapping mapping = (ObjectMapping) ((Entry) it.next()).getValue();
            mapping.restoreToLoader();
        }
    }

    public void listHistory(final Context context, final Block navigation) {
        history.listObjects(context, navigation);
    }

    public void addObjectToHistory(final String idString) {
        history.addObject(idString);
    }

    public void addCollectionToHistory(final String idString) {
        history.addCollection(idString);
    }

    public void init() {
        final AdapterManager adapterManager = IsisContext.getPersistenceSession().getAdapterManager();
        final List<Object> services = getUserProfile().getPerspective().getServices();
        for (final Object service : services) {
            final ObjectAdapter serviceAdapter = adapterManager.adapterFor(service);
            if (serviceAdapter == null) {
                LOG.warn("unable to find service: " + service + "; skipping");
                continue;
            }
            mapObject(serviceAdapter);
        }
        serviceMap.putAll(objectMap);
    }

    public void updateVersion(final ObjectAdapter adapter) {
        if (adapter.isTransient()) {
            return;
        }

        // TODO refactor this for clarity: removes existing mapping and replaces
        // it with a new one as it
        // contains the new version
        final String id = mapObject(adapter);
        if (id != null) {
            final ObjectMapping mapping = new PersistentObjectMapping(adapter);
            objectMap.put(id, mapping);
        }
    }

    public void processChanges() {
        final List<ObjectAdapter> disposedObjects = IsisContext.getUpdateNotifier().getDisposedObjects();
        for (final ObjectAdapter adapter : disposedObjects) {
            final ObjectMapping mapping = objectMapping(adapter);
            if (objectMap.containsValue(mapping)) {
                final String existingId = findExistingId(objectMap, mapping);
                history.remove(existingId);

                final ArrayList<Crumb> relatedCrumbs = new ArrayList<Crumb>();
                for (final Crumb crumb : getCrumbs()) {
                    /*
                     * if (crumb.isFor(existingId)) { relatedCrumbs.add(crumb);
                     * }
                     */}
                for (final Crumb crumb : relatedCrumbs) {
                    crumbs.remove(crumb);
                }

                for (final CollectionMapping collection : collectionMap.values()) {
                    collection.remove(existingId);
                }
                objectMap.remove(existingId);
            }
        }
    }

    // ////////////////////////////////////////////////////
    // Dependencies (from context)
    // ////////////////////////////////////////////////////

    private static UserProfile getUserProfile() {
        return IsisContext.getUserProfile();
    }

}
TOP

Related Classes of org.apache.isis.viewer.html.context.Context

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.