001/*
002 * (C) Copyright 2012-2017 Nuxeo (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Florent Guillaume
018 */
019package org.nuxeo.ecm.core.management.jtajca.internal;
020
021import java.util.HashMap;
022import java.util.Map;
023
024import javax.management.InstanceAlreadyExistsException;
025import javax.management.InstanceNotFoundException;
026import javax.management.MBeanRegistrationException;
027import javax.management.MBeanServer;
028import javax.management.MalformedObjectNameException;
029import javax.management.NotCompliantMBeanException;
030import javax.management.ObjectInstance;
031import javax.management.ObjectName;
032
033import org.apache.commons.logging.Log;
034import org.apache.commons.logging.LogFactory;
035import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
036import org.nuxeo.ecm.core.management.jtajca.ConnectionPoolMonitor;
037import org.nuxeo.ecm.core.management.jtajca.CoreSessionMonitor;
038import org.nuxeo.ecm.core.management.jtajca.Defaults;
039import org.nuxeo.ecm.core.management.jtajca.TransactionMonitor;
040import org.nuxeo.ecm.core.repository.RepositoryService;
041import org.nuxeo.runtime.api.Framework;
042import org.nuxeo.runtime.management.ServerLocator;
043import org.nuxeo.runtime.metrics.MetricsService;
044import org.nuxeo.runtime.model.Component;
045import org.nuxeo.runtime.model.ComponentContext;
046import org.nuxeo.runtime.model.DefaultComponent;
047
048/**
049 * Component used to install/uninstall the monitors (transaction and connections).
050 *
051 * @since 5.6
052 */
053public class DefaultMonitorComponent extends DefaultComponent {
054
055    protected final Log log = LogFactory.getLog(DefaultMonitorComponent.class);
056
057    protected CoreSessionMonitor coreSessionMonitor;
058
059    protected TransactionMonitor transactionMonitor;
060
061    protected Map<String, ConnectionPoolMonitor> poolConnectionMonitors = new HashMap<>();
062
063    @Override
064    public void start(ComponentContext context) {
065        RepositoryService repositoryService = Framework.getService(RepositoryService.class);
066        if (repositoryService == null) {
067            // RepositoryService failed to start, no need to go further
068            return;
069        }
070        uninstall();
071        install();
072    }
073
074    @Override
075    public int getApplicationStartedOrder() {
076        // should deploy after metrics service
077        Component component = (Component) Framework.getRuntime().getComponent(MetricsService.class.getName());
078        return component.getApplicationStartedOrder() + 1;
079    }
080
081    @Override
082    public void stop(ComponentContext context) {
083        uninstall();
084    }
085
086    protected boolean installed;
087
088    protected void install() {
089        installed = true;
090
091        coreSessionMonitor = new DefaultCoreSessionMonitor();
092        coreSessionMonitor.install();
093
094        transactionMonitor = new DefaultTransactionMonitor();
095        transactionMonitor.install();
096
097        RepositoryService repositoryService = Framework.getService(RepositoryService.class);
098        @SuppressWarnings("resource")
099        GenericKeyedObjectPool<String, ?> pool = repositoryService.getPool();
100        repositoryService.getRepositoryNames().forEach(repositoryName -> {
101            String name = "repository/" + repositoryName;
102            ConnectionPoolMonitor monitor = new ObjectPoolMonitor(name, pool, repositoryName);
103            monitor.install();
104            poolConnectionMonitors.put(name, monitor);
105        });
106    }
107
108    /**
109     * Does nothing.
110     *
111     * @deprecated since 11.1, unused
112     */
113    @Deprecated
114    protected void activateRepository(String repositoryName) {
115        // nothing
116    }
117
118    protected void uninstall() {
119        if (!installed) {
120            return;
121        }
122        // temporary log to help diagnostics
123        log.info("Total commits during server life: " + transactionMonitor.getTotalCommits());
124        installed = false;
125        for (ConnectionPoolMonitor storage : poolConnectionMonitors.values()) {
126            storage.uninstall();
127        }
128        coreSessionMonitor.uninstall();
129        transactionMonitor.uninstall();
130        poolConnectionMonitors.clear();
131        coreSessionMonitor = null;
132        transactionMonitor = null;
133    }
134
135    public static class ServerInstance {
136        public final MBeanServer server;
137
138        public final ObjectName name;
139
140        ServerInstance(MBeanServer server, ObjectName name) {
141            this.server = server;
142            this.name = name;
143        }
144    }
145
146    protected static ServerInstance bind(Object managed) {
147        return bind(managed, "default");
148    }
149
150    protected static ServerInstance bind(Class<?> itf, Object managed) {
151        return bind(itf, managed, "default");
152    }
153
154    protected static ServerInstance bind(Object managed, String name) {
155        return bind(managed.getClass().getInterfaces()[0], managed, name);
156    }
157
158    protected static ServerInstance bind(Class<?> itf, Object managed, String name) {
159        MBeanServer mbs = Framework.getService(ServerLocator.class).lookupServer();
160        name = Defaults.instance.name(itf, name);
161        try {
162            ObjectInstance oi = mbs.registerMBean(managed, new ObjectName(name));
163            return new ServerInstance(mbs, oi.getObjectName());
164        } catch (InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException
165                | MalformedObjectNameException e) {
166            throw new UnsupportedOperationException("Cannot bind " + managed + " on " + name, e);
167        }
168    }
169
170    protected static void unbind(ServerInstance instance) {
171        try {
172            instance.server.unregisterMBean(instance.name);
173        } catch (MBeanRegistrationException | InstanceNotFoundException e) {
174            LogFactory.getLog(DefaultMonitorComponent.class).error("Cannot unbind " + instance, e);
175        }
176    }
177
178}