Package org.brixcms.web.model

Source Code of org.brixcms.web.model.ModelBuffer$Model

/**
* 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.brixcms.web.model;

import org.apache.wicket.model.IDetachable;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.PropertyModel;
import org.brixcms.BrixNodeModel;
import org.brixcms.jcr.wrapper.BrixNode;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* Proxy a BrixNode model object, exposing lightweight transactional semantics through the {@link
* org.brixcms.web.model.ModelBuffer.Model#apply} method. Properties of a target model are exposed as models themselves
* and maintain status regarding whether changes have been made. When the apply method is called, the changes in the
* cached models are iterated and flushed.
* <p/>
* This is typically used by clients that wish to present a cancelable user interface, without maintaining the original
* state of target model object. If the user cancels the operation, the buffer is deallocated without ever applying the
* changes to the target.
* <p/>
* After creating a ModelBuffer, use {@link ModelBuffer#forProperty(java.lang.String)} and {@link
* ModelBuffer#forNodeProperty(java.lang.String)} to create and return these cached model objects. These can be provided
* to user interface objects.
* <p/>
* {@link org.brixcms.plugin.site.page.admin.EditTab#EditTab(java.lang.String, org.apache.wicket.model.IModel<
* org.brixcms.jcr.wrapper.BrixNode>)} provides a solid use case of this class.
*/
public class ModelBuffer implements IModel<Object> {
    private Object target;

    private Map<String, IModel> propertyMap;

    private List<Model> models = null;

    public ModelBuffer() {

    }

    /**
     * Constructor requiring a BrixNode to proxy.
     *
     * @param target
     */
    public ModelBuffer(Object target) {
        this.target = target;
    }



    public void detach() {
        if (target != null && target instanceof IModel) {
            ((IModel<?>) target).detach();
        }
    }

    public Object getObject() {
        return target;
    }

    public void setObject(Object object) {
        target = object;
    }

    public void apply() {
        if (models != null) {
            for (Model model : models) {
                model.apply();
            }
        }
    }

    /**
     * Buffer a node property for the target object.
     *
     * @param propertyName The JCR key name of the underlying property
     * @return model A model that buffers the requested property
     */
    public <T> IModel<T> forNodeProperty(String propertyName) {
        return forProperty(propertyName, true);
    }

    /**
     * Backing method for public forProperty API calls. Property buffers are cached by name, returning an existing buffer
     * if it was previously created.
     *
     * @param propertyName The JCR key name of the underlying property
     * @param isNode       Selector for string type or JcrNode type
     * @return model A model that buffers the requested property
     */
    @SuppressWarnings("unchecked")
    protected <T> IModel<T> forProperty(String propertyName, boolean isNode) {
        if (propertyMap != null && propertyMap.containsKey(propertyName)) {
            return propertyMap.get(propertyName);
        }
        IModel model = forModel(new PropertyModel(this, propertyName), isNode);
        if (propertyMap == null) {
            propertyMap = new HashMap<String, IModel>();
        }
        propertyMap.put(propertyName, model);
        return model;
    }

    /**
     * Create a proxy for a node property. In contrast to {@link org.brixcms.web.model.ModelBuffer#forProperty}, this
     * method always creates the buffered model.
     *
     * @param delegate Accessor to the underlying targetObject, typically a PropertyModel
     * @param isNode   if the datatype is a JcrNode
     * @return
     */
    public IModel forModel(IModel delegate, boolean isNode) {
        if (models == null) {
            models = new ArrayList<Model>();
        }
        Model model;
        if (!isNode)
            model = new Model(delegate);
        else
            model = new NodeModel(delegate);

        models.add(model);
        return model;
    }

    /**
     * Buffer a string property for the target object.
     *
     * @param propertyName The JCR key name of the underlying property
     * @return model A model that buffers the requested property
     */
    public <T> IModel<T> forProperty(String propertyName) {
        return forProperty(propertyName, false);
    }

    /**
     * Internal storage type for non-JcrNode properties
     */
    private static class Model implements IModel {
        private final IModel delegate;
        private Object value;
        private boolean valueSet = false;

        public Model(IModel delegate) {
            this.delegate = delegate;
        }

        public Object getObject() {
            if (valueSet) {
                return value;
            } else {
                return delegate.getObject();
            }
        }

        public void setObject(Object object) {
            valueSet = true;
            value = object;
        }

        public void detach() {
            delegate.detach();
            if (value instanceof IDetachable) {
                ((IDetachable) value).detach();
            }
        }

        protected void apply(IModel delegate, Object value) {
            delegate.setObject(value);
        }

        public void apply() {
            if (valueSet) {
                apply(delegate, value);
                valueSet = false;
            }
        }
    }

    /**
     * Internal storage type for JcrNode properties
     */
    private static class NodeModel extends Model {
        public NodeModel(IModel delegate) {
            super(delegate);
        }

        @Override
        public Object getObject() {
            Object value = super.getObject();
            if (value instanceof IModel) {
                return ((IModel) value).getObject();
            } else {
                return value;
            }
        }

        @Override
        public void setObject(Object object) {
            if (object instanceof BrixNode) {
                super.setObject(new BrixNodeModel((BrixNode) object));
            } else {
                super.setObject(object);
            }
        }

        @Override
        protected void apply(IModel delegate, Object value) {
            if (value instanceof IModel) {
                value = ((IModel) value).getObject();
            }
            super.apply(delegate, value);
        }
    }
}
TOP

Related Classes of org.brixcms.web.model.ModelBuffer$Model

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.