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