All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.efaps.update.Install Maven / Gradle / Ivy

/*
 * Copyright 2003 - 2012 The eFaps Team
 *
 * 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.
 *
 * Revision:        $Rev: 7908 $
 * Last Changed:    $Date: 2012-08-13 16:39:28 -0500 (Mon, 13 Aug 2012) $
 * Last Changed By: $Author: [email protected] $
 */

package org.efaps.update;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.jexl.JexlContext;
import org.apache.commons.jexl.JexlHelper;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.efaps.ci.CIAdminCommon;
import org.efaps.db.Context;
import org.efaps.db.MultiPrintQuery;
import org.efaps.db.QueryBuilder;
import org.efaps.update.schema.datamodel.SQLTableUpdate;
import org.efaps.update.util.InstallationException;
import org.efaps.util.EFapsException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;

/**
 * TODO description.
 *
 * @author The eFaps Team
 * @version $Id: Install.java 7908 2012-08-13 21:39:28Z [email protected] $
 */
public class Install
{
    /**
     * Logging instance used to give logging information of this class.
     */
    private static final Logger LOG = LoggerFactory.getLogger(SQLTableUpdate.class);

    /**
     * All defined file urls which are updated.
     *
     * @see #addFile(URL, String)
     */
    private final List files = new ArrayList();

    /**
     * Flag to store that the cache is initialised.
     *
     * @see #initialise
     * @see #addURL
     */
    private boolean initialised = false;

    /**
     * Cache with all update instances (loaded from the list of {@link #urls}).
     *
     * @see #initialise
     * @see #install
     */
    private final Map, List> cache
        = new HashMap, List>();

    /**
     * Installs the XML update scripts of the schema definitions for this
     * version defined in {@link #number}. The install itself is done for given
     * version normally in one big transaction. If the database does not support
     * to big transactions (method
     * {@link org.efaps.db.databases.AbstractDatabase#supportsBigTransactions()},
     * each modification of one update is committed within small single
     * transactions.
     *
     * @param _number           number to install
     * @param _latestNumber     latest version number to install (e..g. defined
     *                          in the version.xml file)
     * @param _profiles         profiles to be applied
     * @param _ignoredSteps     set of ignored life cycle steps which are not
     *                          executed
     * @throws InstallationException on error
     * @see org.efaps.db.databases.AbstractDatabase#supportsBigTransactions()
     */
    @SuppressWarnings("unchecked")
    public void install(final Long _number,
                        final Long _latestNumber,
                        final Set _profiles,
                        final Set _ignoredSteps)
        throws InstallationException
    {
        final boolean bigTrans = Context.getDbType().supportsBigTransactions();
        final String user;
        try  {
            user = (Context.getThreadContext().getPerson() != null)
                   ? Context.getThreadContext().getPerson().getName()
                   : null;
        } catch (final EFapsException e)  {
            throw new InstallationException("No context in this thread defined!", e);
        }

        // initialize cache
        initialise();

        // initialize JexlContext (used to evaluate version)
        final JexlContext jexlContext = JexlHelper.createContext();
        if (_number != null) {
            jexlContext.getVars().put("version", _number);
        }
        if (_latestNumber != null) {
            jexlContext.getVars().put("latest", _latestNumber);
        }

        // loop through all life cycle steps
        for (final UpdateLifecycle step : getUpdateLifecycles())  {
            if (!_ignoredSteps.contains(step)) {
                if (Install.LOG.isInfoEnabled())  {
                    Install.LOG.info("..Running Lifecycle step " + step);
                }
                for (final Map.Entry, List> entry : this.cache.entrySet()) {
                    for (final IUpdate update : entry.getValue()) {
                        update.updateInDB(jexlContext, step, _profiles);
                        if (!bigTrans) {
                            try {
                                Context.commit();
                            } catch (final EFapsException e) {
                                throw new InstallationException("Transaction commit failed", e);
                            }
                            try {
                                Context.begin(user);
                            } catch (final EFapsException e) {
                                throw new InstallationException("Transaction start failed", e);
                            }
                        }
                    }
                }
            } else if (Install.LOG.isInfoEnabled())  {
                Install.LOG.info("..Skipped Lifecycle step " + step);
            }
        }
    }

    /**
     * Method to get all UpdateLifecycle in an ordered List.
     * @return ordered List of all UpdateLifecycle
     */
    private List getUpdateLifecycles()
    {
        final List ret = new ArrayList();
        for (final UpdateLifecycle cycle : UpdateLifecycle.values()) {
            ret.add(cycle);
        }
        Collections.sort(ret, new Comparator() {

            public int compare(final UpdateLifecycle _cycle1,
                               final UpdateLifecycle _cycle2)
            {
                return _cycle1.getOrder().compareTo(_cycle2.getOrder());
            }
        });

        return ret;
    }

    /**
     * All installation files are updated. For each file, the installation and
     * latest version is evaluated depending from all installed version and the
     * defined application in the XML update file. The installation version is
     * the same as the latest version of the application.
     *
     * @throws InstallationException if update failed
     */
    @SuppressWarnings("unchecked")
    public void updateLatest(final Set _profiles)
        throws InstallationException
    {
        final boolean bigTrans = Context.getDbType().supportsBigTransactions();
        final String user;
        try  {
            user = (Context.getThreadContext().getPerson() != null)
                   ? Context.getThreadContext().getPerson().getName()
                   : null;
        } catch (final EFapsException e)  {
            throw new InstallationException("No context in this thread defined!", e);
        }

        // initialize cache
        initialise();

        // get for all applications the latest version
        final Map versions = getLatestVersions();

        // loop through all life cycle steps
        for (final UpdateLifecycle step : getUpdateLifecycles()) {
            if (Install.LOG.isInfoEnabled()) {
                Install.LOG.info("..Running Lifecycle step " + step);
            }
            for (final Map.Entry, List> entry
                            : this.cache.entrySet()) {
                for (final IUpdate update : entry.getValue()) {
                    final Integer latestVersion = versions.get(update.getFileApplication());
                    // initialize JexlContext (used to evaluate version)
                    final JexlContext jexlContext = JexlHelper.createContext();
                    if (latestVersion != null) {
                        jexlContext.getVars().put("version", latestVersion);
                        jexlContext.getVars().put("latest", latestVersion);
                    }
                    // and create
                    update.updateInDB(jexlContext, step, _profiles);
                    if (!bigTrans) {
                        if (!bigTrans) {
                            try {
                                Context.commit();
                            } catch (final EFapsException e) {
                                throw new InstallationException("Transaction commit failed", e);
                            }
                            try {
                                Context.begin(user);
                            } catch (final EFapsException e) {
                                throw new InstallationException("Transaction start failed", e);
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * Load the already installed versions for this application from eFaps. The
     * method must be called within a Context begin and commit (it is not done
     * itself in this method!
     * @return Map containing the versions
     * @throws InstallationException on error
     */
    public Map getLatestVersions()
        throws InstallationException
    {
        final Map versions = new HashMap();
        if (CIAdminCommon.Version.getType() != null) {
            try  {
                final QueryBuilder queryBldr = new QueryBuilder(CIAdminCommon.Version);
                final MultiPrintQuery multi = queryBldr.getPrint();
                multi.addAttribute(CIAdminCommon.Version.Name, CIAdminCommon.Version.Revision);
                multi.executeWithoutAccessCheck();
                while (multi.next()) {
                    final String name = multi.getAttribute(CIAdminCommon.Version.Name);
                    final Integer revision = multi.getAttribute(CIAdminCommon.Version.Revision);
                    if (!versions.containsKey(name) || (versions.get(name) < revision)) {
                        versions.put(name, revision);
                    }
                }
            } catch (final EFapsException e)  {
                throw new InstallationException("Latest version could not be found", e);
            }
        }
        return versions;
    }

    /**
     * Reads all XML update files and parses them.
     *
     * @see #initialised
     * @throws InstallationException on error
     */
    protected void initialise()
        throws InstallationException
    {

        if (!this.initialised) {
            this.initialised = true;
            this.cache.clear();

            for (final FileType fileType : FileType.values()) {

                if (fileType == FileType.XML) {
                    for (final InstallFile file : this.files) {
                        if (file.getType() == fileType) {
                            final SaxHandler handler = new SaxHandler();
                            try {
                                final IUpdate elem = handler.parse(file.getUrl());
                                List list = this.cache.get(elem.getClass());
                                if (list == null) {
                                    list = new ArrayList();
                                    this.cache.put(elem.getClass(), list);
                                }
                                list.add(handler.getUpdate());
                            } catch (final SAXException e) {
                                throw new InstallationException("initialise()", e);
                            } catch (final IOException e) {
                                throw new InstallationException("initialise()", e);
                            }
                        }
                    }
                } else {
                    for (final Class updateClass : fileType.getClazzes()) {

                        final List list = new ArrayList();
                        this.cache.put(updateClass, list);

                        Method method = null;
                        try {
                            method = updateClass.getMethod("readFile", URL.class);
                        } catch (final SecurityException e) {
                            throw new InstallationException("initialise()", e);
                        } catch (final NoSuchMethodException e) {
                            throw new InstallationException("initialise()", e);
                        }
                        for (final InstallFile file : this.files) {
                            if (file.getType() == fileType) {
                                Object obj = null;
                                try {
                                    obj = method.invoke(null, file.getUrl());
                                } catch (final IllegalArgumentException e) {
                                    throw new InstallationException("initialise()", e);
                                } catch (final IllegalAccessException e) {
                                    throw new InstallationException("initialise()", e);
                                } catch (final InvocationTargetException e) {
                                    throw new InstallationException("initialise()", e);
                                }
                                if (obj != null) {
                                    list.add((AbstractUpdate) obj);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * Appends a new file defined through an URL and the string representation
     * of the file type.
     *
     * @param _url URL of the file to append
     * @param _type type of the file
     * @see #files
     * @see #initialised
     * @see #addFile(URL, FileType) method called to add the URL after convert
     *      the string representation of the type to a file type instance
     */
    public void addFile(final URL _url,
                        final String _type)
    {
        addFile(_url, FileType.getFileTypeByType(_type));
    }

    /**
     * Appends a new file defined through an URL. The initialized flag
     * {@link #initialized} is automatically reseted.
     *
     * @param _url URL of the file to add
     * @param _fileType file type of the file to add
     */
    public void addFile(final URL _url,
                        final FileType _fileType)
    {
        this.files.add(new InstallFile(_url, _fileType));
        this.initialised = false;
    }

    /**
     * This is the getter method for the instance variable {@link #files}.
     *
     * @return value of instance variable {@link #files}
     */
    public List getFiles()
    {
        return this.files;
    }

    /**
     * Returns a string representation with values of all instance variables.
     *
     * @return string representation of this Application
     */
    @Override
    public String toString()
    {
        return new ToStringBuilder(this)
            .append("urls", this.files)
            .toString();
    }

    /**
     * Class is used as a container for one file that must be installed.
     */
    public static class InstallFile
    {
        /**
         * URL to the file.
         */
        private final URL url;

        /**
         * Type of the file.
         */
        private final FileType type;

        /**
         * @param _url      Url to the file
         * @param _type     Type of the file.
         */
        public InstallFile(final URL _url,
                           final FileType _type)
        {
            this.url = _url;
            this.type = _type;
        }

        /**
         * This is the getter method for the instance variable {@link #url}.
         *
         * @return value of instance variable {@link #url}
         */
        public URL getUrl()
        {
            return this.url;
        }

        /**
         * This is the getter method for the instance variable {@link #type}.
         *
         * @return value of instance variable {@link #type}
         */
        public FileType getType()
        {
            return this.type;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy