/* * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License, version 2 as published by the Free Software * Foundation. * * You should have received a copy of the GNU General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program 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. * * * Copyright 2008 Pentaho Corporation. All rights reserved. * * @created Oct 15, 2008 * @author Aaron Phillips * */ package org.pentaho.platform.engine.core.system.objfac; import org.pentaho.platform.api.engine.IPentahoInitializer; import org.pentaho.platform.api.engine.IPentahoObjectFactory; import org.pentaho.platform.api.engine.IPentahoSession; import org.pentaho.platform.api.engine.ObjectFactoryException; import org.pentaho.platform.engine.core.messages.Messages; import org.pentaho.platform.engine.core.system.StandaloneSession; import org.pentaho.platform.util.logging.Logger; import org.springframework.context.ApplicationContext; /** * Framework for Spring-based object factories. Subclasses are required only to implement * the init method, which is responsible for setting the {@link ApplicationContext}. * <p> * A note on creation and management of objects: * Object creation and scoping is handled by Spring with one exception: in the case of * a {@link StandaloneSession}. Spring's session scope relates a bean to an {@link HttpSession}, * and as such it does not know about custom sessions. The correct approach to solve this problem * is to write a custom Spring scope (called something like "pentahosession"). Unfortunately, we * cannot implement a custom scope to handle the {@link StandaloneSession} because the custom scope * would not be able to access it. There is currently no way to statically obtain a reference to a * pentaho session. So we are left with using custom logic in this factory to execute a different non-Spring logic path * when the IPentahoSession is of type StandaloneSession. * <p> * TODO (BISERVER-2380) remove the custom logic in {@link #retreiveObject(String, IPentahoSession)} and use * a custom Spring scope to handle any session types that Spring does not handle out-of-the-box, * such as {@link StandaloneSession}. In order to do this, we need a way to access the * current {@link IPentahoSession} from a static context (perhaps a ThreadLocal). * * @see IPentahoObjectFactory * * @author Aaron Phillips */ public abstract class AbstractSpringPentahoObjectFactory implements IPentahoObjectFactory { protected ApplicationContext beanFactory; /** * @see IPentahoObjectFactory#get(Class, IPentahoSession) */ public <T> T get(Class<T> interfaceClass, final IPentahoSession session) throws ObjectFactoryException { return get(interfaceClass, interfaceClass.getSimpleName(), session); } /** * @see IPentahoObjectFactory#get(Class, String, IPentahoSession) */ @SuppressWarnings("unchecked") public <T> T get(Class<T> interfaceClass, String key, final IPentahoSession session) throws ObjectFactoryException { return (T) retreiveObject(key, session); } protected Object instanceClass(String key) throws ObjectFactoryException { Object object = null; try { object = beanFactory.getType(key).newInstance(); } catch (Exception e) { String msg = Messages.getInstance().getString("AbstractSpringPentahoObjectFactory.WARN_FAILED_TO_CREATE_OBJECT", key); //$NON-NLS-1$ throw new ObjectFactoryException(msg, e); } return object; } protected Object retrieveViaSpring(String beanId) throws ObjectFactoryException { Object object = null; try { object = beanFactory.getBean(beanId); } catch (Throwable t) { String msg = Messages.getInstance().getString("AbstractSpringPentahoObjectFactory.WARN_FAILED_TO_RETRIEVE_OBJECT", beanId); //$NON-NLS-1$ throw new ObjectFactoryException(msg,t); } return object; } protected Object retreiveObject(String key, final IPentahoSession session) throws ObjectFactoryException { //cannot access logger here since this object factory provides the logger Logger.debug(this, "Attempting to get an instance of [" + key + "] while in session [" + session + "]"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ Object object = null; if (session != null && session instanceof StandaloneSession) { //first ask Spring for the object, if it is session scoped it will fail //since Spring doesn't know about StandaloneSessions try { object = beanFactory.getBean(key); } catch (Throwable t) { //Spring could not create the object, perhaps due to session scoping, let's try //retrieving it from our internal session map Logger.debug(this, "Retrieving object from Pentaho session map (not Spring)."); //$NON-NLS-1$ object = session.getAttribute(key); if ((object == null)) { //our internal session map doesn't have it, let's create it object = instanceClass(key); session.setAttribute(key, object); } } } else { //Spring can handle the object retrieval since we are not dealing with StandaloneSession object = retrieveViaSpring(key); } //FIXME: what is this doing here?? if (object instanceof IPentahoInitializer) { ((IPentahoInitializer) object).init(session); } Logger.debug(this, " got an instance of [" + key + "]: " + object); //$NON-NLS-1$ //$NON-NLS-2$ return object; } /** * @see IPentahoObjectFactory#objectDefined(String) */ public boolean objectDefined(String key) { return beanFactory.containsBean(key); } /** * @see IPentahoObjectFactory#getImplementingClass(String) */ @SuppressWarnings("unchecked") public Class getImplementingClass(String key) { return beanFactory.getType(key); } }