| /* |
| * Copyright (c) 1998, 2020 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // Oracle - initial API and implementation from Oracle TopLink |
| package org.eclipse.persistence.sessions.factories; |
| |
| import java.util.Collection; |
| import org.eclipse.persistence.sessions.broker.SessionBroker; |
| import org.eclipse.persistence.sessions.*; |
| import org.eclipse.persistence.sessions.server.Server; |
| import org.eclipse.persistence.sessions.factories.SessionManager; |
| |
| |
| /** |
| * Helper class to simplify the development and generation of code that accesses |
| * TopLink through the SessionManager (sessions config XML). |
| * Responsibilities:<ul> |
| * <li> Lookup of a session by name using default or provided sessions config location |
| * <li> Support lookup of active UnitOfWork and Session in JTA environments |
| * <li> Hot/Re-deployment handling of applications |
| * <li> Detachment helpers to simplify usage within a local session bean |
| * </ul> |
| * |
| * Basic usage example: |
| * <code> |
| * SessionFactory = sessionFactory = new SessionFactory("session-name"); |
| * |
| * ... |
| * |
| * public List read(Vector args) { |
| * Session session = sessionFactory.acquireSession(); |
| * |
| * List results = (List) session.executeQuery("query-name", MyClass.class, args); |
| * |
| * session.release(); |
| * return results; |
| * } |
| * |
| * public void write(MyClass detachedInstance) { |
| * UnitOfWork uow = sessionFactory.acquireUnitOfWork(); |
| * |
| * MyClass workingCopy = (MyClass) uow.readObject(detachedInstance); |
| * |
| * if (workingCopy == null) { |
| * throw new MyException("Cannot write changes. Object does not exist"); |
| * } |
| * |
| * uow.deepMergeClone(detachedInstance); |
| * |
| * uow.commit(); |
| * } |
| * </code> |
| * |
| * <b>Detachment</b>: The detach helper methods are provided to assist with the |
| * construction of applications. This helper class was designed for use within |
| * session beans (SB) and in the case of local SBs the objects returned are not |
| * serialized. Since EclipseLink's default behavior is to return the shared instance |
| * from the cache and rely on developers to only modify instances within a |
| * UnitOfWork this may be an issue. The client to the local session bean may |
| * try to modify the instance and thus corrupt the cache. By detaching the object |
| * the client to the session bean gets its own isolated copy that it can freely |
| * modify. This provides the same functionality as with a remote session bean |
| * and allows the developer the choice in how/when objects are detached. |
| * <i>Note</i>: The above code example shows how a detached instance can have |
| * changes made to it persisted through use of the UnitOfWork merge API. |
| * |
| * @author Doug Clarke {@literal &} John Braken |
| * @version 10.1.3 |
| * @since Dec 10, 2006 |
| */ |
| public class SessionFactory { |
| /** |
| * Location for the sessions.xml file. The default here is the most common. |
| * If none is provided then EclipseLink's default locations of 'sessions.xml' |
| * and 'META-INF/sessions.xml' will be tried. |
| */ |
| private String sessionXMLPath; |
| private String sessionName; |
| |
| /** |
| * Constructor for creating a new EclipseLinkSessionHelper instance. |
| * |
| * @param sessionsXMLPath - resource path of the sessions configuration xml. |
| * @param sessionName - name of the session to use. |
| */ |
| public SessionFactory(String sessionsXMLPath, String sessionName) { |
| this.sessionXMLPath = sessionsXMLPath; |
| this.sessionName = sessionName; |
| } |
| |
| public SessionFactory(String sessionName) { |
| this.sessionName = sessionName; |
| } |
| |
| public String getSessionName() { |
| return sessionName; |
| } |
| |
| public String getSessionXMLPath() { |
| return this.sessionXMLPath; |
| } |
| |
| /** |
| * The class-loader returned form this call will be used when loading the |
| * EclipseLink configuration. By default this is the current thread's loader. |
| * If this is not the case users can subclass this session factory and |
| * override this method to provide a different loader. |
| */ |
| protected ClassLoader getClassLoader() { |
| return Thread.currentThread().getContextClassLoader(); |
| } |
| |
| /** |
| * Helper method that looks up the singleton session and ensure that |
| * if the application has been hot-deployed it gets a fresh version of the |
| * server. |
| */ |
| public DatabaseSession getSharedSession() { |
| return getSharedSession(true, false); |
| } |
| |
| /** |
| * Used in place of getSharedSession() when the calling application needs |
| * access to the session prior to login or it wishes to force the session |
| * configuration to be re-loaded an applied. This also makes use of the |
| * current class-loader return from getClassLoader() and a SessionManager |
| * class-loader check to see if the application was loaded by another |
| * class-loader and is should this be refreshed as the application has been |
| * hot deployed. |
| */ |
| public DatabaseSession getSharedSession(boolean login, boolean refresh) { |
| XMLSessionConfigLoader xmlLoader; |
| |
| if (getSessionXMLPath() != null) { |
| xmlLoader = new XMLSessionConfigLoader(getSessionXMLPath()); |
| } else { |
| xmlLoader = new XMLSessionConfigLoader(); |
| } |
| |
| return (DatabaseSession)SessionManager.getManager().getSession(xmlLoader, |
| getSessionName(), |
| getClassLoader(), |
| login, |
| refresh, |
| true); |
| } |
| |
| /** |
| * Returns the Session active for this specified helper. If the EclipseLink |
| * session does not have an external transaction controller or there is |
| * not an active JTA transaction then a newly acquire client session is |
| * returned on each call. |
| * |
| * This method also properly handles acquire a client session from a broker |
| * as well as returning the shared session in the case it is a database |
| * session. |
| */ |
| public Session acquireSession() { |
| Session sharedSession = getSharedSession(); |
| |
| if (sharedSession.hasExternalTransactionController()) { |
| UnitOfWork uow = sharedSession.getActiveUnitOfWork(); |
| if (uow != null) { |
| return uow.getParent(); |
| } |
| } |
| |
| if (sharedSession.isServerSession()) { |
| return ((Server)sharedSession).acquireClientSession(); |
| } |
| if (sharedSession.isSessionBroker()) { |
| SessionBroker broker = (SessionBroker)sharedSession; |
| if (broker.isServerSessionBroker()) { |
| return broker.acquireClientSessionBroker(); |
| } |
| return broker; |
| } |
| // Assume we have a database session and return it. |
| return sharedSession; |
| } |
| |
| /** |
| * Looks up the active UnitOfWork using either the global JTA TX or acquires |
| * a new one from the active session. |
| */ |
| public UnitOfWork acquireUnitOfWork() { |
| return acquireUnitOfWork(getSharedSession()); |
| } |
| |
| /** |
| * Looks up the active UnitOfWork using either the global JTA TX or acquires |
| * a new one from the active session. THis method should be used if a session |
| * has already been acquired. |
| */ |
| public UnitOfWork acquireUnitOfWork(Session session) { |
| if (session.hasExternalTransactionController()) { |
| return session.getActiveUnitOfWork(); |
| } |
| |
| return session.acquireUnitOfWork(); |
| } |
| |
| /** |
| * Build a detached copy using a one-off UnitOfWork. |
| * This simulates creation of a copy through serialization when using a |
| * remote session bean if this copy process is not done the user of this |
| * helper would return the shared copy from the cache that should not be |
| * modified. These detachment methods *MUST* be used for local session |
| * beans where the returned objects can be modified by the client. |
| * |
| * @param entity an existing persistent entity |
| * @return a copy of the entity for use in a local client that may make changes to it |
| */ |
| public Object detach(Object entity) { |
| UnitOfWork uow = |
| ((org.eclipse.persistence.internal.sessions.AbstractSession)getSharedSession()).acquireNonSynchronizedUnitOfWork(null); |
| |
| Object copy = uow.registerObject(entity); |
| uow.release(); |
| |
| return copy; |
| } |
| |
| public Collection detach(Collection entities) { |
| UnitOfWork uow = |
| ((org.eclipse.persistence.internal.sessions.AbstractSession)getSharedSession()).acquireNonSynchronizedUnitOfWork(null); |
| |
| Collection copies = uow.registerAllObjects(entities); |
| uow.release(); |
| |
| return copies; |
| } |
| |
| } |