Package net.xeoh.plugins.diagnosis.local.impl

Source Code of net.xeoh.plugins.diagnosis.local.impl.DiagnosisImpl

/*
* DiagnosisImpl.java
*
* Copyright (c) 2011, Ralf Biedert All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of the author nor the names of its contributors may be used to endorse or
* promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package net.xeoh.plugins.diagnosis.local.impl;

import static net.jcores.jre.CoreKeeper.$;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import net.xeoh.plugins.base.PluginConfiguration;
import net.xeoh.plugins.base.annotations.PluginImplementation;
import net.xeoh.plugins.base.annotations.events.Shutdown;
import net.xeoh.plugins.base.util.PluginConfigurationUtil;
import net.xeoh.plugins.diagnosis.local.Diagnosis;
import net.xeoh.plugins.diagnosis.local.DiagnosisChannel;
import net.xeoh.plugins.diagnosis.local.DiagnosisChannelID;
import net.xeoh.plugins.diagnosis.local.DiagnosisMonitor;
import net.xeoh.plugins.diagnosis.local.DiagnosisStatus;
import net.xeoh.plugins.diagnosis.local.impl.serialization.java.Entry;
import net.xeoh.plugins.diagnosis.local.impl.serialization.java.EntryCallback;
import net.xeoh.plugins.diagnosis.local.impl.serialization.java.LogFileReader;
import net.xeoh.plugins.diagnosis.local.impl.serialization.java.LogFileWriter;
import net.xeoh.plugins.diagnosis.local.options.ChannelOption;
import net.xeoh.plugins.diagnosis.local.options.status.OptionInfo;

@PluginImplementation
public class DiagnosisImpl implements Diagnosis {
    /** Stores information on a key */
    class KeyEntry {
        /** Locks access to this item */
        final Lock entryLock = new ReentrantLock();

        /** All listeners subscribed to this item */
        final Collection<DiagnosisMonitor<?>> allListeners = new ArrayList<DiagnosisMonitor<?>>();

        /** The current channel holder */
        DiagnosisStatus<?> lastItem = null;
    }

    /** Manages all information regarding a key */
    final Map<Class<? extends DiagnosisChannelID<?>>, KeyEntry> items = new ConcurrentHashMap<Class<? extends DiagnosisChannelID<?>>, KeyEntry>();

    /** Plugin configuration (will be injected manually by the PluginManager) */
    public PluginConfiguration configuration;

    /** If true, the whole plugin will be disabled */
    boolean isDisabled = false;

    /** If true, if we should dump stack traces */
    boolean useStackTraces = false;

    /** If we should compress our output */
    boolean compressOutput = true;

    /** Depth of stack traces */
    int stackTracesDepth = 1;

    /** The file to which we record to */
    String recordingFile = null;

    /** The actual serializer we use */
    volatile LogFileWriter serializer = null;

    /** If recording should be enabled */
    boolean recordingEnabled = false;

    /*
     * (non-Javadoc)
     *
     * @see net.xeoh.plugins.diagnosis.local.Diagnosis#channel(java.lang.Class,
     * net.xeoh.plugins.diagnosis.local.options.ChannelOption[])
     */
    @SuppressWarnings("unchecked")
    @Override
    public <T extends Serializable> DiagnosisChannel<T> channel(Class<? extends DiagnosisChannelID<T>> channel,
                                                                ChannelOption... options) {
        // In case we are disabled, return a dummy
        if (this.isDisabled) {
            final DiagnosisChannel<?> impl = new DiagnosisChannelDummyImpl(this, channel);
            return (DiagnosisChannel<T>) impl;
        }

        // In case this was the first call, create a serializer
        synchronized (this) {
            if (this.serializer == null && this.recordingEnabled) {
                this.serializer = createWriter();
            }
        }

        final DiagnosisChannel<?> impl = new DiagnosisChannelImpl(this, channel);
        return (DiagnosisChannel<T>) impl;
    }

   
    /**
     * Try to create a write for our logging data.
     *
     * @return
     */
    LogFileWriter createWriter() {
        // First try to return a writer with the given name
        try {
            return new LogFileWriter(this.recordingFile, this.compressOutput);
        } catch (Exception e) {}

        // First try to return a writer with some time stamp attached (in case the old one was not overwritable)
        try {
            return new LogFileWriter(this.recordingFile + "." + System.currentTimeMillis(), this.compressOutput);
        } catch (Exception e) {}

        // Now we are out of luck
        return null;
    }

    /**
     * Stores the given entry to our record file
     *
     * @param status
     * @param entry
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public void recordEntry(DiagnosisStatus<?> status, Entry entry) {
        if (this.serializer != null)
            this.serializer.record(entry);

        final KeyEntry keyEntry = getKeyEntry(status.getChannel());


       
        // Now process entry
        try {
            keyEntry.entryLock.lock();
            keyEntry.lastItem = status;

           
            // Check if we should publish silently.
            for (DiagnosisMonitor<?> listener : keyEntry.allListeners) {
                try {
                    ((DiagnosisMonitor<?>) listener).onStatusChange((DiagnosisStatus) status);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } finally {
            keyEntry.entryLock.unlock();
        }
    }

    /** Opens all required streams */
    @SuppressWarnings("boxing")
    // This MUST NOT be tagged with @Init, as it will be executed manually by the PluginManager.
    public void init() {
        final PluginConfigurationUtil util = new PluginConfigurationUtil(this.configuration);

        this.isDisabled = !util.getBoolean(Diagnosis.class, "general.enabled", true);
        this.recordingEnabled = util.getBoolean(Diagnosis.class, "recording.enabled", false);
        this.recordingFile = util.getString(Diagnosis.class, "recording.file", "diagnosis.record");
        this.useStackTraces = util.getBoolean(Diagnosis.class, "analysis.stacktraces.enabled", false);
        this.stackTracesDepth = util.getInt(Diagnosis.class, "analysis.stacktraces.depth", 1);

        String mode = util.getString(Diagnosis.class, "recording.format", "java/serialization/gzip");
        if ("java/serialization/gzip".equals(mode)) {
            this.compressOutput = true;
        }

        if ("java/serialization".equals(mode)) {
            this.compressOutput = false;
        }

    }

    /** Close the log file */
    @Shutdown
    public void shutdown() {
        // TODO
        // this.serializer...()
    }

    /*
     * (non-Javadoc)
     *
     * @see net.xeoh.plugins.diagnosis.local.Diagnosis#registerListener(java.lang.Class,
     * net.xeoh.plugins.diagnosis.local.DiagnosisListener)
     */
    @SuppressWarnings("unchecked")
    @Override
    public <T extends Serializable> void registerMonitor(Class<? extends DiagnosisChannelID<T>> channel,
                                                          DiagnosisMonitor<T> listener) {
        if (channel == null || listener == null) return;

        // Get the meta information for the requested id
        final KeyEntry keyEntry = getKeyEntry(channel);

       
        // Now process and add the entry
        try {
            keyEntry.entryLock.lock();
            // If there has been a channel established, use that one
            if (keyEntry.lastItem != null) {
                try {
                    listener.onStatusChange((DiagnosisStatus<T>) keyEntry.lastItem);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            keyEntry.allListeners.add(listener);
        } finally {
            keyEntry.entryLock.unlock();
        }
    }

    /**
     * Returns the key entry of a given ID.
     *
     * @param id The ID to request
     * @return The key entry.
     */
    private KeyEntry getKeyEntry(Class<? extends DiagnosisChannelID<?>> id) {
        KeyEntry keyEntry = null;
       
        synchronized (this.items) {
            keyEntry = this.items.get(id);
            if (keyEntry == null) {
                keyEntry = new KeyEntry();
                this.items.put(id, keyEntry);
            }
        }

        return keyEntry;
    }

    /*
     * (non-Javadoc)
     *
     * @see net.xeoh.plugins.diagnosis.local.Diagnosis#replay(java.lang.String,
     * net.xeoh.plugins.diagnosis.local.DiagnosisMonitor)
     */
    @Override
    public void replay(final String file, final DiagnosisMonitor<?> listener) {
        final LogFileReader reader = new LogFileReader(file);
        reader.replay(new EntryCallback() {
            @SuppressWarnings({ "rawtypes", "unchecked" })
            @Override
            public void nextEntry(Entry entry) {
                // Convert the entry to a status events
                final List<OptionInfo> infos = new ArrayList<OptionInfo>();
                for (String value : entry.additionalInfo.keySet()) {
                    infos.add(new OptionInfo(value, (Serializable) entry.additionalInfo.get(value)));
                }

                final DiagnosisStatusImpl<?> event = new DiagnosisStatusImpl(entry.channel, (Serializable) entry.value, entry.date, $(infos).array(OptionInfo.class));
                listener.onStatusChange((DiagnosisStatus) event);
            }
        });
    }
}
TOP

Related Classes of net.xeoh.plugins.diagnosis.local.impl.DiagnosisImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.