net.xy.jcms.controller.configurations.Configuration.java Source code

Java tutorial

Introduction

Here is the source code for net.xy.jcms.controller.configurations.Configuration.java

Source

/**
 * This file is part of XY.JCms, Copyright 2010 (C) Xyan Kruse, Xyan@gmx.net, Xyan.kilu.de
 * 
 * XY.JCms is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 * 
 * XY.JCms is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with XY.JCms. If not, see
 * <http://www.gnu.org/licenses/>.
 */
package net.xy.jcms.controller.configurations;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.EnumSet;
import java.util.HashMap;

import net.xy.jcms.shared.DebugUtils;
import net.xy.jcms.shared.JCmsHelper;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

/**
 * All configuration not dedicated to the clients request instead supplied or
 * retrieved by other sources to name a few options, db, uiconfig, messages,
 * content, cms.
 * 
 * @author Xyan
 * 
 */
public abstract class Configuration<CONFIGURATION_OBJECT> {

    /**
     * logger
     */
    static final Logger LOG = Logger.getLogger(Configuration.class);

    /**
     * typesation of config this triggers the appropriated parser and config
     * readers
     * 
     * @author Xyan
     * 
     */
    public static enum ConfigurationType {
        /**
         * the repository contains all to the view obmitted content would empty
         * initialized and is the result of the proccesing the
         * ControllerConfiguration
         */
        ContentRepository,
        /**
         * this configuration gots refilled in the components tree configuration
         * objects it will not be used but can be altered by controllers.
         */
        UIConfiguration,
        /**
         * this configuration gots refilled into configuration objects for the
         * including fragments components building the componenttree.
         */
        TemplateConfiguration,
        /**
         * the message configuration gots refilled into the component
         * configuration objects and also will be used by controllers
         */
        MessageConfiguration,
        /**
         * configuration only used in the controllers, would not be taken into
         * account when hashing the datamodel
         */
        ControllerConfiguration,
        /**
         * usually an renderfactory which provides the renderer for the
         * component configuration. will be refilled to each component.
         */
        RenderKitConfiguration,
        /**
         * just an triger to obmit usecase parameters to the handler
         */
        Parameters;

        /**
         * these configuration are obmittedt to the view and therefore will be
         * hashed to determine view changes.
         */
        public static final EnumSet<ConfigurationType> VIEWAPPLICABLE = EnumSet.of(ContentRepository,
                UIConfiguration, MessageConfiguration, RenderKitConfiguration, TemplateConfiguration);

        /**
         * all configuration will be additionally obmitted to the controllers
         */
        public static final EnumSet<ConfigurationType> CONTROLLERAPPLICABLE = EnumSet.of(ControllerConfiguration);
        static {
            CONTROLLERAPPLICABLE.addAll(VIEWAPPLICABLE);
        }
    }

    /**
     * what kind of configuration should only abstract view no jj models
     */
    private final ConfigurationType configurationType;

    /**
     * value of the configuration can be anything from an string to an dto or
     * complete db dump.
     */
    private final CONFIGURATION_OBJECT configurationValue;

    /**
     * constructor with obmited config object
     * 
     * @param configurationType
     * @param configurationValue
     */
    public Configuration(final ConfigurationType configurationType, final CONFIGURATION_OBJECT configurationValue) {
        if (configurationType == null) {
            throw new IllegalArgumentException("Configuration must have an proper type set");
        }
        this.configurationType = configurationType;
        this.configurationValue = configurationValue;
    }

    /**
     * constructor with an additional source origin. note configuration will be
     * parsed and retrieved before object initiliazation.
     * 
     * @param configurationType
     * @param configurationValue
     * @param configurationSource
     */
    public Configuration(final ConfigurationType configurationType, final CONFIGURATION_OBJECT configurationValue,
            final String configurationSource) {
        if (configurationType == null) {
            throw new IllegalArgumentException("Configuration must have an proper type set");
        }
        this.configurationType = configurationType;
        this.configurationValue = configurationValue;
    }

    /**
     * returns configurationType
     * 
     * @return value
     */
    public ConfigurationType getConfigurationType() {
        return configurationType;
    }

    /**
     * return the real configuration holding object
     * 
     * @return value
     */
    protected CONFIGURATION_OBJECT getConfigurationValue() {
        return configurationValue;
    }

    /**
     * implements joining of configurations
     * 
     * @param otherConfig2
     */
    public abstract Configuration<CONFIGURATION_OBJECT> mergeConfiguration(
            final Configuration<CONFIGURATION_OBJECT> otherConfig2);

    /**
     * implements joining of an config and an other config object
     * 
     * @param configObject
     * @return value
     */
    public abstract Configuration<CONFIGURATION_OBJECT> mergeConfiguration(final CONFIGURATION_OBJECT configObject);

    /**
     * public method for merging two configs of the same type
     * 
     * @param otherConfig1
     * @param otherConfig2
     * @return an new config of 1 and 2
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static Configuration mergeConfiguration(final Configuration otherConfig1,
            final Configuration otherConfig2) {
        return otherConfig1.mergeConfiguration(otherConfig2);
    }

    /**
     * for hashing each view configuration has to implement there own hashing
     * alghorhytm which returns the same hash for equal configuration based on
     * its own sight.
     * 
     * @return value
     */
    @Override
    public abstract int hashCode();

    /**
     * each configuration musst also implent equals to figure out if two
     * configurations express the same.
     */
    @Override
    public abstract boolean equals(Object object);

    @Override
    public String toString() {
        return "type=" + getConfigurationType();
    }

    /**
     * initialises an configuration with an string. only for specific types
     * available.
     * 
     * @param type
     * @param in
     * @param loader
     *            needed to load configuration components like typeconverters,
     *            renderer and fragments
     * @param mount
     *            specifies the mountpoint on which relative component pathes should be resolved
     * @return value
     */
    public static Configuration<?> initByString(final ConfigurationType type, final String in,
            final ClassLoader loader, String mount) {
        if (StringUtils.isBlank(mount)) {
            mount = StringUtils.EMPTY;
        }
        switch (type) {
        case TemplateConfiguration:
            return TemplateConfiguration.initByString(in, loader, mount);
        case UIConfiguration:
            return UIConfiguration.initByString(in, loader, mount);
        case MessageConfiguration:
            return MessageConfiguration.initByString(in, mount);
        case RenderKitConfiguration:
            return RenderKitConfiguration.initByString(in, loader, mount);
        case ControllerConfiguration:
            return ControllerConfiguration.initByString(in);
        // TODO [LOW] relative component path supoort in fragments including controller configs
        case ContentRepository:
            return new ContentRepository(new HashMap<String, Object>());
        default:
            throw new UnsupportedOperationException(
                    "Configurationtype is not implemented to be initialized by stream. "
                            + DebugUtils.printFields(type));
        }
    }

    /**
     * just an delegeate without mount param
     * 
     * @see most param method
     */
    public static Configuration<?> initByString(final ConfigurationType type, final String in,
            final ClassLoader loader) {
        return initByString(type, in, loader, null);
    }

    /**
     * initializes an configuration with an input stream resource. only for
     * certain configuration available.
     * 
     * @param type
     * @param stream
     * @param mount
     *            specifies the mountpoint on which relative component pathes should be resolved
     * @return value
     */
    public static Configuration<?> initByStream(final ConfigurationType type, final InputStream stream,
            final ClassLoader loader, final String mount) {
        final StringBuilder writer = new StringBuilder();
        BufferedReader reader;
        try {
            reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"), 1024);
        } catch (final UnsupportedEncodingException e) {
            throw new UnsupportedOperationException(
                    "Mendatory charachterset UTF-8 is not supported on this system.", e);
        }
        final char[] buffer = new char[1024];
        try {
            int n;
            while ((n = reader.read(buffer)) != -1) {
                writer.append(buffer, 0, n);
            }
        } catch (final IOException e) {
        }
        return initByString(type, writer.toString(), loader, mount);
    }

    /**
     * just an delegeate without mount param
     * 
     * @see most param method
     */
    public static Configuration<?> initByStream(final ConfigurationType type, final InputStream stream,
            final ClassLoader loader) {
        return initByStream(type, stream, loader, null);
    }

    /**
     * inits the config from an included resource
     * 
     * @param type
     * @param include
     *            pseudo uri specifieing an resource e.g. class://lang.java.test
     * @param mount
     *            specifies the mountpoint on which relative component pathes should be resolved
     * @return value
     */
    public static Configuration<?> initConfigurationByInclude(final ConfigurationType type, final String include,
            final ClassLoader loader, final String mount) {
        if (include.startsWith("class://")) {
            final String classpath = include.replaceFirst("^class://", "");
            InputStream st;
            try {
                st = JCmsHelper.loadResource(classpath, loader);
                if (st != null) {
                    return Configuration.initByStream(type, st, loader, mount);
                }
            } catch (final IOException e) {
            }
        }
        throw new IllegalArgumentException("Include reffers to an invalid location!");
    }

    /**
     * just an delegeate without mount param
     * 
     * @see most param method
     */
    public static Configuration<?> initConfigurationByInclude(final ConfigurationType type, final String include,
            final ClassLoader loader) {
        return initConfigurationByInclude(type, include, loader, null);
    }

    /**
     * by default caching is enabled but it can for optimization purpose
     * deactivated
     */
    protected boolean enableCache = true;

    /**
     * @return if this config is mutable
     */
    public boolean disableCache() {
        return true;
    }
}