001/*
002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     mcedica
011 */
012package org.nuxeo.ecm.core.management.probes;
013
014import java.util.Collection;
015import java.util.Collections;
016import java.util.Date;
017import java.util.HashMap;
018import java.util.HashSet;
019import java.util.Map;
020import java.util.Set;
021
022import org.apache.commons.logging.Log;
023import org.apache.commons.logging.LogFactory;
024import org.nuxeo.ecm.core.management.api.Probe;
025import org.nuxeo.ecm.core.management.api.ProbeInfo;
026import org.nuxeo.ecm.core.management.api.ProbeManager;
027import org.nuxeo.ecm.core.management.api.ProbeStatus;
028import org.nuxeo.runtime.management.ManagementRuntimeException;
029
030public class ProbeManagerImpl implements ProbeManager {
031
032    protected static final Log log = LogFactory.getLog(ProbeManagerImpl.class);
033
034    protected final Map<Class<? extends Probe>, ProbeInfo> infosByTypes = new HashMap<Class<? extends Probe>, ProbeInfo>();
035
036    protected final Map<String, ProbeInfo> infosByShortcuts = new HashMap<String, ProbeInfo>();
037
038    protected final Map<String, Probe> probesByShortcuts = new HashMap<String, Probe>();
039
040    protected final Set<ProbeInfo> failed = new HashSet<ProbeInfo>();
041
042    protected final Set<ProbeInfo> succeed = new HashSet<ProbeInfo>();
043
044    protected Set<String> doExtractProbesName(Collection<ProbeInfo> runners) {
045        Set<String> names = new HashSet<String>();
046        for (ProbeInfo runner : runners) {
047            names.add(runner.getShortcutName());
048        }
049        return names;
050    }
051
052    @Override
053    public Collection<ProbeInfo> getAllProbeInfos() {
054        return Collections.unmodifiableCollection(infosByTypes.values());
055    }
056
057    @Override
058    public Collection<ProbeInfo> getInSuccessProbeInfos() {
059        return Collections.unmodifiableCollection(succeed);
060    }
061
062    @Override
063    public Collection<ProbeInfo> getInFailureProbeInfos() {
064        return Collections.unmodifiableCollection(failed);
065    }
066
067    @Override
068    public Collection<String> getProbeNames() {
069        return infosByShortcuts.keySet();
070    }
071
072    @Override
073    public int getProbesCount() {
074        return infosByTypes.size();
075    }
076
077    @Override
078    public Collection<String> getProbesInError() {
079        return doExtractProbesName(failed);
080    }
081
082    @Override
083    public int getProbesInErrorCount() {
084        return failed.size();
085    }
086
087    @Override
088    public Collection<String> getProbesInSuccess() {
089        return doExtractProbesName(succeed);
090    }
091
092    @Override
093    public int getProbesInSuccessCount() {
094        return succeed.size();
095    }
096
097    @Override
098    public ProbeInfo getProbeInfo(Class<? extends Probe> probeClass) {
099        ProbeInfo info = infosByTypes.get(probeClass);
100        if (info == null) {
101            throw new IllegalArgumentException("no probe registered for " + probeClass);
102        }
103        return info;
104    }
105
106    @Override
107    public boolean runAllProbes() {
108        doRun();
109        return getProbesInErrorCount() <= 0;
110    }
111
112    @Override
113    public ProbeInfo runProbe(ProbeInfo probe) {
114        doRunProbe(probe);
115        return probe;
116    }
117
118    @Override
119    public ProbeInfo runProbe(String name) {
120        ProbeInfo probeInfo = getProbeInfo(name);
121        if (probeInfo == null) {
122            log.warn("Probe " + name + " can not be found");
123            return null;
124        }
125        return runProbe(probeInfo);
126    }
127
128    @Override
129    public ProbeInfo getProbeInfo(String name) {
130        return infosByShortcuts.get(name);
131    }
132
133    public void registerProbe(ProbeDescriptor descriptor) {
134        Class<? extends Probe> probeClass = descriptor.getProbeClass();
135        Probe probe;
136        try {
137            probe = probeClass.newInstance();
138        } catch (ReflectiveOperationException e) {
139            throw new ManagementRuntimeException("Cannot create management probe for " + descriptor);
140        }
141
142        ProbeInfoImpl info = new ProbeInfoImpl(descriptor);
143        infosByTypes.put(probeClass, info);
144        infosByShortcuts.put(descriptor.getShortcut(), info);
145        probesByShortcuts.put(descriptor.getShortcut(), probe);
146    }
147
148    public void unregisterProbe(ProbeDescriptor descriptor) {
149        Class<? extends Probe> probeClass = descriptor.getProbeClass();
150        infosByTypes.remove(probeClass);
151        infosByShortcuts.remove(descriptor.getShortcut());
152    }
153
154    protected void doRun() {
155        for (ProbeInfo probe : infosByTypes.values()) {
156            doRunProbe(probe);
157        }
158    }
159
160    protected static Long doGetDuration(Date fromDate, Date toDate) {
161        return toDate.getTime() - fromDate.getTime();
162    }
163
164    protected void doRunProbe(ProbeInfo probe) {
165        if (!probe.isEnabled()) {
166            return;
167        }
168        boolean ok = false;
169        try {
170            ProbeInfoImpl probeInfoImpl = (ProbeInfoImpl) probe;
171            Thread currentThread = Thread.currentThread();
172            ClassLoader lastLoader = currentThread.getContextClassLoader();
173            currentThread.setContextClassLoader(ProbeInfoImpl.class.getClassLoader());
174            probeInfoImpl.lastRunnedDate = new Date();
175            probeInfoImpl.runnedCount += 1;
176            try {
177                Probe runnableProbe = probesByShortcuts.get(probe.getShortcutName());
178                probeInfoImpl.lastStatus = runnableProbe.run();
179                if (probeInfoImpl.lastStatus.isSuccess()) {
180                    probeInfoImpl.lastSucceedDate = probeInfoImpl.lastRunnedDate;
181                    probeInfoImpl.lastSuccessStatus = probeInfoImpl.lastStatus;
182                    probeInfoImpl.successCount += 1;
183                } else {
184                    probeInfoImpl.lastFailureStatus = probeInfoImpl.lastStatus;
185                    probeInfoImpl.failureCount += 1;
186                    probeInfoImpl.lastFailureDate = probeInfoImpl.lastRunnedDate;
187                }
188            } catch (RuntimeException e) {
189                probeInfoImpl.failureCount += 1;
190                probeInfoImpl.lastFailureDate = new Date();
191                probeInfoImpl.lastFailureStatus = ProbeStatus.newError(e);
192                // then swallow exception
193            } finally {
194                probeInfoImpl.lastDuration = doGetDuration(probeInfoImpl.lastRunnedDate, new Date());
195                currentThread.setContextClassLoader(lastLoader);
196            }
197
198            if (probe.isInError()) {
199                succeed.remove(probe);
200                failed.add(probe);
201            } else {
202                failed.remove(probe);
203                succeed.add(probe);
204            }
205            ok = true;
206        } finally {
207            if (!ok) {
208                succeed.remove(probe);
209                failed.add(probe);
210            }
211        }
212    }
213
214}