/* * IronJacamar, a Java EE Connector Architecture implementation * Copyright 2014, Red Hat Inc, and individual contributors * as indicated by the @author tags. See the copyright.txt file 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 Eclipse Public License 1.0 as * published by the Free Software Foundation. * * 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 Eclipse * Public License for more details. * * You should have received a copy of the Eclipse 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.ironjacamar.core.workmanager; import org.ironjacamar.core.CoreBundle; import org.ironjacamar.core.CoreLogger; import org.ironjacamar.core.api.workmanager.DistributedWorkManager; import org.ironjacamar.core.api.workmanager.DistributedWorkManagerStatistics; import org.ironjacamar.core.spi.workmanager.Address; import org.ironjacamar.core.spi.workmanager.notification.NotificationListener; import org.ironjacamar.core.spi.workmanager.policy.Policy; import org.ironjacamar.core.spi.workmanager.selector.Selector; import org.ironjacamar.core.spi.workmanager.transport.Transport; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import javax.resource.spi.work.DistributableWork; import javax.resource.spi.work.Work; import javax.resource.spi.work.WorkException; import javax.resource.spi.work.WorkManager; import org.jboss.logging.Logger; import org.jboss.logging.Messages; /** * The distributed work manager implementation. * * @author <a href="mailto:jesper.pedersen@ironjacamar.org">Jesper Pedersen</a> */ public class DistributedWorkManagerImpl extends WorkManagerImpl implements DistributedWorkManager { /** The logger */ private static CoreLogger log = Logger.getMessageLogger(CoreLogger.class, DistributedWorkManagerImpl.class.getName()); /** Whether trace is enabled */ private static boolean trace = log.isTraceEnabled(); /** The bundle */ private static CoreBundle bundle = Messages.getBundle(CoreBundle.class); /** Policy */ private Policy policy; /** Selector */ private Selector selector; /** Transport */ private Transport transport; /** Notification listeners */ private Collection<NotificationListener> listeners; /** Distributed statistics enabled */ private boolean distributedStatisticsEnabled; /** Distributed statistics */ private DistributedWorkManagerStatisticsImpl distributedStatistics; /** Should doWork be enabled for distribution */ private boolean doWorkDistributionEnabled; /** Should startWork be enabled for distribution */ private boolean startWorkDistributionEnabled; /** Should scheduleWork be enabled for distribution */ private boolean scheduleWorkDistributionEnabled; /** Local address */ private Address localAddress; /** * Constructor */ public DistributedWorkManagerImpl() { super(); this.policy = null; this.selector = null; this.transport = null; this.listeners = Collections.synchronizedList(new ArrayList<NotificationListener>(3)); this.distributedStatisticsEnabled = true; this.distributedStatistics = null; this.doWorkDistributionEnabled = true; this.startWorkDistributionEnabled = true; this.scheduleWorkDistributionEnabled = true; this.localAddress = null; } /** * {@inheritDoc} */ public Policy getPolicy() { return policy; } /** * {@inheritDoc} */ public synchronized void setPolicy(Policy v) { if (policy != null && policy instanceof NotificationListener) { listeners.remove((NotificationListener)policy); } policy = v; if (policy != null && policy instanceof NotificationListener) { listeners.add((NotificationListener)policy); } } /** * {@inheritDoc} */ public Selector getSelector() { return selector; } /** * {@inheritDoc} */ public synchronized void setSelector(Selector v) { if (selector != null && selector instanceof NotificationListener) { listeners.remove((NotificationListener)selector); } selector = v; if (selector != null && selector instanceof NotificationListener) { listeners.add((NotificationListener)selector); } } /** * {@inheritDoc} */ public Transport getTransport() { return transport; } /** * {@inheritDoc} */ public synchronized void setTransport(Transport v) { if (transport != null) { if (transport instanceof NotificationListener) listeners.remove((NotificationListener)transport); removeDistributedStatistics(); } transport = v; if (transport != null) { if (transport instanceof NotificationListener) listeners.add((NotificationListener)transport); initDistributedStatistics(); } } /** * {@inheritDoc} */ public boolean isDistributedStatisticsEnabled() { return distributedStatisticsEnabled; } /** * {@inheritDoc} */ public void setDistributedStatisticsEnabled(boolean v) { distributedStatisticsEnabled = v; } /** * {@inheritDoc} */ public Collection<NotificationListener> getNotificationListeners() { return listeners; } /** * Set the listeners * @param v The value */ void setNotificationListeners(Collection<NotificationListener> v) { listeners = v; } /** * {@inheritDoc} */ public void setDoWorkDistributionEnabled(boolean v) { doWorkDistributionEnabled = v; } /** * {@inheritDoc} */ public boolean isDoWorkDistributionEnabled() { return doWorkDistributionEnabled; } /** * {@inheritDoc} */ public void setStartWorkDistributionEnabled(boolean v) { startWorkDistributionEnabled = v; } /** * {@inheritDoc} */ public boolean isStartWorkDistributionEnabled() { return startWorkDistributionEnabled; } /** * {@inheritDoc} */ public void setScheduleWorkDistributionEnabled(boolean v) { scheduleWorkDistributionEnabled = v; } /** * {@inheritDoc} */ public boolean isScheduleWorkDistributionEnabled() { return scheduleWorkDistributionEnabled; } /** * {@inheritDoc} */ public void localDoWork(Work work) throws WorkException { if (transport != null) { checkTransport(); if (getLongRunningThreadPool() != null && WorkManagerUtil.isLongRunning(work)) { transport.updateLongRunningFree(getLocalAddress(), getLongRunningThreadPool().getNumberOfFreeThreads() - 1); } else { transport.updateShortRunningFree(getLocalAddress(), getShortRunningThreadPool().getNumberOfFreeThreads() - 1); } WorkEventListener wel = new WorkEventListener(WorkManagerUtil.isLongRunning(work), getShortRunningThreadPool(), getLongRunningThreadPool(), getLocalAddress(), transport); super.doWork(work, WorkManager.INDEFINITE, null, wel); } else { super.doWork(work); } } /** * {@inheritDoc} */ public void localScheduleWork(Work work) throws WorkException { if (transport != null) { checkTransport(); if (getLongRunningThreadPool() != null && WorkManagerUtil.isLongRunning(work)) { transport.updateLongRunningFree(getLocalAddress(), getLongRunningThreadPool().getNumberOfFreeThreads() - 1); } else { transport.updateShortRunningFree(getLocalAddress(), getShortRunningThreadPool().getNumberOfFreeThreads() - 1); } WorkEventListener wel = new WorkEventListener(WorkManagerUtil.isLongRunning(work), getShortRunningThreadPool(), getLongRunningThreadPool(), getLocalAddress(), transport); super.scheduleWork(work, WorkManager.INDEFINITE, null, wel); } else { super.scheduleWork(work); } } /** * {@inheritDoc} */ public long localStartWork(Work work) throws WorkException { if (transport != null) { checkTransport(); if (getLongRunningThreadPool() != null && WorkManagerUtil.isLongRunning(work)) { transport.updateLongRunningFree(getLocalAddress(), getLongRunningThreadPool().getNumberOfFreeThreads() - 1); } else { transport.updateShortRunningFree(getLocalAddress(), getShortRunningThreadPool().getNumberOfFreeThreads() - 1); } WorkEventListener wel = new WorkEventListener(WorkManagerUtil.isLongRunning(work), getShortRunningThreadPool(), getLongRunningThreadPool(), getLocalAddress(), transport); return super.startWork(work, WorkManager.INDEFINITE, null, wel); } else { return super.startWork(work); } } /** * {@inheritDoc} */ @Override public void doWork(Work work) throws WorkException { if (policy == null || selector == null || transport == null || work == null || !(work instanceof DistributableWork) || !doWorkDistributionEnabled) { localDoWork(work); } else { doFirstChecks(work, WorkManager.INDEFINITE, null); checkTransport(); DistributableWork dw = (DistributableWork)work; boolean executed = false; if (policy.shouldDistribute(this, dw)) { Address dwmAddress = selector.selectDistributedWorkManager(getLocalAddress(), dw); if (dwmAddress != null && !getLocalAddress().equals(dwmAddress)) { transport.doWork(dwmAddress, dw); executed = true; } } if (!executed) { localDoWork(work); } } } /** * {@inheritDoc} */ @Override public long startWork(Work work) throws WorkException { if (policy == null || selector == null || transport == null || work == null || !(work instanceof DistributableWork) || !startWorkDistributionEnabled) { return localStartWork(work); } else { doFirstChecks(work, WorkManager.INDEFINITE, null); checkTransport(); DistributableWork dw = (DistributableWork)work; if (policy.shouldDistribute(this, dw)) { Address dwmAddress = selector.selectDistributedWorkManager(getLocalAddress(), dw); if (dwmAddress != null && !getLocalAddress().equals(dwmAddress)) { return transport.startWork(dwmAddress, dw); } } return localStartWork(work); } } /** * {@inheritDoc} */ @Override public void scheduleWork(Work work) throws WorkException { if (policy == null || selector == null || transport == null || work == null || !(work instanceof DistributableWork) || !scheduleWorkDistributionEnabled) { localScheduleWork(work); } else { doFirstChecks(work, WorkManager.INDEFINITE, null); checkTransport(); DistributableWork dw = (DistributableWork)work; boolean executed = false; if (policy.shouldDistribute(this, dw)) { Address dwmAddress = selector.selectDistributedWorkManager(getLocalAddress(), dw); if (dwmAddress != null && !getLocalAddress().equals(dwmAddress)) { transport.scheduleWork(dwmAddress, dw); executed = true; } } if (!executed) { localScheduleWork(work); } } } /** * Check the transport * @exception WorkException In case of an error */ private void checkTransport() throws WorkException { if (!transport.isInitialized()) { try { transport.initialize(); initialize(); } catch (Throwable t) { WorkException we = new WorkException("Exception during transport initialization"); we.initCause(t); throw we; } } } /** * {@inheritDoc} */ public DistributedWorkManagerStatistics getDistributedStatistics() { return distributedStatistics; } /** * Set the distributed statistics * @param v The value */ void setDistributedStatistics(DistributedWorkManagerStatisticsImpl v) { distributedStatistics = v; } /** * Init distributed statistics */ private synchronized void initDistributedStatistics() { if (distributedStatistics == null) { distributedStatistics = new DistributedWorkManagerStatisticsImpl(); listeners.add((NotificationListener)distributedStatistics); } } /** * Remove distributed statistics */ private synchronized void removeDistributedStatistics() { if (distributedStatistics != null) { listeners.remove((NotificationListener)distributedStatistics); distributedStatistics.setTransport(null); distributedStatistics = null; } } /** * {@inheritDoc} */ @Override protected void deltaDoWorkAccepted() { if (trace) log.trace("deltaDoWorkAccepted"); super.deltaDoWorkAccepted(); if (distributedStatisticsEnabled && distributedStatistics != null && transport != null) { try { checkTransport(); distributedStatistics.sendDeltaDoWorkAccepted(); } catch (WorkException we) { log.debugf("deltaDoWorkAccepted: %s", we.getMessage(), we); } } } /** * {@inheritDoc} */ @Override protected void deltaDoWorkRejected() { if (trace) log.trace("deltaDoWorkRejected"); super.deltaDoWorkRejected(); if (distributedStatisticsEnabled && distributedStatistics != null && transport != null) { try { checkTransport(); distributedStatistics.sendDeltaDoWorkRejected(); } catch (WorkException we) { log.debugf("deltaDoWorkRejected: %s", we.getMessage(), we); } } } /** * {@inheritDoc} */ @Override protected void deltaStartWorkAccepted() { if (trace) log.trace("deltaStartWorkAccepted"); super.deltaStartWorkAccepted(); if (distributedStatisticsEnabled && distributedStatistics != null && transport != null) { try { checkTransport(); distributedStatistics.sendDeltaStartWorkAccepted(); } catch (WorkException we) { log.debugf("deltaStartWorkAccepted: %s", we.getMessage(), we); } } } /** * {@inheritDoc} */ @Override protected void deltaStartWorkRejected() { if (trace) log.trace("deltaStartWorkRejected"); super.deltaStartWorkRejected(); if (distributedStatisticsEnabled && distributedStatistics != null && transport != null) { try { checkTransport(); distributedStatistics.sendDeltaStartWorkRejected(); } catch (WorkException we) { log.debugf("deltaStartWorkRejected: %s", we.getMessage(), we); } } } /** * {@inheritDoc} */ @Override protected void deltaScheduleWorkAccepted() { if (trace) log.trace("deltaScheduleWorkAccepted"); super.deltaScheduleWorkAccepted(); if (distributedStatisticsEnabled && distributedStatistics != null && transport != null) { try { checkTransport(); distributedStatistics.sendDeltaScheduleWorkAccepted(); } catch (WorkException we) { log.debugf("deltaScheduleWorkAccepted: %s", we.getMessage(), we); } } } /** * {@inheritDoc} */ @Override protected void deltaScheduleWorkRejected() { if (trace) log.trace("deltaScheduleWorkRejected"); super.deltaScheduleWorkRejected(); if (distributedStatisticsEnabled && distributedStatistics != null && transport != null) { try { checkTransport(); distributedStatistics.sendDeltaScheduleWorkRejected(); } catch (WorkException we) { log.debugf("deltaScheduleWorkRejected: %s", we.getMessage(), we); } } } /** * {@inheritDoc} */ @Override protected void deltaWorkSuccessful() { if (trace) log.trace("deltaWorkSuccessful"); super.deltaWorkSuccessful(); if (distributedStatisticsEnabled && distributedStatistics != null && transport != null) { try { checkTransport(); distributedStatistics.sendDeltaWorkSuccessful(); } catch (WorkException we) { log.debugf("deltaWorkSuccessful: %s", we.getMessage(), we); } } } /** * {@inheritDoc} */ @Override protected void deltaWorkFailed() { if (trace) log.trace("deltaWorkFailed"); super.deltaWorkFailed(); if (distributedStatisticsEnabled && distributedStatistics != null && transport != null) { try { checkTransport(); distributedStatistics.sendDeltaWorkFailed(); } catch (WorkException we) { log.debugf("deltaWorkFailed: %s", we.getMessage(), we); } } } /** * Get local address * @return The value */ Address getLocalAddress() { if (localAddress == null) localAddress = new Address(getId(), getName(), transport != null ? transport.getId() : null); return localAddress; } /** * Initialize */ public void initialize() { if (distributedStatistics != null) { distributedStatistics.setOwnId(getLocalAddress()); distributedStatistics.setTransport(transport); } } /** * Clone the WorkManager implementation * @return A copy of the implementation * @exception CloneNotSupportedException Thrown if the copy operation isn't supported * */ @Override public org.ironjacamar.core.api.workmanager.WorkManager clone() throws CloneNotSupportedException { DistributedWorkManagerImpl wm = (DistributedWorkManagerImpl)super.clone(); wm.setPolicy(getPolicy()); wm.setSelector(getSelector()); wm.setTransport(getTransport()); wm.setDistributedStatisticsEnabled(isDistributedStatisticsEnabled()); wm.setDoWorkDistributionEnabled(isDoWorkDistributionEnabled()); wm.setStartWorkDistributionEnabled(isStartWorkDistributionEnabled()); wm.setScheduleWorkDistributionEnabled(isScheduleWorkDistributionEnabled()); DistributedWorkManagerStatisticsImpl dwmsi = new DistributedWorkManagerStatisticsImpl(); wm.setDistributedStatistics(dwmsi); if (getPolicy() != null && getPolicy() instanceof NotificationListener) wm.listeners.add((NotificationListener)getPolicy()); if (getSelector() != null && getSelector() instanceof NotificationListener) wm.listeners.add((NotificationListener)getSelector()); if (getTransport() != null && getTransport() instanceof NotificationListener) wm.listeners.add((NotificationListener)getTransport()); wm.listeners.add((NotificationListener)dwmsi); return wm; } /** * {@inheritDoc} */ @Override public void toString(StringBuilder sb) { sb.append(" policy=").append(policy); sb.append(" selector=").append(selector); sb.append(" transport=").append(transport); sb.append(" distributedStatisticsEnabled=").append(distributedStatisticsEnabled); sb.append(" distributedStatistics=").append(distributedStatistics); sb.append(" listeners=").append(listeners); sb.append(" doWorkDistributionEnabled=").append(doWorkDistributionEnabled); sb.append(" startWorkDistributionEnabled=").append(startWorkDistributionEnabled); sb.append(" scheduleWorkDistributionEnabled=").append(scheduleWorkDistributionEnabled); } }