org.efaps.db.Context.java Source code

Java tutorial

Introduction

Here is the source code for org.efaps.db.Context.java

Source

/*
 * Copyright 2003 - 2016 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.
 *
 */

package org.efaps.db;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;

import org.apache.commons.lang.RandomStringUtils;
import org.efaps.admin.user.Company;
import org.efaps.admin.user.Person;
import org.efaps.admin.user.UserAttributesSet;
import org.efaps.admin.user.UserAttributesSet.UserAttributesDefinition;
import org.efaps.db.databases.AbstractDatabase;
import org.efaps.db.databases.DataBaseFactory;
import org.efaps.db.store.Resource;
import org.efaps.db.store.Store;
import org.efaps.db.transaction.ConnectionResource;
import org.efaps.init.INamingBinds;
import org.efaps.init.IeFapsProperties;
import org.efaps.init.StartupException;
import org.efaps.util.EFapsException;
import org.efaps.util.cache.CacheReloadException;
import org.joda.time.Chronology;
import org.joda.time.DateTimeZone;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author The eFaps Team
 */
public final class Context implements INamingBinds {

    /**
     * Key used to access the current company from the userattributes.
     */
    public static final String CURRENTCOMPANY = Context.class.getName() + ".CurrentCompany";

    /**
     * Logging instance used in this class.
     */
    private static final Logger LOG = LoggerFactory.getLogger(Context.class);

    /**
     * Static variable storing the database type.
     */
    private static AbstractDatabase<?> DBTYPE;

    /**
     * SQL data source to the database.
     */
    private static DataSource DATASOURCE;

    /**
     * Stores the transaction manager.
     *
     * @see #setTransactionManager
     */
    private static TransactionManager TRANSMANAG;

    /**
     * STore the timeout for the transaction manager.
     */
    private static int TRANSMANAGTIMEOUT = 0;

    static {
        try {
            final InitialContext initCtx = new InitialContext();
            javax.naming.Context envCtx = null;
            try {
                envCtx = (javax.naming.Context) initCtx.lookup("java:/comp/env");
            } catch (final NamingException e) {
                Context.LOG.info("Expected NamingException during evaluation for Context, No action required");
            }
            // for a build the context might be different, try this before surrender
            if (envCtx == null) {
                envCtx = (javax.naming.Context) initCtx.lookup("java:comp/env");
            }

            Context.DATASOURCE = (DataSource) envCtx.lookup(INamingBinds.RESOURCE_DATASOURCE);
            try {
                final AbstractDatabase<?> dbType = (AbstractDatabase<?>) envCtx
                        .lookup(INamingBinds.RESOURCE_DBTYPE);
                Context.DBTYPE = dbType;
            } catch (final NamingException e) {
                Context.LOG.info("Expected NamingException during evaluation for Context, No action required");
                Context.DBTYPE = DataBaseFactory.getDatabase(Context.DATASOURCE.getConnection());
            }

            Context.TRANSMANAG = (TransactionManager) envCtx.lookup(INamingBinds.RESOURCE_TRANSMANAG);

            try {
                Context.TRANSMANAGTIMEOUT = 0;
                final Map<?, ?> props = (Map<?, ?>) envCtx.lookup(INamingBinds.RESOURCE_CONFIGPROPERTIES);
                if (props != null) {
                    final String transactionTimeoutString = (String) props.get(IeFapsProperties.TRANSACTIONTIMEOUT);
                    if (transactionTimeoutString != null) {
                        Context.TRANSMANAGTIMEOUT = Integer.parseInt(transactionTimeoutString);
                    }
                }
            } catch (final NamingException e) {
                // this is actual no error, so nothing is presented
                Context.TRANSMANAGTIMEOUT = 0;
            }
        } catch (final NamingException e) {
            Context.LOG.error("NamingException", e);
            throw new Error(e);
        } catch (final SQLException e) {
            Context.LOG.error("SQLException", e);
            throw new Error(e);
        }
    }

    /**
     * Each thread has his own context object. The value is automatically
     * assigned from the filter class. This allows to have a different Context
     * for every Users which is connect to the WebApp Server. For the case that
     * a thread creates a child threat the context is inherited to this new
     * thread. This is needed e.g. in JasperReport for SubReports.
     * @see #inherit
     */
    private static ThreadLocal<Context> INHERITTHREADCONTEXT = new InheritableThreadLocal<Context>();

    /**
     * Each thread has his own context object. The value is automatically
     * assigned from the filter class. This allows to have a different Context
     * for every Users which is connect to the WebApp Server. For the case that
     * a thread creates a child threat a different context is created this is
     * needed e.g. for background process form quartz.
     */
    private static ThreadLocal<Context> THREADCONTEXT = new ThreadLocal<Context>();

    /**
     * The instance variable stores all open instances of {@link Resource}.
     *
     * @see #getStoreResource(Instance)
     * @see #getStoreResource(Type,long)
     */
    private final Set<Resource> storeStore = new HashSet<Resource>();

    /**
     * Stores all created connection resources.
     */
    private final Set<ConnectionResource> connectionStore = new HashSet<ConnectionResource>();

    /**
     * Stack used to store returned connections for reuse.
     */
    private final Stack<ConnectionResource> connectionStack = new Stack<ConnectionResource>();

    /**
     * Transaction for the context.
     */
    private Transaction transaction;

    /**
     * This is the instance variable for the SQL Connection to the database.
     *
     * @see #getConnection
     * @see #setConnection
     */
    private Connection connection = null;

    /**
     * This instance variable represents the user of the context.
     *
     * @see #getPerson
     */
    private Person person = null;

    /**
     * The current active company.
     */
    private Long companyId = null;

    /**
     * The parameters used to open a new thread context are stored in this
     * instance variable (e.g. the request parameters from a http servlet are
     * stored in this variable).
     *
     * @see #getParameters
     */
    private final Map<String, String[]> parameters;

    /**
     * The file parameters used to open a new thread context are stored in this
     * instance variable (e.g. the request parameters from a http servlet or in
     * the shell the parameters from the command shell). The file item
     * represents one file which includes an input stream, the name and the
     * length of the file.
     *
     * @see #getFileParameters
     */
    private final Map<String, FileParameter> fileParameters;

    /**
     * A map to be able to set attributes with a lifetime of a request (e.g.
     * servlet request).
     *
     * @see #containsRequestAttribute
     * @see #getRequestAttribute
     * @see #setRequestAttribute
     */
    private final Map<String, Object> requestAttributes = new HashMap<String, Object>();

    /**
     * A map to be able to set attributes with a lifetime of a session (e.g. as
     * long as the user is logged in).
     *
     * @see #containsSessionAttribute
     * @see #getSessionAttribute
     * @see #setSessionAttribute
     */
    private Map<String, Object> sessionAttributes = new HashMap<String, Object>();

    /**
     * Holds the timezone belonging to the user of this context.
     */
    private DateTimeZone timezone;

    /**
     * Holds the locale belonging to the user of this context.
     */
    private Locale locale;

    /**
     * Holds the chronology belonging to the user of this context.
     */
    private Chronology chronology;

    /**
     * Holds the iso code of the language belonging to the user of this context.
     */
    private String language;

    /**
     * If used in a webapp the context path of the webapp can be stored here, so
     * that it is accessible for e.g. esjps.
     */
    private String path;

    /**
     * Must the ThreadContext be inherit or not.
     */
    private final boolean inherit;

    /**
     * Id of the request (means normally this instance of the context).
     * Used for cacheing during a request.
     */
    private final String requestId;

    /**
     * Private Constructor.
     *
     * @see #begin(String, Locale, Map, Map, Map)
     *
     * @param _transaction Transaction to be used in this context
     * @param _locale Locale to be used in this context
     * @param _sessionAttributes attributes belonging to this session
     * @param _parameters parameters beloonging to this session
     * @param _fileParameters paramters for file up/download
     * @param _inherit              must the context be inherited to child threads
     * @throws EFapsException on error
     */
    private Context(final Transaction _transaction, final Locale _locale,
            final Map<String, Object> _sessionAttributes, final Map<String, String[]> _parameters,
            final Map<String, FileParameter> _fileParameters, final boolean _inherit) throws EFapsException {
        this.inherit = _inherit;
        this.transaction = _transaction;
        this.requestId = RandomStringUtils.randomAlphanumeric(8);
        this.parameters = _parameters == null ? new HashMap<String, String[]>() : _parameters;
        this.fileParameters = _fileParameters == null ? new HashMap<String, FileParameter>() : _fileParameters;
        this.sessionAttributes = _sessionAttributes == null ? new HashMap<String, Object>() : _sessionAttributes;
        this.locale = _locale == null ? Locale.ENGLISH : _locale;
        try {
            setConnection(Context.DATASOURCE.getConnection());
        } catch (final SQLException e) {
            Context.LOG.error("could not get a sql connection", e);
        }
    }

    /**
     * @return ThreadLocal related to this context
     */
    private ThreadLocal<Context> getThreadLocal() {
        final ThreadLocal<Context> ret;
        if (this.inherit) {
            ret = Context.INHERITTHREADCONTEXT;
        } else {
            ret = Context.THREADCONTEXT;
        }
        return ret;
    }

    /**
     * Destructor of class <code>Context</code>.
     */
    @Override
    public void finalize() {
        if (Context.LOG.isDebugEnabled()) {
            Context.LOG.debug("finalize context for " + this.person);
            Context.LOG.debug("connection is " + getConnection());
        }
        if (this.connection != null) {
            try {
                this.connection.close();
            } catch (final SQLException e) {
                Context.LOG.error("could not close a sql connection", e);
            }
        }
    }

    /**
     * The method tests if all resources (JDBC connection and store resources)
     * are closed, that means that the resources are freeed and returned for
     * reuse.
     *
     * @return <i>true</i> if all resources are closed, otherwise <i>false</i>
     *         is returned
     * @see #connectionStore
     * @see #storeStore
     */
    public boolean allConnectionClosed() {
        boolean closed = true;

        for (final ConnectionResource con : this.connectionStore) {
            if (con.isOpened()) {
                closed = false;
                break;
            }
        }
        if (closed) {
            for (final Resource store : this.storeStore) {
                if (store.isOpened()) {
                    closed = false;
                    break;
                }
            }
        }
        return closed;
    }

    /**
     * Close this contexts, meaning this context object is removed as thread
     * context.<br/>
     * If not all connection are closed, all connection are closed.
     *
     */
    public void close() {
        if (Context.LOG.isDebugEnabled()) {
            Context.LOG.debug("close context for " + this.person);
            Context.LOG.debug("connection is " + getConnection());
        }
        QueryCache.cleanByKey(getRequestId());
        if (this.connection != null) {
            try {
                //this.connection.commit();
                this.connection.close();
            } catch (final SQLException e) {
                Context.LOG.error("could not close a sql connection", e);
            }
        }

        setConnection(null);
        if (getThreadLocal().get() != null && getThreadLocal().get() == this) {
            getThreadLocal().set(null);
        }
        // check if all JDBC connection are close...
        for (final ConnectionResource con : this.connectionStore) {
            try {
                if (con.getConnection() != null && !con.getConnection().isClosed()) {
                    con.getConnection().close();
                    Context.LOG.error("connection was not closed!");
                }
            } catch (final SQLException e) {
                Context.LOG.error("QLException is thrown while trying to get close status of "
                        + "connection or while trying to close", e);
            }
        }
    }

    /**
     * Method to abort the transaction.
     *
     * @throws EFapsException if setting of rollback was not successfully
     */
    public void abort() throws EFapsException {
        try {
            this.transaction.setRollbackOnly();
        } catch (final SystemException e) {
            throw new EFapsException(getClass(), "abort.SystemException", e);
        }
    }

    /**
     * Returns a opened connection resource. If a previous close connection
     * resource already exists, this already existing connection resource is
     * returned.
     *
     * @return opened connection resource
     * @throws EFapsException if connection resource cannot be created
     */
    public ConnectionResource getConnectionResource() throws EFapsException {
        ConnectionResource con = null;
        if (this.connectionStack.isEmpty()) {
            try {
                con = new ConnectionResource(Context.DATASOURCE.getConnection());
            } catch (final SQLException e) {
                throw new EFapsException(getClass(), "getConnectionResource.SQLException", e);
            }
            this.connectionStore.add(con);
        } else {
            con = this.connectionStack.pop();
        }
        if (!con.isOpened()) {
            con.open();
        }
        return con;
    }

    /**
     * @param _con ConnectionResource
     */
    public void returnConnectionResource(final ConnectionResource _con) {
        this.connectionStack.push(_con);
    }

    /**
     * Method to get the sore resource.
     *
     * @param _instance Instance to get the StoreResource for
     * @param _event    StorEvent the store is wanted for
     * @throws EFapsException on error
     * @return StoreResource
     * @see #getStoreResource(Type,long)
     */
    public Resource getStoreResource(final Instance _instance, final Resource.StoreEvent _event)
            throws EFapsException {
        Resource storeRsrc = null;
        final Store store = Store.get(_instance.getType().getStoreId());
        storeRsrc = store.getResource(_instance);
        storeRsrc.open(_event);
        this.storeStore.add(storeRsrc);
        return storeRsrc;
    }

    /**
     * If a person is assigned to this context, the id of this person is
     * returned. Otherwise the default person id value is returned. The method
     * guarantees to return value which is valid!<br/>
     * The value could be used e.g. if a a value is inserted into the database
     * and the person id is needed for the creator and / or modifier.
     *
     * @return person id of current person or default person id value
     */
    public long getPersonId() {
        long ret = 1;

        if (this.person != null) {
            ret = this.person.getId();
        }
        return ret;
    }

    /**
     * Method to get a parameter from the context.
     *
     * @param _key Key for the parameter
     * @return String value of the parameter
     */
    public String getParameter(final String _key) {
        String value = null;
        if (this.parameters != null) {
            final String[] values = this.parameters.get(_key);
            if (values != null && values.length > 0) {
                value = values[0];
            }
        }
        return value;
    }

    /**
     * Getter method for instance variable {@link #path}.
     *
     * @return value of instance variable {@link #path}
     */
    public String getPath() {
        return this.path;
    }

    /**
     * Setter method for instance variable {@link #path}.
     *
     * @param _path value for instance variable {@link #path}
     */
    public void setPath(final String _path) {
        this.path = _path;
    }

    /**
     * Getter method for the instance variable {@link #requestId}.
     *
     * @return value of instance variable {@link #requestId}
     */
    public String getRequestId() {
        return this.requestId;
    }

    /**
     * Returns true if request attributes maps one or more keys to the specified
     * object. More formally, returns <i>true</i> if and only if the request
     * attributes contains at least one mapping to a object o such that (o==null
     * ? o==null : o.equals(o)).
     *
     * @param _key key whose presence in the request attributes is to be tested
     * @return <i>true</i> if the request attributes contains a mapping for
     *         given key, otherwise <i>false</i>
     * @see #requestAttributes
     * @see #getRequestAttribute
     * @see #setRequestAttribute
     */
    public boolean containsRequestAttribute(final String _key) {
        return this.requestAttributes.containsKey(_key);
    }

    /**
     * Returns the object to which this request attributes maps the specified
     * key. Returns <code>null</code> if the request attributes contains no
     * mapping for this key. A return value of <code>null</code> does not
     * necessarily indicate that the request attributes contains no mapping for
     * the key; it's also possible that the request attributes explicitly maps
     * the key to null. The {@link #containsRequestAttribute} operation may be
     * used to distinguish these two cases.<br/>
     * More formally, if the request attributes contains a mapping from a key k
     * to a object o such that (key==null ? k==null : key.equals(k)), then this
     * method returns o; otherwise it returns <code>null</code> (there can be at
     * most one such mapping).
     *
     * @param _key key name of the mapped attribute to be returned
     * @return object to which the request attribute contains a mapping for
     *         specified key, or <code>null</code> if not specified in the
     *         request attributes
     * @see #requestAttributes
     * @see #containsRequestAttribute
     * @see #setRequestAttribute
     */
    public Object getRequestAttribute(final String _key) {
        return this.requestAttributes.get(_key);
    }

    /**
     * Associates the specified value with the specified key in the request
     * attributes. If the request attributes previously contained a mapping for
     * this key, the old value is replaced by the specified value.
     *
     * @param _key key name of the attribute to set
     * @param _value _value of the attribute to set
     * @return Object
     * @see #requestAttributes
     * @see #containsRequestAttribute
     * @see #getRequestAttribute
     */
    public Object setRequestAttribute(final String _key, final Object _value) {
        return this.requestAttributes.put(_key, _value);
    }

    /**
     * Returns true if session attributes maps one or more keys to the specified
     * object. More formally, returns <i>true</i> if and only if the session
     * attributes contains at least one mapping to a object o such that (o==null
     * ? o==null : o.equals(o)).
     *
     * @param _key key whose presence in the session attributes is to be tested
     * @return <i>true</i> if the session attributes contains a mapping for
     *         given key, otherwise <i>false</i>
     * @see #sessionAttributes
     * @see #getSessionAttribute
     * @see #setSessionAttribute
     */
    public boolean containsSessionAttribute(final String _key) {
        return this.sessionAttributes.containsKey(_key);
    }

    /**
     * Returns the object to which this session attributes maps the specified
     * key. Returns <code>null</code> if the session attributes contains no
     * mapping for this key. A return value of <code>null</code> does not
     * necessarily indicate that the session attributes contains no mapping for
     * the key; it's also possible that the session attributes explicitly maps
     * the key to null. The {@link #containsSessionAttribute} operation may be
     * used to distinguish these two cases.<br/>
     * More formally, if the session attributes contains a mapping from a key k
     * to a object o such that (key==null ? k==null : key.equals(k)), then this
     * method returns o; otherwise it returns <code>null</code> (there can be at
     * most one such mapping).
     *
     * @param _key key name of the mapped attribute to be returned
     * @return object to which the session attribute contains a mapping for
     *         specified key, or <code>null</code> if not specified in the
     *         session attributes
     * @see #sessionAttributes
     * @see #containsSessionAttribute
     * @see #setSessionAttribute
     */
    public Object getSessionAttribute(final String _key) {
        return this.sessionAttributes.get(_key);
    }

    /**
     * Associates the specified value with the specified key in the session
     * attributes. If the session attributes previously contained a mapping for
     * this key, the old value is replaced by the specified value.
     *
     * @param _key key name of the attribute to set
     * @param _value value of the attribute to set
     * @return Object
     * @see #sessionAttributes
     * @see #containsSessionAttribute
     * @see #getSessionAttribute
     */
    public Object setSessionAttribute(final String _key, final Object _value) {
        return this.sessionAttributes.put(_key, _value);
    }

    /**
     * Remove a attribute form the Session.
     * @param _key key of the session attribute to be removed.
     */
    public void removeSessionAttribute(final String _key) {
        this.sessionAttributes.remove(_key);
    }

    /**
     * This method retrieves a UserAttribute of the Person this Context belongs
     * to. The UserAttributes are stored in the {@link #sessionAttributes} Map,
     * therefore are thought to be valid for one session.
     *
     * @param _key key to Search for
     * @return String with the value
     * @throws EFapsException on error
     */
    public String getUserAttribute(final String _key) throws EFapsException {
        if (containsSessionAttribute(UserAttributesSet.CONTEXTMAPKEY)) {
            return ((UserAttributesSet) getSessionAttribute(UserAttributesSet.CONTEXTMAPKEY)).getString(_key);
        } else {
            throw new EFapsException(Context.class, "getUserAttribute.NoSessionAttribute");
        }
    }

    /**
     * This method determines if UserAttribute of the Person this Context
     * belongs to exists.The UserAttributes are stored in the
     * {@link #sessionAttributes} Map, therefore are thought to be valid for one
     * session.
     *
     * @param _key key to Search for
     * @return true if found, else false
     *
     * @throws EFapsException on error
     */
    public boolean containsUserAttribute(final String _key) throws EFapsException {
        boolean ret = false;
        if (containsSessionAttribute(UserAttributesSet.CONTEXTMAPKEY)) {
            ret = ((UserAttributesSet) getSessionAttribute(UserAttributesSet.CONTEXTMAPKEY)).containsKey(_key);
        } else {
            final UserAttributesSet userAttribute = new UserAttributesSet(getPersonId());
            setSessionAttribute(UserAttributesSet.CONTEXTMAPKEY, userAttribute);
            ret = userAttribute.containsKey(_key);
        }
        return ret;
    }

    /**
     * Set a new UserAttribute for the UserAttribute of the Person this
     * Context.The UserAttributes are stored in the {@link #sessionAttributes}
     * Map, therefore are thought to be valid for one session.
     *
     * @param _key Key of the UserAttribute
     * @param _value Value of the UserAttribute
     * @throws EFapsException on error
     */
    public void setUserAttribute(final String _key, final String _value) throws EFapsException {
        if (containsSessionAttribute(UserAttributesSet.CONTEXTMAPKEY)) {
            ((UserAttributesSet) getSessionAttribute(UserAttributesSet.CONTEXTMAPKEY)).set(_key, _value);
        } else {
            final UserAttributesSet userAttribute = new UserAttributesSet(getPersonId());
            userAttribute.set(_key, _value);
            setSessionAttribute(UserAttributesSet.CONTEXTMAPKEY, userAttribute);
        }
    }

    /**
     * Set a new UserAttribute for the UserAttribute of the Person this
     * Context.The UserAttributes are stored in the {@link #sessionAttributes}
     * Map, therefore are thought to be valid for one session.
     *
     * @param _key Key of the UserAttribute
     * @param _value Value of the UserAttribute
     * @param _definition Definition
     * @throws EFapsException on error
     */
    public void setUserAttribute(final String _key, final String _value, final UserAttributesDefinition _definition)
            throws EFapsException {
        if (containsSessionAttribute(UserAttributesSet.CONTEXTMAPKEY)) {
            ((UserAttributesSet) getSessionAttribute(UserAttributesSet.CONTEXTMAPKEY)).set(_key, _value,
                    _definition);
        } else {
            throw new EFapsException(Context.class, "getUserAttributes.NoSessionAttribute");
        }
    }

    /**
     * Method to get the UserAttributesSet of the user of this context.
     *
     * @return UserAttributesSet
     * @throws EFapsException on error
     */
    public UserAttributesSet getUserAttributes() throws EFapsException {
        if (containsSessionAttribute(UserAttributesSet.CONTEXTMAPKEY)) {
            return (UserAttributesSet) getSessionAttribute(UserAttributesSet.CONTEXTMAPKEY);
        } else {
            throw new EFapsException(Context.class, "getUserAttributes.NoSessionAttribute");
        }
    }

    /**
     * This is the getter method for instance variable {@link #connection}.
     *
     * @return value of instance variable {@link #connection}
     * @see #connection
     * @see #setConnection
     */
    public Connection getConnection() {
        return this.connection;
    }

    /**
     * This is the setter method for instance variable {@link #connection}.
     *
     * @param _connection new value for instance variable {@link #connection}
     * @see #connection
     * @see #getConnection
     */
    private void setConnection(final Connection _connection) {
        this.connection = _connection;
    }

    /**
     * @param _transaction Transaction to set
     */
    private void setTransaction(final Transaction _transaction) {
        this.transaction = _transaction;
    }

    /**
     * This is the getter method for instance variable {@link #transaction}.
     *
     * @return value of instance variable {@link #transaction}
     * @see #transaction
     */
    public Transaction getTransaction() {
        return this.transaction;
    }

    /**
     * This is the getter method for instance variable {@link #person}.
     *
     * @return value of instance variable {@link #person}
     * @see #person
     */
    public Person getPerson() {
        return this.person;
    }

    /**
     * Get the Company currently valid for this context.
     *
     * @return value of instance variable {@link #company}
     * @throws CacheReloadException on error
     */
    public Company getCompany() throws CacheReloadException {
        return this.companyId == null ? null : Company.get(this.companyId);
    }

    /**
     * Set the Company currently valid for this context.
     * @param _company Company to set
     * @throws CacheReloadException on error
     */
    public void setCompany(final Company _company) throws CacheReloadException {
        if (_company == null) {
            this.companyId = null;
        } else {
            this.companyId = _company.getId();
        }
    }

    /**
     * This is the getter method for instance variable {@link #locale}.
     *
     * @return value of instance variable {@link #locale}
     * @see #locale
     */
    public Locale getLocale() {
        return this.locale;
    }

    /**
     * This is the getter method for instance variable {@link #timezone}.
     *
     * @return value of instance variable {@link #timezone}
     * @see #timezone
     */
    public DateTimeZone getTimezone() {
        return this.timezone;
    }

    /**
     * This is the getter method for instance variable {@link #chronology}.
     *
     * @return value of instance variable {@link #chronology}
     * @see #locale
     */
    public Chronology getChronology() {
        return this.chronology;
    }

    /**
     * Getter method for instance variable {@link #language}.
     *
     * @return value of instance variable {@link #language}
     */
    public String getLanguage() {
        return this.language;
    }

    /**
     * Setter method for instance variable {@link #language}.
     *
     * @param _language value for instance variable {@link #language}
     */
    public void setLanguage(final String _language) {
        this.language = _language;
    }

    /**
     * This is the getter method for instance variable {@link #parameters}.
     *
     * @return value of instance variable {@link #parameters}
     * @see #parameters
     */
    public Map<String, String[]> getParameters() {
        return this.parameters;
    }

    /**
     * This is the getter method for instance variable {@link #fileParameters}.
     *
     * @return value of instance variable {@link #fileParameters}
     * @see #fileParameters
     */
    public Map<String, FileParameter> getFileParameters() {
        return this.fileParameters;
    }

    /**
     * Is a Thread active.
     *
     * @return true if either the ThreadContext or the
     *              Inherited ThreadContext is no null
     */
    public static boolean isThreadActive() {
        return Context.INHERITTHREADCONTEXT.get() != null || Context.THREADCONTEXT.get() != null;
    }

    /**
     * The method checks if for the current thread a context object is defined.
     * This found context object is returned.
     *
     * @return defined context object of current thread
     * @throws EFapsException if no context object for current thread is defined
     * @see #INHERITTHREADCONTEXT
     */
    public static Context getThreadContext() throws EFapsException {
        Context context = Context.THREADCONTEXT.get();
        if (context == null) {
            context = Context.INHERITTHREADCONTEXT.get();
        }
        if (context == null) {
            throw new EFapsException(Context.class, "getThreadContext.NoContext4ThreadDefined");
        }
        return context;
    }

    /**
     * Method to get a new Context.
     *
     * @see #begin(String, Locale, Map, Map, Map)
     * @throws EFapsException on error
     * @return new Context
     */
    public static Context begin() throws EFapsException {
        return Context.begin(null);
    }

    /**
     * Method to get a new Context.
     *
     * @see #begin(String, Locale, Map, Map, Map)
     * @param _userName Naem of the user the Context must be created for
     * @throws EFapsException on error
     * @return new Context
     *
     */
    public static Context begin(final String _userName) throws EFapsException {
        return Context.begin(_userName, Inheritance.Inheritable);
    }

    /**
     * Method to get a new Context.
     *
     * @param _userName Naem of the user the Context must be created for
     * @param _inheritance the inheritance
     * @return new Context
     * @throws EFapsException on error
     * @see #begin(String, Locale, Map, Map, Map)
     */
    public static Context begin(final String _userName, final Inheritance _inheritance) throws EFapsException {
        return Context.begin(_userName, null, null, null, null, _inheritance);
    }

    /**
     * For current thread a new context object must be created.
     *
     * @param _userName             name of current user to set
     * @param _locale               locale instance (which language settings has the user)
     * @param _sessionAttributes    attributes for this session
     * @param _parameters           map with parameters for this thread context
     * @param _fileParameters       map with file parameters
     * @param _inheritance the inheritance
     * @return new context of thread
     * @throws EFapsException if a new transaction could not be started or if
     *             current thread context is already set
     * @see #INHERITTHREADCONTEXT
     */
    public static Context begin(final String _userName, final Locale _locale,
            final Map<String, Object> _sessionAttributes, final Map<String, String[]> _parameters,
            final Map<String, FileParameter> _fileParameters, final Inheritance _inheritance)
            throws EFapsException {
        if (Inheritance.Inheritable.equals(_inheritance) && Context.INHERITTHREADCONTEXT.get() != null
                || Inheritance.Local.equals(_inheritance) && Context.THREADCONTEXT.get() != null) {
            throw new EFapsException(Context.class, "begin.Context4ThreadAlreadSet");
        }
        try {
            // the timeout set is reseted on creation of a new Current object in
            // the transaction manager,
            // so if the default must be overwritten it must be set explicitly
            // again
            if (Context.TRANSMANAGTIMEOUT > 0) {
                Context.TRANSMANAG.setTransactionTimeout(Context.TRANSMANAGTIMEOUT);
            }
            Context.TRANSMANAG.begin();
        } catch (final SystemException e) {
            throw new EFapsException(Context.class, "begin.beginSystemException", e);
        } catch (final NotSupportedException e) {
            throw new EFapsException(Context.class, "begin.beginNotSupportedException", e);
        }
        final Transaction transaction;
        try {
            transaction = Context.TRANSMANAG.getTransaction();
        } catch (final SystemException e) {
            throw new EFapsException(Context.class, "begin.getTransactionSystemException", e);
        }
        final Context context = new Context(transaction, _locale, _sessionAttributes, _parameters, _fileParameters,
                Inheritance.Inheritable.equals(_inheritance));
        switch (_inheritance) {
        case Inheritable:
            Context.INHERITTHREADCONTEXT.set(context);
            break;
        case Local:
            Context.THREADCONTEXT.set(context);
            break;
        case Standalone:
            Context.THREADCONTEXT.set(context);
            Context.INHERITTHREADCONTEXT.set(context);
            break;
        default:
            break;
        }

        if (_userName != null) {
            context.person = Person.get(_userName);
            context.locale = context.person.getLocale();
            context.timezone = context.person.getTimeZone();
            context.chronology = context.person.getChronology();
            context.language = context.person.getLanguage();
            if (_sessionAttributes != null) {
                if (context.containsUserAttribute(Context.CURRENTCOMPANY)) {
                    final Company comp = Company
                            .get(Long.parseLong(context.getUserAttribute(Context.CURRENTCOMPANY)));
                    if (comp != null && !context.person.getCompanies().isEmpty()
                            && context.person.isAssigned(comp)) {
                        context.companyId = comp.getId();
                    } else {
                        context.setUserAttribute(Context.CURRENTCOMPANY, "0");
                    }
                }
                // if no current company is set in the UserAttributes, the first one found is set
                if (context.companyId == null && context.person.getCompanies().size() > 0) {
                    final Long compID = context.person.getCompanies().iterator().next();
                    context.setUserAttribute(Context.CURRENTCOMPANY, compID.toString());
                    context.companyId = compID;
                }
            }
        }
        return context;
    }

    /**
     * Save the Context by committing and beginning a new Transaction.
     * @throws EFapsException on error
     */
    public static void save() throws EFapsException {
        try {
            Context.TRANSMANAG.commit();
            Context.TRANSMANAG.begin();
            final Context context = Context.getThreadContext();
            context.setTransaction(Context.TRANSMANAG.getTransaction());
            context.connectionStack.clear();
            context.connectionStore.clear();
        } catch (final SecurityException e) {
            throw new EFapsException(Context.class, "save.SecurityException", e);
        } catch (final IllegalStateException e) {
            throw new EFapsException(Context.class, "save.IllegalStateException", e);
        } catch (final RollbackException e) {
            throw new EFapsException(Context.class, "save.RollbackException", e);
        } catch (final HeuristicMixedException e) {
            throw new EFapsException(Context.class, "save.HeuristicMixedException", e);
        } catch (final HeuristicRollbackException e) {
            throw new EFapsException(Context.class, "save.HeuristicRollbackException", e);
        } catch (final SystemException e) {
            throw new EFapsException(Context.class, "save.SystemException", e);
        } catch (final NotSupportedException e) {
            throw new EFapsException(Context.class, "save.NotSupportedException", e);
        }
    }

    /**
     * Commit the context.
     * @throws EFapsException if commit of the transaction manager failed
     */
    public static void commit() throws EFapsException {
        Context.commit(true);
    }

    /**
     * @param _close close the threat context or not
     * @throws EFapsException if commit of the transaction manager failed
     */
    public static void commit(final boolean _close) throws EFapsException {
        try {
            Context.TRANSMANAG.commit();
        } catch (final IllegalStateException e) {
            throw new EFapsException(Context.class, "commit.IllegalStateException", e);
        } catch (final SecurityException e) {
            throw new EFapsException(Context.class, "commit.SecurityException", e);
        } catch (final HeuristicMixedException e) {
            throw new EFapsException(Context.class, "commit.HeuristicMixedException", e);
        } catch (final HeuristicRollbackException e) {
            throw new EFapsException(Context.class, "commit.HeuristicRollbackException", e);
        } catch (final RollbackException e) {
            throw new EFapsException(Context.class, "commit.RollbackException", e);
        } catch (final SystemException e) {
            throw new EFapsException(Context.class, "commit.SystemException", e);
        } finally {
            if (_close) {
                Context.getThreadContext().close();
            }
        }
    }

    /**
     * @throws EFapsException if roll back of the transaction manager failed
     */
    public static void rollback() throws EFapsException {
        try {
            Context.TRANSMANAG.rollback();
        } catch (final IllegalStateException e) {
            throw new EFapsException(Context.class, "rollback.IllegalStateException", e);
        } catch (final SecurityException e) {
            throw new EFapsException(Context.class, "rollback.SecurityException", e);
        } catch (final SystemException e) {
            throw new EFapsException(Context.class, "rollback.SystemException", e);
        } finally {
            Context.getThreadContext().close();
        }
    }

    /**
     * Is the status of transaction manager active?
     *
     * @return <i>true</i> if transaction manager is active, otherwise
     *         <i>false</i>
     * @throws EFapsException if the status of the transaction manager could not
     *             be evaluated
     * @see #TRANSMANAG
     */
    public static boolean isTMActive() throws EFapsException {
        try {
            return Context.TRANSMANAG.getStatus() == Status.STATUS_ACTIVE;
        } catch (final SystemException e) {
            throw new EFapsException(Context.class, "isTMActive.SystemException", e);
        }
    }

    /**
     * Is a transaction associated with a target object for transaction manager?
     *
     * @return <i>true</i> if a transaction associated, otherwise <i>false</i>
     * @throws EFapsException if the status of the transaction manager could not
     *             be evaluated
     * @see #TRANSMANAG
     */
    public static boolean isTMNoTransaction() throws EFapsException {
        try {
            return Context.TRANSMANAG.getStatus() == Status.STATUS_NO_TRANSACTION;
        } catch (final SystemException e) {
            throw new EFapsException(Context.class, "isTMNoTransaction.SystemException", e);
        }
    }

    /**
     * Is the status of transaction manager marked roll back?
     *
     * @return <i>true</i> if transaction manager is marked roll back, otherwise
     *         <i>false</i>
     * @throws EFapsException if the status of the transaction manager could not
     *             be evaluated
     * @see #TRANSMANAG
     */
    public static boolean isTMMarkedRollback() throws EFapsException {
        try {
            return Context.TRANSMANAG.getStatus() == Status.STATUS_MARKED_ROLLBACK;
        } catch (final SystemException e) {
            throw new EFapsException(Context.class, "isTMMarkedRollback.SystemException", e);
        }
    }

    /**
     * Returns the database type of the default connection (database where the
     * data model definition is stored).
     *
     * @see #DBTYPE
     * @return AbstractDatabase
     */
    public static AbstractDatabase<?> getDbType() {
        return Context.DBTYPE;
    }

    /**
     * Resets the context to current defined values in the Javax naming
     * environment.
     *
     * @throws StartupException if context could not be reseted to new values
     * @see #DBTYPE
     * @see #DATASOURCE
     * @see #TRANSMANAG
     * @see #TRANSMANAGTIMEOUT
     */
    public static void reset() throws StartupException {
        try {
            final InitialContext initCtx = new InitialContext();
            final javax.naming.Context envCtx = (javax.naming.Context) initCtx.lookup("java:comp/env");
            Context.DBTYPE = (AbstractDatabase<?>) envCtx.lookup(INamingBinds.RESOURCE_DBTYPE);
            Context.DATASOURCE = (DataSource) envCtx.lookup(INamingBinds.RESOURCE_DATASOURCE);
            Context.TRANSMANAG = (TransactionManager) envCtx.lookup(INamingBinds.RESOURCE_TRANSMANAG);
            try {
                Context.TRANSMANAGTIMEOUT = 0;
                final Map<?, ?> props = (Map<?, ?>) envCtx.lookup(INamingBinds.RESOURCE_CONFIGPROPERTIES);
                if (props != null) {
                    final String transactionTimeoutString = (String) props.get(IeFapsProperties.TRANSACTIONTIMEOUT);
                    if (transactionTimeoutString != null) {
                        Context.TRANSMANAGTIMEOUT = Integer.parseInt(transactionTimeoutString);
                    }
                }
            } catch (final NamingException e) {
                // this is actual no error, so nothing is presented
                Context.TRANSMANAGTIMEOUT = 0;
            }
        } catch (final NamingException e) {
            throw new StartupException("eFaps context could not be initialized", e);
        }
    }

    /**
     * Interfaces defining file parameters used to access file parameters (e.g.
     * uploads from the user within the web application).
     */
    public interface FileParameter {

        /**
         * Closes the file for this this file parameter is defined (e.g. deletes
         * the file in the temporary directory, if needed).
         *
         * @throws IOException if the close failed
         */
        void close() throws IOException;

        /**
         * Returns the input stream of the file for which this file parameter is
         * defined.
         *
         * @return input stream of the file
         * @throws IOException if the input stream could not be returned
         */
        InputStream getInputStream() throws IOException;

        /**
         * Returns the size of the file for which this file parameter is
         * defined.
         *
         * @return size of file
         */
        long getSize();

        /**
         * Returns the content type of the file for which this file parameter is
         * defined.
         *
         * @return content type of the file
         */
        String getContentType();

        /**
         * Returns the name of the file for which this file parameter is
         * defined.
         *
         * @return name of file
         */
        String getName();

        /**
         * Returns the name of the parameter for which this file parameter is
         * defined.
         *
         * @return parameter name
         */
        String getParameterName();
    }

    /**
     * The Enum Inheritance.
     *
     * @author The eFaps Team
     */
    public enum Inheritance {
        /** The Inheritable. */
        Inheritable,
        /** The Local. */
        Local,
        /** The New. */
        Standalone,
    }
}