package sample.manager;

 

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.net.HttpURLConnection;

import java.net.URL;

 

import javax.swing.Icon;

 

import com.lightysoft.logmx.business.LogURL;

import com.lightysoft.logmx.business.LogURLParameter;

import com.lightysoft.logmx.business.LogURLParameterType;

import com.lightysoft.logmx.mgr.AutoRefreshLineInfo;

import com.lightysoft.logmx.mgr.LogFileManager;

import com.lightysoft.logmx.mgr.ManagerSpecVersion;

 

/**

 * Sample Log file Manager handling HTTP protocol.

 *

 * Please visit http://www.logmx.com/p_manager_dev.php to get more

 * information on how to write Managers.

 *

 * You can use LogMX API Javadoc located in the "help/api/" directory

 * of your LogMX distribution.

 */

public class SampleHTTPManager extends LogFileManager {

    private String host = null;

 

    private String file = null;

 

    private int port = 0;

 

    private BufferedReader bufReader = null;

 

    private HttpURLConnection httpConnection = null;

 

    private String url = null;

 

    private long currFileDate = 0;

 

    private int currFileSize = 0;

 

    private static LogURL logURL = null;

 

    private static final String NAME = "Sample HTTP file manager";

 

    private static final String PROTOCOL = "http";

 

    private static final String URL_PARAM_HOST = "Host";

 

    private static final String URL_PARAM_PORT = "Port";

 

    private static final String URL_PARAM_FILE = "File";

 

    private static final int DEFAULT_PORT = 80;

 

    private static final String URL_PATTERN = PROTOCOL + "://{" + URL_PARAM_HOST + "}[:{"

            + URL_PARAM_PORT + "}][/{" + URL_PARAM_FILE + "}]";

 

    private static final Icon FILE_TYPE_ICON = getIconFile("gfx_http_file.png");

 

 

    /**

     * Called by LogMX to get the name of this Manager.

     * This name can contain any character and is displayed in LogMX GUI.

     *

     * @return

     *      Manager name

     */

    public String getName() {

        return NAME;

    }

 

    /**

     * Called by LogMX to get a template of <code>LogURL</code> used by this Manager.<BR/>

     *

     * <BR/>

     * The returned <code>LogURL</code> can (should) be a static shared instance for better performance.

     * LogMX will not use it directly but will use a clone of it.

     *

     * @return

     *      <code>LogURL</code> used by this Manager

     */

    public LogURL getTemplateLogURL() {

        if (logURL == null) {

            logURL = new LogURL();

            logURL.addParameter(new LogURLParameter(URL_PARAM_HOST, LogURLParameterType.HOST));

            logURL.addParameter(new LogURLParameter(URL_PARAM_PORT, LogURLParameterType.INTEGER,

                DEFAULT_PORT, true));

            logURL.addParameter(new LogURLParameter(URL_PARAM_FILE, LogURLParameterType.FILEPATH,

                null, true)); // optional param to allow URLs like "http://www.logmx.com"

        }

        return logURL;

    }

 

    /**

     * Called by LogMX to know how to display a URL handled by this Manager.

     * The syntax is:

     * <UL>

     *   <LI><code>SimpleText</code> to denote text <code>"SimpleText"</code></LI>

     *   <LI><code>{MyParam}</code> to denote the value of {@link com.lightysoft.logmx.business.LogURLParameter} named <code>"MyParam"</code></LI>

     *   <LI><code>[SimpleOptionalPart]</code> to denote an optional part containing free text, <code>LogURLParameter</code> value, or both.</LI>

     * </UL>

     * <BR/>

     * Here are a few examples of patterns this method can return and URLs matching this pattern:<BR/>

     * <UL>

     *   <LI><code>scp://{Login}@{Host}:[{Port}:]{File}</code></LI>

     *      <UL>

     *         <LI><code>scp://john@myhost:22:/mydir/myfile.log</code></LI>

     *         <LI><code>scp://john@myhost:/myfile.log</code></LI>

     *      </UL>

     *   <LI><code>http://{Host}[:{Port}][/{File}]</code></LI>

     *      <UL>

     *         <LI><code>http://www.logmx.com:80/myscript.php?p=4</code></LI>

     *         <LI><code>http://www.logmx.com:80/mypage.html</code></LI>

     *         <LI><code>http://www.logmx.com</code></LI>

     *      </UL>

     * </UL>

     *

     * @return

     *      URL Pattern used by this Manager

     */

    public String getURLPattern() {

        return URL_PATTERN;

    }

 

    /**

     * Called by LogMX to initialize the Manager for the specified resource.<BR/>

     * This method shouldn't try to open the resource yet, but should only save URL parameters

     * for further use.

     *

     * @param pLogURL

     *      LogURL for the resource this Manager will have to open

     * @param pURLString

     *      String representation for this URL (may be helpful for the Manager, especially to implement

     *      {@link com.lightysoft.logmx.mgr.LogFileManager#getCurrentURL()}

     * @throws Exception

     *      If the Manager is not able to process this URL

     */

    public void init(LogURL pLogURL, String pURLString) throws Exception {

        LogURLParameter hostParam = pLogURL.getParameter(URL_PARAM_HOST);

        LogURLParameter fileParam = pLogURL.getParameter(URL_PARAM_FILE);

        LogURLParameter portParam = pLogURL.getParameter(URL_PARAM_PORT);

 

        host = hostParam.getValue().toString();

        file = (fileParam.getValue() == null) ? "/" : fileParam.getValue().toString();

        port = (portParam.getValue() == null) ? DEFAULT_PORT : (Integer) portParam.getValue();

        url = pURLString;

 

        // If file path is not empty but doesn't start with "/", add this slash

        if (!file.equals("") && !file.startsWith("/")) {

            file = "/" + file;

        }

    }

 

    /**

     * Open the resource specified by {@link com.lightysoft.logmx.mgr.LogFileManager#init(LogURL, String)} to get ready

     * to read, and return the number of bytes that will be read.<BR/>

     * If the Manager is not able to get the number of bytes to read, it can return a negative number.

     * As this number is used to display a progress bar while the Manager is loading the resource, returning a

     * negative number will make the progress bar stays at "100%" all the time.

     * 

     * @return

     *      Number of bytes to read, or -1 if Manager is not able to find out.

     * @throws Exception

     *      If the resource couldn't be opened (this Exception message will be displayed in LogMX GUI)

     */

    public long prepareForReading() throws Exception {

        // Initialize HTTP connection

        URL url = new URL(PROTOCOL, host, port, file);

        httpConnection = (HttpURLConnection) url.openConnection();

 

        // Getting file size/date from HTTP headers

        currFileSize = httpConnection.getContentLength();

        currFileDate = httpConnection.getLastModified();

 

        // Creating a buffered reader for this stream, using the Encoding specified by LogMX

        bufReader = new BufferedReader(new InputStreamReader(url.openStream(), getEncoding()));

 

        return currFileSize;

    }

 

    /**

     * Called by LogMX to get the next line of text from the underlying Manager resource (file, stream, socket,...).<BR/>

     * Manager must return <B><code>null</code></B> if there is no more byte to read.

     *

     * @return

     *      Next line, or <B><code>null</code></B> if there is no more byte to read.

     * @throws Exception

     *      If an error occurred while reading bytes. Managers should not handle Exceptions but should

     *      throw them instead, so that LogMX can catch them.

     */

    public String readLine() throws Exception {

        return bufReader.readLine();

    }

 

    /**

     * Called by LogMX to get the current opened URL, matching this Manager URL template.<BR/>

     * This method may return the URL string received by {@link com.lightysoft.logmx.mgr.LogFileManager#init(LogURL, String)},

     * or use {@link com.lightysoft.logmx.mgr.LogFileManager#getURLFromLogURL(LogURL, String)} to construct the URL.

     *

     * @return

     *      Current opened URL

     */

    public String getCurrentURL() {

        return url;

    }

 

    /**

     * Called by LogMX to know when the opened resource was modified for the last time.<BR/>

     * The expected result is a standard Java timestamp (number of milliseconds since 01/01/1970, 00:00:00 GMT).

     * For example, if you have a Java Date, you can get such a timestamp using {@link java.util.Date#getTime()}.<BR/>

     * <BR/>

     * <B>This method may be called periodically, so it should be rather fast (e.g. no socket connection, but fast I/O operations).</B><BR/>

     * <BR/>

     * If the Manager is not able to get this timestamp, it may return 0, but file-change detection will be affected.

     * 

     * @return

     *      A Java-based timestamp of last modification, or 0 if Manager can't get this timestamp

     */

    public long getCurrentFileLastModifDate() {

        return currFileDate;

    }

 

    /**

     * Called by LogMX to get the current resource size in bytes.<BR/>

     * <BR/>

     * <B>This method may be called periodically, so it should be rather fast (e.g. no socket connection, but fast I/O operations).</B><BR/>

     * <BR/>

     * If the Manager is not able to get this timestamp, it may return 0, but file-change detection will be affected.

     * 

     * @return

     *      Current resource size in bytes, or 0 if Manager can't get this size

     */

    public long getCurrentFileSize() {

        return currFileSize;

    }

 

    /**

     * Called by LogMX to get this Manager icon, which must be a 16x16 icon.<BR/>

     * Manager may use {@link com.lightysoft.logmx.mgr.LogFileManager#getIconFile(String)} to get an icon file

     * contained in LogMX pictures directory, in order to avoid relative file path issues.<BR/>

     * This icon may (should) be cached, the same instance may be returned for each call for better performances.<BR/>

     * If <code>null</code> is returned, a default icon will be used.

     * 

     * @return

     *      Manager icon, or <code>null</code> to use a default icon.

     */

    public Icon getFileTypeIcon() {

        return FILE_TYPE_ICON;

    }

 

    /**

     * Called by LogMX to get the Protocol handled by this Manager.<BR>

     * This protocol can be any string, like "http", "jdbc", "ftp", "myprotocol", ...<BR>

     * LogMX will use it to find the Manager to use for a given a URL (eg: "jdbc:oracle:thin:@host:1521:db")

     *

     * @return

     *      Protocol handled by this Manager

     */

    public String getProtocolName() {

        return PROTOCOL;

    }

 

    /**

     * Called by LogMX when it doesn't need to use this Manager anymore.<BR/>

     * This method should release all resources allocated by this Manager (e.g. close file, socket,...)<BR/>

     * Once this method is called, LogMX won't call <code>readLine()</code>.<BR/>

     */

    public void releaseResources() {

        if (bufReader != null) {

            try {

                bufReader.close();

            } catch (IOException e) {

                // doesn't mind

                e.printStackTrace();

            }

        }

        httpConnection.disconnect();

    }

 

    /**

     * Called by LogMX to get the Manager Specification version supported by this Manager.

     * For example, this method can return <code>ManagerSpecVersion.V1_0</code>

     *  

     * @return

     *      Supported Manager Specification version

     */

    public ManagerSpecVersion getSpecificationVersion() {

        return ManagerSpecVersion.V1_0;

    }

 

    /**

     * Called by LogMX to know if this Manger can delete (i.e. remove from disk) the current file.<BR/>

     * If <code>false</code> is returned, LogMX will not call {@link com.lightysoft.logmx.mgr.LogFileManager#deleteFile()}

     *

     * @return

     *      <code>true</code> if this Manager can delete the current file, or <code>false</code> if it can't.

     */

    public boolean supportFileDelete() {

        return false;

    }

 

    /**

     * Called by LogMX to know if this Manger can flush (i.e. empty) the current file.<BR/>

     * If <code>false</code> is returned, LogMX will not call {@link com.lightysoft.logmx.mgr.LogFileManager#flushFile()}

     *

     * @return

     *      <code>true</code> if this Manager can flush the current file, or <code>false</code> if it can't.

     */

    public boolean supportFileFlush() {

        return false;

    }

 

    /**

     * Called by LogMX to know if this Manager support header reading (read a specified number of bytes from the beginning of the file).<BR/>

     * Used for Auto Refresh and Auto detect encoding features.

     * If <code>false</code> is returned, LogMX will not call {@link com.lightysoft.logmx.mgr.LogFileManager#readFileHeader(int)}

     *

     * @return

     *      <code>true</code> if this Manager support header reading, or <code>false</code> if it doesn't.

     */

    public boolean supportHeaderReading() {

        return false;

    }

 

    /**

     * Called by LogMX to know if this Manager support random access (read bytes starting at a specified offset).<BR/>

     * Used for Auto Refresh feature only.

     * If <code>false</code> is returned, LogMX will not call {@link com.lightysoft.logmx.mgr.LogFileManager#readLineAtOffset(long)}

     *

     * @return

     *      <code>true</code> if this Manager support random access, or <code>false</code> if it doesn't.

     */

    public boolean supportRandomAccess() {

        return false;

    }

 

    /**

     * Called by LogMX to delete (i.e. remove from disk) the current file.<BR/>

     * If this Manager doesn't support this feature ({@link com.lightysoft.logmx.mgr.LogFileManager#supportFileDelete()}

     * returns <code>false</code>), this method may only contain "<code>return false;</code>".

     *

     * @return

     *      <code>true</code> if deletion succeeded, or <code>false</code> it didn't.

     */

    public boolean deleteFile() {

        // Unsupported operation

        return false;

    }

 

    /**

     * Called by LogMX to flush (i.e. empty) the current file.<BR/>

     * If this Manager doesn't support this feature ({@link com.lightysoft.logmx.mgr.LogFileManager#supportFileFlush()}

     * returns <code>false</code>), this method may only contain "<code>return false;</code>".

     *

     * @return

     *      <code>true</code> if flush succeeded, or <code>false</code> it didn't.

     */

    public boolean flushFile() {

        // Unsupported operation

        return false;

    }

 

    /**

     * Called by LogMX to read the first <code>pNbBytes</code> bytes from the underlying file or resource.<BR/>

     * Only Managers supporting Auto Refresh must implement this method, others should return <code>null</code>.

     * 

     * @param pNbBytes

     *      Number of bytes to read. <B>If negative, Manager must read as much bytes as possible</B>

     *      (for example, up to the end of file)

     * @return

     *      Read bytes, or <code>null</code> if Manager doesn't support header reading

     * @throws Exception

     *      If Manager could not read bytes

     */

    public byte[] readFileHeader(int pNbBytes) throws Exception {

        // Unsupported operation

        return null;

    }

 

    /**

     * Called by LogMX to read the line of text starting at the specified offset.<BR/>

     * Only Managers supporting Auto Refresh must implement this method, others should return <code>null</code>.

     *

     * @param pOffset

     *      Starting offset

     * @return

     *      Information on read line (text and EOF flag), or <code>null</code> if Manager doesn't support header reading

     * @throws Exception

     *      If Manager could not read bytes

     */

    public AutoRefreshLineInfo readLineAtOffset(long pOffset) throws Exception {

        // Unsupported operation

        return null;

    }

 

    /**

     * Called by LogMX to know the current position in file.<BR/>

     * Only Managers supporting Auto Refresh must implement this method, others should return 0.

     *

     * @return

     *      Current offset in file

     * @throws Exception

     *      If Manager couldn't retrieve current offset

     */

    public long getCurrentOffset() throws Exception {

        // Unsupported operation

        return 0;

    }

 

}