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

org.restcomm.slee.resource.jdbc.JdbcResourceAdaptor Maven / Gradle / Ivy

There is a newer version: 7.2.0-113
Show newest version
/*
 * JBoss, Home of Professional Open Source
 * Copyright 2011, Red Hat, Inc. and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.restcomm.slee.resource.jdbc;

import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.slee.Address;
import javax.slee.facilities.EventLookupFacility;
import javax.slee.facilities.Tracer;
import javax.slee.resource.ActivityFlags;
import javax.slee.resource.ActivityHandle;
import javax.slee.resource.ConfigProperties;
import javax.slee.resource.EventFlags;
import javax.slee.resource.FailureReason;
import javax.slee.resource.FireableEventType;
import javax.slee.resource.InvalidConfigurationException;
import javax.slee.resource.Marshaler;
import javax.slee.resource.ReceivableService;
import javax.slee.resource.ResourceAdaptor;
import javax.slee.resource.ResourceAdaptorContext;
import javax.slee.transaction.SleeTransactionManager;
import javax.sql.DataSource;

import org.restcomm.slee.resource.jdbc.event.JdbcTaskExecutionThrowableEvent;
import org.restcomm.slee.resource.jdbc.event.JdbcTaskExecutionThrowableEventImpl;
import org.restcomm.slee.resource.jdbc.task.JdbcTask;
import org.restcomm.slee.resource.jdbc.task.JdbcTaskResult;
import org.restcomm.slee.resource.jdbc.task.simple.SimpleJdbcTaskResultEvent;

/**
 * The JDBC Resource Adaptor object.
 * 
 * @author martins
 * 
 */
public class JdbcResourceAdaptor implements ResourceAdaptor {

	/**
	 * the RA context, which gives
	 */
	private ResourceAdaptorContext context;

	private static final String DATASOURCE_JNDI_NAME_CONFIG_PROPERTY = "DATASOURCE_JNDI_NAME";
	private String datasourceName;

	private static final String EXECUTOR_SERVICE_THREADS_CONFIG_PROPERTY = "EXECUTOR_SERVICE_THREADS";
	private int executorServiceThreads;

	private static final String RA_SBB_INTERFACE_CONNECTION_GETTERS_ON_CONFIG_PROPERTY = "RA_SBB_INTERFACE_CONNECTION_GETTERS_ON";
	private boolean raSbbInterfaceConnectionGettersOn;

	/**
	 * the RA interface for SBBs
	 */
	private JdbcResourceAdaptorSbbInterfaceImpl sbbInterface = new JdbcResourceAdaptorSbbInterfaceImpl(
			this);

	/**
	 * the RA's Marshaller
	 */
	private JdbcResourceAdaptorMarshaller marshaller = new JdbcResourceAdaptorMarshaller(
			this);

	/**
	 * the RA "logger"
	 */
	private Tracer tracer;

	private DataSource datasource;

	private ExecutorService executorService;

	private FireableEventType simpleJdbcTaskResultEventType;
	private FireableEventType jdbcTaskExecutionThrowableEventType;

	private SleeTransactionManager txManager;
	private EventLookupFacility eventLookupFacility;

	// --- getters which expose RA functionalities, needed by other classes

	/**
	 * 
	 * @return
	 */
	public ResourceAdaptorContext getContext() {
		return context;
	}

	/**
	 * 
	 * @return
	 */
	public DataSource getDatasource() {
		return datasource;
	}

	/**
	 * 
	 * @return
	 */
	public Tracer getTracer() {
		return this.tracer;
	}

	/**
	 * 
	 * @return
	 */
	public SleeTransactionManager getTxManager() {
		return txManager;
	}

	// --- beginning of SLEE 1.1 RA contract ---

	@Override
	public void activityEnded(ActivityHandle activityHandle) {
		// NOT USED
	}

	@Override
	public void activityUnreferenced(ActivityHandle activityHandle) {
		// NOT USED
	}

	@Override
	public void administrativeRemove(ActivityHandle activityHandle) {
		// NOT USED
	}

	@Override
	public void eventProcessingFailed(ActivityHandle activityHandle,
			FireableEventType eventType, Object eventObject, Address address,
			ReceivableService service, int eventFlags, FailureReason reason) {
		// NOT USED
	}

	@Override
	public void eventProcessingSuccessful(ActivityHandle activityHandle,
			FireableEventType eventType, Object eventObject, Address address,
			ReceivableService service, int eventFlags) {
		// NOT USED
	}

	@Override
	public void eventUnreferenced(ActivityHandle activityHandle,
			FireableEventType eventType, Object eventObject, Address address,
			ReceivableService service, int eventFlags) {
		// not used
	}

	@Override
	public Object getActivity(ActivityHandle activityHandle) {
		return activityHandle;
	}

	@Override
	public ActivityHandle getActivityHandle(Object activityObject) {
		if (activityObject instanceof JdbcActivityImpl) {
			final JdbcActivityImpl jdbcActivity = (JdbcActivityImpl) activityObject;
			if (jdbcActivity.getRaEntityName().equals(
					getContext().getEntityName())) {
				return jdbcActivity;
			} else {
				return null;
			}
		} else {
			return null;
		}
	}

	@Override
	public Marshaler getMarshaler() {
		return this.marshaller;
	}

	@Override
	public Object getResourceAdaptorInterface(String className) {
		return this.sbbInterface;
	}

	@Override
	public void queryLiveness(ActivityHandle activityHandle) {
		// NOT USED
	}

	@Override
	public void raActive() {
		try {
			this.datasource = (DataSource) InitialContext
					.doLookup(datasourceName);
		} catch (NamingException e) {
			tracer.severe("failed to retrieve the data source", e);
		}
		this.executorService = Executors
				.newFixedThreadPool(executorServiceThreads);
	}

	@Override
	public void raConfigurationUpdate(ConfigProperties configuration) {
		// NOT USED
	}

	@Override
	public void raConfigure(ConfigProperties configuration) {
		this.datasourceName = (String) configuration.getProperty(
				DATASOURCE_JNDI_NAME_CONFIG_PROPERTY).getValue();
		this.executorServiceThreads = (Integer) configuration.getProperty(
				EXECUTOR_SERVICE_THREADS_CONFIG_PROPERTY).getValue();
		this.raSbbInterfaceConnectionGettersOn = (Boolean) configuration
				.getProperty(
						RA_SBB_INTERFACE_CONNECTION_GETTERS_ON_CONFIG_PROPERTY)
				.getValue();
		this.sbbInterface
				.setRaSbbInterfaceConnectionGettersOn(raSbbInterfaceConnectionGettersOn);
	}

	@Override
	public void raInactive() {
		this.datasource = null;
		this.executorService = null;
	}

	@Override
	public void raStopping() {
		// NOT USED
	}

	@Override
	public void raUnconfigure() {
		this.datasourceName = null;
		this.executorServiceThreads = 0;
	}

	@Override
	public void raVerifyConfiguration(ConfigProperties properties)
			throws InvalidConfigurationException {
		String datasourceName = (String) properties.getProperty(
				"DATASOURCE_JNDI_NAME").getValue();
		try {
			InitialContext.doLookup(datasourceName);
		} catch (NamingException e) {
			throw new InvalidConfigurationException("bad datasource name", e);
		}
		Integer executorServiceThreads = (Integer) properties.getProperty(
				"EXECUTOR_SERVICE_THREADS").getValue();
		if (executorServiceThreads < 1) {
			throw new InvalidConfigurationException(
					"executor service threads must be a positive integer");
		}
	}

	@Override
	public void serviceActive(ReceivableService service) {
		// THE RA DOES NOT USES EVENT FILTERING
	}

	@Override
	public void serviceInactive(ReceivableService service) {
		// THE RA DOES NOT USES EVENT FILTERING
	}

	@Override
	public void serviceStopping(ReceivableService service) {
		// THE RA DOES NOT USES EVENT FILTERING
	}

	@Override
	public void setResourceAdaptorContext(ResourceAdaptorContext context) {
		this.context = context;
		this.tracer = context.getTracer(this.getClass().getSimpleName());
		this.txManager = context.getSleeTransactionManager();
		this.eventLookupFacility = context.getEventLookupFacility();
		try {
			this.simpleJdbcTaskResultEventType = eventLookupFacility
					.getFireableEventType(SimpleJdbcTaskResultEvent.EVENT_TYPE_ID);
			this.jdbcTaskExecutionThrowableEventType = eventLookupFacility
					.getFireableEventType(JdbcTaskExecutionThrowableEvent.EVENT_TYPE_ID);
		} catch (Throwable e) {
			tracer.severe("Failed to retrieve fireable event types", e);
		}
	}

	@Override
	public void unsetResourceAdaptorContext() {
		this.context = null;
		this.tracer = null;
		this.jdbcTaskExecutionThrowableEventType = null;
		this.simpleJdbcTaskResultEventType = null;
	}

	// --- end of SLEE 1.1 RA contract

	// --- activity management
	/**
	 * 
	 * @return
	 */
	JdbcActivityImpl createActivity() {
		JdbcActivityImpl activity = new JdbcActivityImpl(this, UUID
				.randomUUID().toString());
		try {
			this.context.getSleeEndpoint().startActivitySuspended(activity,
					activity, ActivityFlags.SLEE_MAY_MARSHAL);
		} catch (Exception e) {
			tracer.severe("failed to start activity " + activity.getId(), e);
		}
		return activity;
	}

	/**
	 * 
	 * @param activity
	 */
	void endActivity(JdbcActivityImpl activity) {
		try {
			this.context.getSleeEndpoint().endActivityTransacted(activity);
		} catch (Exception e) {
			tracer.severe("failed to end activity", e);
		}
	}

	// --- async sql execution

	private void fireEvent(FireableEventType eventType, Object event,
			ActivityHandle activity, int eventFlags) {
		if (tracer.isFineEnabled()) {
			tracer.fine("firing event: eventType = " + eventType
					+ " , event = " + event + " , activity = " + activity
					+ ", eventFlags = " + eventFlags);
		}
		try {
			context.getSleeEndpoint().fireEvent(activity, eventType, event,
					null, null, eventFlags);
		} catch (Throwable e) {
			tracer.severe("failed to fire event " + eventType + " in handle "
					+ activity, e);
		}
	}

	public void execute(final JdbcTask jdbcTask, final JdbcActivityImpl activity) {
		if (tracer.isFineEnabled()) {
			tracer.fine("execute( task = " + jdbcTask + " , activity = "
					+ activity + " )");
		}

		// get class loader from execution request context, task may need it for
		// actual execution
		final ClassLoader classLoader = Thread.currentThread()
				.getContextClassLoader();

		// build runnable task
		Runnable task = new Runnable() {

			@Override
			public void run() {

				Thread.currentThread().setContextClassLoader(classLoader);

				final JdbcTaskContextImpl context = new JdbcTaskContextImpl(
						JdbcResourceAdaptor.this);
				try {
					// execute
					JdbcTaskResult taskResult = jdbcTask.execute(context);
					// protect the thread against bad tasks, which have open
					// transaction after task execution
					if (txManager.getTransaction() != null) {
						txManager.commit();
					}
					if (taskResult == null) {
						// no event to fire
						if (tracer.isFineEnabled()) {
							tracer.fine("execution of task " + jdbcTask
									+ " in activity " + activity
									+ " returned null result.");
						}
						return;
					}
					FireableEventType eventType = null;
					if (taskResult.getEventTypeID() == SimpleJdbcTaskResultEvent.EVENT_TYPE_ID) {
						eventType = simpleJdbcTaskResultEventType;
					} else {
						eventType = eventLookupFacility
								.getFireableEventType(taskResult
										.getEventTypeID());
					}
					fireEvent(eventType, taskResult.getEventObject(), activity,
							EventFlags.NO_FLAGS);
				} catch (Throwable e) {
					if (tracer.isFineEnabled()) {
						tracer.fine("failed to complete task execution", e);
					}

					try {
						// rolling back transaction if failed
						if (txManager.getTransaction() != null) {
							if (tracer.isFineEnabled()) {
								tracer.fine("transaction " + txManager.getTransaction().toString()
										+ " has status " + txManager.getTransaction().getStatus());
							}

							txManager.rollback();
						}
					}
					catch (Exception e1) {
						if (tracer.isFineEnabled()) {
							tracer.fine("failure in transaction rollback", e1);
						}
					}

					// build event
					Object event = new JdbcTaskExecutionThrowableEventImpl(e,
							jdbcTask);
					// fire event
					fireEvent(jdbcTaskExecutionThrowableEventType, event,
							activity, EventFlags.NO_FLAGS);
				} finally {
					if (context.connection != null) {
						try {
							if (!context.connection.isClosed()) {
								context.connection.close();
							}
						} catch (Exception e) {
							if (tracer.isFineEnabled()) {
								tracer.fine(
										"failure in connection closing procedure",
										e);
							}
						}
					}
				}
			}
		};

		// submit to executor
		executorService.submit(task);
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy