com.adaptris.core.runtime.AdapterManager.java Source code

Java tutorial

Introduction

Here is the source code for com.adaptris.core.runtime.AdapterManager.java

Source

/*
 * Copyright 2015 Adaptris Ltd.
 * 
 * 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 com.adaptris.core.runtime;

import static org.apache.commons.lang.StringUtils.isEmpty;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import javax.management.MBeanNotificationInfo;
import javax.management.MalformedObjectNameException;
import javax.management.Notification;
import javax.management.ObjectName;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;

import com.adaptris.core.Adapter;
import com.adaptris.core.AdapterLifecycleEvent;
import com.adaptris.core.AdaptrisComponent;
import com.adaptris.core.AdaptrisConnection;
import com.adaptris.core.Channel;
import com.adaptris.core.ClosedState;
import com.adaptris.core.ComponentState;
import com.adaptris.core.CoreException;
import com.adaptris.core.DefaultMarshaller;
import com.adaptris.core.FailedMessageRetrier;
import com.adaptris.core.InitialisedState;
import com.adaptris.core.ProcessingExceptionHandler;
import com.adaptris.core.Service;
import com.adaptris.core.StartedState;
import com.adaptris.core.StoppedState;
import com.adaptris.core.management.VersionReport;
import com.adaptris.core.util.ManagedThreadFactory;

/**
 * Base implementation of {@link AdapterManagerMBean}.
 */
public class AdapterManager extends ComponentManagerImpl<Adapter>
        implements AdapterManagerMBean, AdapterRuntimeManager {
    private transient Adapter adapter;
    private transient Set<ChannelRuntimeManager> channelManagers;
    private transient Set<ChildRuntimeInfoComponent> childRuntimeInfoComponents;

    private transient ObjectName myObjectName = null;
    private String adapterBuildVersion;
    private List<String> adapterModules = new ArrayList<String>();
    private List<String> adapterArtifacts = new ArrayList<String>();

    private AdapterManager() {
        super();
        channelManagers = new HashSet<ChannelRuntimeManager>();
        childRuntimeInfoComponents = new HashSet<ChildRuntimeInfoComponent>();
    }

    public AdapterManager(Adapter owner) throws MalformedObjectNameException, CoreException {
        this();
        adapter = owner;
        initRefs();
        initVersionInfo();
    }

    private void initRefs() throws MalformedObjectNameException, CoreException {
        myObjectName = ObjectName.getInstance(JMX_ADAPTER_TYPE + ID_PREFIX + getWrappedComponent().getUniqueId());
        addChildJmxComponent(new AdapterComponentChecker(this));
        for (Channel c : adapter.getChannelList()) {
            if (c.hasUniqueId()) {
                addChild(new ChannelManager(c, this, true), true);
            }
        }
        registerChildRuntime(adapter.getMessageErrorDigester());
        registerChildRuntime(adapter.getFailedMessageRetrier());
        registerChildRuntime(adapter.getMessageErrorHandler());
        registerChildRuntime(adapter.logHandler());
        marshalConfig();
    }

    private void initVersionInfo() {
        VersionReport v = VersionReport.getInstance();
        adapterBuildVersion = v.getAdapterBuildVersion();
        adapterModules.addAll(v.getReport());
        adapterArtifacts.addAll(v.getArtifactIdentifiers());
    }

    private void registerChildRuntime(AdaptrisComponent c) throws CoreException {
        ChildRuntimeInfoComponent comp = (ChildRuntimeInfoComponent) RuntimeInfoComponentFactory.create(this, c);
        if (comp != null) {
            addChildJmxComponent(comp);
        }
    }

    @Override
    public ObjectName createObjectName() throws MalformedObjectNameException {
        return myObjectName;
    }

    @Override
    public long requestStartTime() {
        Date startTime = getWrappedComponent().lastStartTime();
        if (startTime != null) {
            return startTime.getTime();
        }
        return 0;
    }

    @Override
    public long requestStopTime() {
        // Should never be null, unlike lastStartTime()
        return getWrappedComponent().lastStopTime().getTime();
    }

    @Override
    public Collection<ObjectName> getChildren() throws MalformedObjectNameException {
        Set<ObjectName> result = new TreeSet<ObjectName>();
        for (ChannelRuntimeManager cmb : channelManagers) {
            result.add(cmb.createObjectName());
        }
        return result;
    }

    @Override
    public boolean addChild(ChannelRuntimeManager cmb) throws CoreException {
        return addChild(cmb, false);
    }

    private boolean addChild(ChannelRuntimeManager cmb, boolean ignoreActualChannel) throws CoreException {
        if (cmb == null) {
            throw new IllegalArgumentException("Null ChannelManagerBean");
        }
        if (!ignoreActualChannel) {
            getWrappedComponent().getChannelList().add(cmb.getWrappedComponent());
            marshalAndSendNotification();

        }
        return channelManagers.add(cmb);

    }

    private boolean removeChannelManager(ChannelRuntimeManager cmb, boolean unregisterJmx) throws CoreException {
        if (cmb == null) {
            throw new IllegalArgumentException("Null ChannelManagerBean");
        }
        int removed = 0;
        Channel c = cmb.getWrappedComponent();
        closeQuietly(c);
        removed += getWrappedComponent().getChannelList().remove(c) ? 1 : 0;
        if (removed == 1)
            marshalAndSendNotification();
        if (channelManagers.remove(cmb)) {
            if (unregisterJmx) {
                cmb.unregisterMBean();
            }
            removed++;
        }
        return removed == 2;
    }

    @Override
    public boolean removeChild(ChannelRuntimeManager cmb) throws CoreException {
        return removeChannelManager(cmb, false);
    }

    @Override
    public boolean addChildren(Collection<ChannelRuntimeManager> coll) throws CoreException {
        throw new UnsupportedOperationException();
        // int i = 0;
        // for (ChannelManager bean : coll) {
        // i += addChild(bean) ? 1 : 0;
        // }
        // return i > 0;
    }

    @Override
    public boolean removeChildren(Collection<ChannelRuntimeManager> coll) throws CoreException {
        int i = 0;
        for (ChannelRuntimeManager bean : coll) {
            i += removeChild(bean) ? 1 : 0;
        }
        return i > 0;
    }

    @Override
    public Adapter getWrappedComponent() {
        return adapter;
    }

    /**
     * Equality is based on the underlying ObjectName.
     * 
     */
    @Override
    public boolean equals(Object o) {
        if (o == null) {
            return false;
        }
        if (o == this) {
            return true;
        }
        try {
            if (o instanceof AdapterManagerMBean) {
                AdapterManagerMBean rhs = (AdapterManagerMBean) o;
                return new EqualsBuilder().append(myObjectName, rhs.createObjectName()).isEquals();
            }
        } catch (MalformedObjectNameException ignored) {

        }
        return false;
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder(11, 17).append(myObjectName).toHashCode();
    }

    @Override
    public String toString() {
        return myObjectName.toString();
    }

    @Override
    protected void checkTransitionTo(ComponentState futureState) throws CoreException {
        // Do nothing, we don't have a parent to check.
    }

    @Override
    public Collection<BaseComponentMBean> getAllDescendants() {
        Set<BaseComponentMBean> result = new HashSet<BaseComponentMBean>();
        for (ChannelRuntimeManager c : channelManagers) {
            result.add(c);
            result.addAll(c.getAllDescendants());
        }
        for (ChildRuntimeInfoComponent cmb : childRuntimeInfoComponents) {
            result.add(cmb);
        }
        return result;
    }

    @Override
    public Collection<ObjectName> getChildRuntimeInfoComponents() throws MalformedObjectNameException {
        Set<ObjectName> result = new TreeSet<ObjectName>();
        for (ChildRuntimeInfoComponent cmb : childRuntimeInfoComponents) {
            result.add(cmb.createObjectName());
        }
        return result;
    }

    @Override
    public boolean addChildJmxComponent(ChildRuntimeInfoComponent comp) {
        if (comp == null) {
            throw new IllegalArgumentException("Null ChildRuntimeInfoComponent");
        }
        return childRuntimeInfoComponents.add(comp);
    }

    @Override
    public boolean removeChildJmxComponent(ChildRuntimeInfoComponent comp) {
        if (comp == null) {
            throw new IllegalArgumentException("Null ChildRuntimeInfoComponent");
        }
        return childRuntimeInfoComponents.remove(comp);
    }

    @Override
    public String createObjectHierarchyString() {
        return ADAPTER_PREFIX + getWrappedComponent().getUniqueId();
    }

    @Override
    public boolean addSharedConnection(String xmlString) throws CoreException, IllegalArgumentException {
        ensureState(ClosedState.getInstance());
        AdaptrisConnection comp = (AdaptrisConnection) DefaultMarshaller.getDefaultMarshaller()
                .unmarshal(xmlString);
        boolean result = getWrappedComponent().getSharedComponents().addConnection(comp);
        if (result) {
            marshalAndSendNotification();
        }
        return result;
    }

    @Override
    public boolean addAndBindSharedConnection(String xmlString) throws CoreException, IllegalStateException {
        ensureState(StartedState.getInstance(), InitialisedState.getInstance(), StoppedState.getInstance());
        AdaptrisConnection comp = (AdaptrisConnection) DefaultMarshaller.getDefaultMarshaller()
                .unmarshal(xmlString);
        boolean result = getWrappedComponent().getSharedComponents().addConnection(comp);
        if (result) {
            getWrappedComponent().getSharedComponents().bindJNDI(comp.getUniqueId());
            marshalAndSendNotification();
        }
        return result;
    }

    @Override
    public boolean removeSharedConnection(String connectionId) throws CoreException, IllegalStateException {
        ensureState(ClosedState.getInstance());
        Collection<AdaptrisConnection> c = getWrappedComponent().getSharedComponents()
                .removeConnection(connectionId);
        boolean result = c.size() > 0;
        if (result) {
            marshalAndSendNotification();
        }
        return result;
    }

    @Override
    public boolean containsSharedConnection(String connectionId) throws CoreException {
        return getWrappedComponent().getSharedComponents().containsConnection(connectionId);
    }

    @Override
    public Collection<String> getSharedConnectionIds() throws CoreException {
        return getWrappedComponent().getSharedComponents().getConnectionIds();
    }

    @Override
    public boolean addSharedService(String xmlString)
            throws CoreException, IllegalStateException, IllegalArgumentException {
        ensureState(ClosedState.getInstance());
        Service comp = (Service) DefaultMarshaller.getDefaultMarshaller().unmarshal(xmlString);
        boolean result = getWrappedComponent().getSharedComponents().addService(comp);
        if (result) {
            marshalAndSendNotification();
        }
        return result;
    }

    @Override
    public boolean addAndBindSharedService(String xmlString)
            throws CoreException, IllegalStateException, IllegalArgumentException {
        ensureState(StartedState.getInstance(), InitialisedState.getInstance(), StoppedState.getInstance());
        Service comp = (Service) DefaultMarshaller.getDefaultMarshaller().unmarshal(xmlString);
        boolean result = getWrappedComponent().getSharedComponents().addService(comp);
        if (result) {
            getWrappedComponent().getSharedComponents().bindJNDI(comp.getUniqueId());
            marshalAndSendNotification();
        }
        return result;
    }

    @Override
    public boolean removeSharedService(String serviceId) throws CoreException, IllegalStateException {
        ensureState(ClosedState.getInstance());
        Collection<Service> c = getWrappedComponent().getSharedComponents().removeService(serviceId);
        boolean result = c.size() > 0;
        if (result) {
            marshalAndSendNotification();
        }
        return result;
    }

    @Override
    public boolean containsSharedService(String serviceId) throws CoreException {
        return getWrappedComponent().getSharedComponents().containsService(serviceId);
    }

    @Override
    public Collection<String> getSharedServiceIds() throws CoreException {
        return getWrappedComponent().getSharedComponents().getServiceIds();
    }

    @Override
    public boolean removeSharedComponent(String id) throws CoreException, IllegalStateException {
        return removeSharedConnection(id) || removeSharedService(id);
    }

    @Override
    public ObjectName addChannel(String xml) throws CoreException, MalformedObjectNameException {
        // ensureState(ClosedState.getInstance());
        Channel newChannel = (Channel) DefaultMarshaller.getDefaultMarshaller().unmarshal(xml);
        ChannelManager channelManager = new ChannelManager(newChannel, this);
        // We don't need to "store" the XML at this point, as channelManager will eventually call
        // addChild() and that's when that happens.
        channelManager.registerMBean();
        return channelManager.createObjectName();
    }

    private ChannelRuntimeManager findChannelManager(String id) {
        ChannelRuntimeManager found = null;
        for (ChannelRuntimeManager mgr : channelManagers) {
            if (id.equals(mgr.getUniqueId())) {
                found = mgr;
                break;
            }
        }
        return found;
    }

    @Override
    public boolean removeChannel(String id) throws CoreException, MalformedObjectNameException {
        boolean removed = false;
        // ensureState(ClosedState.getInstance());
        if (!isEmpty(id)) {
            ChannelRuntimeManager toBeRemoved = findChannelManager(id);
            if (toBeRemoved != null) {
                removed = removeChannelManager(toBeRemoved, true);
            }
        }
        return removed;
    }

    @Override
    public void setMessageErrorHandler(String xml) throws CoreException {
        ensureState(ClosedState.getInstance());
        ProcessingExceptionHandler obj = (ProcessingExceptionHandler) DefaultMarshaller.getDefaultMarshaller()
                .unmarshal(xml);
        obj.prepare();
        getWrappedComponent().setMessageErrorHandler(obj);
        registerChildRuntime(obj);
        marshalAndSendNotification();

    }

    @Override
    public void setFailedMessageRetrier(String xml) throws CoreException {
        ensureState(ClosedState.getInstance());
        FailedMessageRetrier obj = (FailedMessageRetrier) DefaultMarshaller.getDefaultMarshaller().unmarshal(xml);
        obj.prepare();
        getWrappedComponent().setFailedMessageRetrier(obj);
        registerChildRuntime(obj);
        marshalAndSendNotification();

    }

    @Override
    public void registerMBean() throws CoreException {
        registerSelf();
        for (ChannelRuntimeManager c : channelManagers) {
            c.registerMBean();
        }
        for (ChildRuntimeInfoComponent cmb : childRuntimeInfoComponents) {
            cmb.registerMBean();
        }
    }

    @Override
    public void unregisterMBean() throws CoreException {
        unregisterSelf();
        for (ChannelRuntimeManager c : channelManagers) {
            c.unregisterMBean();
        }
        for (ChildRuntimeInfoComponent cmb : childRuntimeInfoComponents) {
            cmb.unregisterMBean();
        }
    }

    @Override
    public void childUpdated() throws CoreException {
        marshalAndSendNotification();

    }

    @Override
    public String getAdapterBuildVersion() {
        return adapterBuildVersion;
    }

    @Override
    public List<String> getModuleVersions() {
        return new ArrayList<String>(adapterModules);
    }

    @Override
    public List<String> getArtifactIdentifiers() {
        return new ArrayList<String>(adapterArtifacts);
    }

    @Override
    public void sendLifecycleEvent(AdapterLifecycleEvent event) throws CoreException {
        event.setAdapterUniqueId(adapter.getUniqueId());
        if (StartedState.getInstance().equals(adapter.getEventHandler().retrieveComponentState())) {
            adapter.getEventHandler().send(event);
        } else {
            log.info("Event Handler stopped; ignoring request to send {}", event.getClass().getSimpleName());
        }
    }

    @Override
    public MBeanNotificationInfo[] getNotificationInfo() {
        MBeanNotificationInfo adapterLifecycle = new MBeanNotificationInfo(
                new String[] { NOTIF_TYPE_ADAPTER_LIFECYCLE, NOTIF_TYPE_ADAPTER_CONFIG },
                Notification.class.getName(), "Adapter Notifications");

        return new MBeanNotificationInfo[] { adapterLifecycle };
    }

    @Override
    protected String getNotificationType(ComponentNotificationType type) {
        String result = null;
        switch (type) {
        case LIFECYCLE: {
            result = NOTIF_TYPE_ADAPTER_LIFECYCLE;
            break;
        }
        case CONFIG: {
            result = NOTIF_TYPE_ADAPTER_CONFIG;
            break;
        }
        default:
        }
        return result;
    }

    @Override
    public void forceClose() throws CoreException {
        sendNotification(createLifecycleNotification(NOTIF_MSG_FORCE_CLOSE, myObjectName));
        log.trace("Force Close on {}", myObjectName);
        // TODO : This is probably quite bad, but once we move to having our own class loader each adapter should have
        // their own static instance of MTF so we aren't interrupting all threads globally...
        ManagedThreadFactory.interruptManagedThreads();
        super.requestClose();
    }
}