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

org.efaps.admin.runlevel.RunLevel 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: 7483 $
 * Last Changed:    $Date: 2012-05-11 11:57:38 -0500 (Fri, 11 May 2012) $
 * Last Changed By: $Author: [email protected] $
 */

package org.efaps.admin.runlevel;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.efaps.db.Context;
import org.efaps.db.transaction.ConnectionResource;
import org.efaps.db.wrapper.SQLPart;
import org.efaps.db.wrapper.SQLSelect;
import org.efaps.util.EFapsException;
import org.efaps.util.cache.AbstractCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This Class is the run level for eFaps. It provides the possibility to load
 * only the specified or needed parts into the Cache. It can be defined within
 * the database.
 *
 * @author The eFaps Team
 * @version $Id: RunLevel.java 7483 2012-05-11 16:57:38Z [email protected] $
 */
public final class RunLevel
{
    /**
     * Logger for this class.
     */
    private static final Logger LOG = LoggerFactory.getLogger(RunLevel.class);

    /**
     * Name of SQL table used to test if the run level is already installed in
     * the database.
     *
     * @see #isInitialisable()
     */
    private static final String TABLE_TESTS = "T_RUNLEVEL";

    /**
     * This is the SQL select statement to select a RunLevel from the database.
     *
     * @see #RunLevel(long)
     * @see #RunLevel(String)
     */
    private static final SQLSelect SELECT_RUNLEVEL = new SQLSelect()
                                                            .column(0, "ID")
                                                            .column(0, "PARENT")
                                                            .from("T_RUNLEVEL", 0);

    /**
     * SQL select statement to select a RunLevel from the database.
     *
     * @see #initialize(String)
     */
    private static final SQLSelect SELECT_DEF_PRE = new SQLSelect()
                                                            .column(0, "CLASS")
                                                            .column(0, "METHOD")
                                                            .column(0, "PARAMETER")
                                                            .from("T_RUNLEVELDEF", 0);

    /**
     * Current RunLevel.
     */
    private static RunLevel RUNLEVEL = null;

    /**
     * Mapping of all RunLevels to id.
     */
    private static final Map ALL_RUNLEVELS = new HashMap();

    /**
     * All cache initialize methods for this RunLevel are stored in this instance
     * variable. They are ordered by the priority.
     */
    private final List cacheMethods = new ArrayList();

    /**
     * The id in the eFaps database of this run level.
     */
    private long id = 0;

    /**
     * The parent run level.
     */
    private RunLevel parent;

    /**
     * Name of this RunLevel.
     */
    private String name;

    /**
     * Initializes this run level instance depending on the _name.
     *
     * @param _name   name of the run level
     * @throws EFapsException on error
     */
    private RunLevel(final String _name)
        throws EFapsException
    {
        this.name = _name;
        initialize(RunLevel.SELECT_RUNLEVEL.getCopy().addPart(SQLPart.WHERE).addColumnPart(0, "RUNLEVEL")
                        .addPart(SQLPart.EQUAL).addEscapedValuePart(_name).getSQL());
    }

    /**
     * Initializes this run level instance depending on the _id.
     *
     * @param _id       id of the run level
     * @throws EFapsException on error
     */
    private RunLevel(final long _id)
        throws EFapsException
    {
        initialize(RunLevel.SELECT_RUNLEVEL.getCopy().addPart(SQLPart.WHERE).addColumnPart(0, "ID")
                        .addPart(SQLPart.EQUAL).addValuePart(_id).getSQL());
    }

    /**
     * The static method first removes all values in the caches. Then the cache
     * is initialized automatically depending on the desired RunLevel
     *
     * @param _runLevel   name of run level to initialize
     * @throws EFapsException on error
     */
    public static void init(final String _runLevel)
        throws EFapsException
    {
        RunLevel.ALL_RUNLEVELS.clear();
        RunLevel.RUNLEVEL = new RunLevel(_runLevel);
    }

    /**
     * @return Return the name of the currenct active RunLevel.
     */
    public static String getName4Current()
    {
        return RunLevel.RUNLEVEL == null ? null : RunLevel.RUNLEVEL.name;
    }

    /**
     * Tests, if the SQL table {@link #TABLE_TESTS} exists (= true).
     * This means the run level could be initialized.
     *
     * @return true if a run level could be initialized (and the SQL
     *         table exists in the database); otherwise false
     * @throws EFapsException if the test for the table fails
     * @see #TABLE_TESTS
     */
    public static boolean isInitialisable()
        throws EFapsException
    {
        try {
            return Context.getDbType().existsTable(Context.getThreadContext().getConnection(),
                                                   RunLevel.TABLE_TESTS);
        } catch (final SQLException e) {
            throw new EFapsException(RunLevel.class, "isInitialisable.SQLException", e);
        }
    }

    /**
     * Execute the current RunLevel. (Load all defined Caches).
     *
     * @throws EFapsException on error
     */
    public static void execute()
        throws EFapsException
    {
        RunLevel.RUNLEVEL.executeMethods();
        final List allInitializer = RunLevel.RUNLEVEL.getAllInitializers();
        for (final AbstractCache cache : AbstractCache.getCaches()) {
            final String initiliazer = cache.getInitializer();
            if (!allInitializer.contains(initiliazer)) {
                cache.clear();
            }
        }
    }

    /**
     * Returns the list of all initializers.
     *
     * @return list of all initializers
     */
    private List getAllInitializers()
    {
        final List ret = new ArrayList();
        for (final CacheMethod cacheMethod : this.cacheMethods) {
            ret.add(cacheMethod.className);
        }
        if (this.parent != null) {
            ret.addAll(this.parent.getAllInitializers());
        }
        return ret;
    }

    /**
     * All cache initialize methods stored in {@link #cacheMethods} are called.
     *
     * @see #cacheMethods
     * @throws EFapsException on error
     */
    protected void executeMethods()
        throws EFapsException
    {
        if (this.parent != null) {
            this.parent.executeMethods();
        }
        for (final CacheMethod cacheMethod : this.cacheMethods) {
            cacheMethod.callMethod();
        }
    }

    /**
     * Reads the id and the parent id of this RunLevel. All defined methods for
     * this run level are loaded. If a parent id is defined, the parent is
     * initialized.
     *
     * @param _sql  SQL statement to get the id and parent id for this run
     *              level
     * @see #parent
     * @see #cacheMethods
     * @throws EFapsException on error
     */
    protected void initialize(final String _sql)
        throws EFapsException
    {
        ConnectionResource con = null;
        try {
            con = Context.getThreadContext().getConnectionResource();
            Statement stmt = null;
            long parentId = 0;

            try {
                stmt = con.getConnection().createStatement();
                // read run level itself
                ResultSet rs = stmt.executeQuery(_sql);
                if (rs.next()) {
                    this.id = rs.getLong(1);
                    parentId = rs.getLong(2);
                } else {
                    RunLevel.LOG.error("RunLevel not found");
                }
                rs.close();

                // read all methods for one run level
                rs = stmt.executeQuery(RunLevel.SELECT_DEF_PRE.getCopy()
                                .addPart(SQLPart.WHERE)
                                .addColumnPart(0, "RUNLEVELID")
                                .addPart(SQLPart.EQUAL)
                                .addValuePart(this.id)
                                .addPart(SQLPart.ORDERBY)
                                .addColumnPart(0, "PRIORITY").getSQL());

                /**
                 * Order part of the SQL select statement.
                 */
                //private static final String SQL_DEF_POST  = " order by PRIORITY";

                while (rs.next()) {
                    if (rs.getString(3) != null) {
                        this.cacheMethods.add(new CacheMethod(rs.getString(1).trim(),
                                                              rs.getString(2).trim(),
                                                              rs.getString(3).trim()));
                    } else {
                        this.cacheMethods.add(new CacheMethod(rs.getString(1).trim(),
                                                              rs.getString(2).trim()));
                    }
                }
            } finally {
                if (stmt != null) {
                    stmt.close();
                }
            }

            con.commit();
            RunLevel.ALL_RUNLEVELS.put(this.id, this);
            if (parentId != 0) {
                this.parent = RunLevel.ALL_RUNLEVELS.get(parentId);
                if (this.parent == null) {
                    this.parent = new RunLevel(parentId);
                }
            }
        } catch (final EFapsException e) {
            RunLevel.LOG.error("initialise()", e);
        } catch (final SQLException e) {
            RunLevel.LOG.error("initialise()", e);
        } finally {
            if ((con != null) && con.isOpened()) {
                con.abort();
            }
        }
    }

    /**
     * Cache for the methods, which are defined for the run level. The stored
     * string values can be used to invoke the methods. Therefore the cache is
     * separated in three fields:
     * 
    *
  • CLASSNAME: name of the class as written in a java class
  • *
  • METHODNAME: name of the a static method, it can optional used * with one string parameter
  • *
  • PARAMETER (optional): the string value corresponding * with the method
  • *
*/ public static final class CacheMethod { /** * Name of the class which must be initialized. */ private final String className; /** * Name of the static method used to initialized the cache. */ private final String methodName; /** * Parameter for the static method used to initialized the cache. */ private final String parameter; /** * Constructor for the {@link CacheMethod} in the case that there are only * {@link #className} and {@link #methodName}. * * @param _className name of the class * @param _methodName name of the method * @see #CacheMethod(String,String,String) */ private CacheMethod(final String _className, final String _methodName) { this(_className, _methodName, null); } /** * Constructor for the cache with {@link #className}, * {@link #methodName} and {@link #parameter}. * * @param _className Name of the Class * @param _methodName Name of the Method * @param _parameter Value of the Parameter */ private CacheMethod(final String _className, final String _methodName, final String _parameter) { this.className = _className; this.methodName = _methodName; this.parameter = _parameter; } /** * Calls the static cache initialize method defined by this instance. * * @throws EFapsException on error */ public void callMethod() throws EFapsException { try { final Class cls = Class.forName(this.className); if (this.parameter != null) { final Method m = cls.getMethod(this.methodName, String.class); m.invoke(cls, this.parameter); } else { final Method m = cls.getMethod(this.methodName, new Class[] {}); m.invoke(cls); } } catch (final ClassNotFoundException e) { RunLevel.LOG.error("class '" + this.className + "' not found", e); throw new EFapsException(getClass(), "callMethod.ClassNotFoundException", null, e, this.className); } catch (final NoSuchMethodException e) { RunLevel.LOG.error("class '" + this.className + "' does not own method '" + this.methodName + "'", e); throw new EFapsException(getClass(), "callMethod.NoSuchMethodException", null, e, this.className, this.methodName); } catch (final IllegalAccessException e) { RunLevel.LOG.error("could not access class '" + this.className + "' method '" + this.methodName + "'", e); throw new EFapsException(getClass(), "callMethod.IllegalAccessException", null, e, this.className, this.methodName); } catch (final InvocationTargetException e) { RunLevel.LOG.error("could not execute class '" + this.className + "' method '" + this.methodName + "' because an exception was thrown.", e); if (e.getCause() != null) { if (e.getCause() instanceof EFapsException) { throw (EFapsException) e.getCause(); } else { throw new EFapsException(getClass(), "callMethod.InvocationTargetException", null, e.getCause(), this.className, this.methodName); } } else { throw new EFapsException(getClass(), "callMethod.InvocationTargetException", null, e, this.className, this.methodName); } } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy