diff --git a/vendor/JXInput/0.3.4/c/JXInputManager.cpp b/vendor/JXInput/0.3.4/c/JXInputManager.cpp
new file mode 100644
index 0000000..3718a7f
--- /dev/null
+++ b/vendor/JXInput/0.3.4/c/JXInputManager.cpp
@@ -0,0 +1,175 @@
+
+#include "stdafx.h"
+#include "JXInputManager.h"
+#include "JXInput.h"
+
+//
+// Globals
+//
+extern HINSTANCE g_hInst;
+
+
+JXInputManager::JXInputManager( HWND hWnd ) :
+mhWnd( hWnd ),
+mDeviceCounter( 0 )
+{
+
+ for ( int i = 0; i < MAX_JXINPUTS; ++i )
+ {
+ mDevices[ i ] = NULL;
+ }
+
+
+ if ( FAILED( InitDirectInput( hWnd ) ) )
+ {
+ FreeDirectInput();
+ }
+
+}
+
+JXInputManager::~JXInputManager()
+{
+ for ( int i = 0; i < getNumberOfJXInputs(); ++i )
+ {
+ delete mDevices[ i ];
+ mDevices[ i ] = NULL;
+ }
+
+ FreeDirectInput();
+}
+
+int JXInputManager::getNumberOfJXInputs() const
+{
+ return mDeviceCounter;
+}
+
+JXInput& JXInputManager::getJXInput( int idx ) const
+{
+ assert( idx < mDeviceCounter );
+ return * mDevices[ idx ];
+}
+
+
+int JXInputManager::getMaxNumberOfAxes() const
+{
+ return JXINPUT_MAX_AXES;
+}
+
+int JXInputManager::getMaxNumberOfButtons() const
+{
+ return JXINPUT_MAX_BUTTONS;
+}
+
+int JXInputManager::getMaxNumberOfDirectionals() const
+{
+ return JXINPUT_MAX_DIRECTIONALS;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Name: InitDirectInput()
+// Desc: Initialize the DirectInput variables.
+//-----------------------------------------------------------------------------
+HRESULT JXInputManager::InitDirectInput( HWND hWnd )
+{
+ HRESULT hr;
+
+ // Register with the DirectInput subsystem and get a pointer
+ // to a IDirectInput interface we can use.
+ // Create a DInput object
+ if( FAILED( hr = DirectInput8Create( g_hInst, DIRECTINPUT_VERSION,
+ IID_IDirectInput8, (VOID**)&mpDI, NULL ) ) )
+ return hr;
+
+ // Look for a simple joystick we can use for this sample program.
+ if( FAILED( hr = mpDI->EnumDevices( DI8DEVCLASS_GAMECTRL,
+ EnumJoysticksCallback,
+ (VOID*)this, DIEDFL_ALLDEVICES /*| DIEDFL_INCLUDEPHANTOMS*/ ) ) )
+ return hr;
+
+ // Look for a other devices
+ if( FAILED( hr = mpDI->EnumDevices( DI8DEVCLASS_DEVICE,
+ EnumJoysticksCallback,
+ (VOID*)this, DIEDFL_ALLDEVICES /*| DIEDFL_INCLUDEPHANTOMS*/ ) ) )
+ return hr;
+
+ return S_OK;
+}
+
+
+//-----------------------------------------------------------------------------
+// Name: FreeDirectInput()
+// Desc: Initialize the DirectInput variables.
+//-----------------------------------------------------------------------------
+HRESULT JXInputManager::FreeDirectInput()
+{
+
+ if ( NULL != mpDI )
+ mpDI->Release();
+ mpDI = NULL;
+ return S_OK;
+}
+
+
+//-----------------------------------------------------------------------------
+// Name: EnumJoysticksCallback()
+// Desc: Called once for each enumerated joystick. If we find one, create a
+// device interface on it so we can play with it.
+//-----------------------------------------------------------------------------
+BOOL CALLBACK JXInputManager::EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance,
+ VOID* pContext )
+{
+ HRESULT hr;
+ LPDIRECTINPUTDEVICE8 pJoystick;
+
+ JXInputManager* pThis = (JXInputManager*)pContext;
+
+ //
+ // if the maximum number of devices is already registered,
+ // issue a warning and stop enumeration.
+ //
+ if( MAX_JXINPUTS == pThis->mDeviceCounter )
+ {
+ OutputDebugString( "Max. number of devices exceeded!" );
+ return DIENUM_STOP;
+ }
+
+
+
+ // Obtain an interface to the enumerated joystick.
+ hr = pThis->mpDI->CreateDevice( pdidInstance->guidInstance, &pJoystick, NULL );
+
+ // If it failed, then we can't use this joystick. (Maybe the user unplugged
+ // it while we were in the middle of enumerating it.)
+ if( FAILED(hr) )
+ return DIENUM_CONTINUE;
+
+ JXInput* pJ = new JXInput( pJoystick, pThis->mhWnd );
+
+ //
+ // only register useful devices
+ //
+ if( pJ->getNumberOfAxes() + pJ->getNumberOfButtons() + pJ->getNumberOfDirectionals() > 0 )
+ {
+ pThis->addJXInput( pJ );
+ }
+ else
+ {
+ delete pJ;
+ }
+
+ return DIENUM_CONTINUE;
+}
+
+
+/**
+ * Register a JXInput device.
+ */
+void JXInputManager::addJXInput( JXInput* pJ )
+{
+ assert( mDeviceCounter < MAX_JXINPUTS );
+
+ if( mDeviceCounter < MAX_JXINPUTS )
+ mDevices[ mDeviceCounter++ ] = pJ;
+}
diff --git a/vendor/JXInput/0.3.4/c/JXInputManager.h b/vendor/JXInput/0.3.4/c/JXInputManager.h
new file mode 100644
index 0000000..41b9da4
--- /dev/null
+++ b/vendor/JXInput/0.3.4/c/JXInputManager.h
@@ -0,0 +1,47 @@
+// JXInputManager.h: Schnittstelle für die Klasse JXInputManager.
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_JXINPUTMANAGER_H__24862402_14C9_407D_8532_A16A6E3A7D64__INCLUDED_)
+#define AFX_JXINPUTMANAGER_H__24862402_14C9_407D_8532_A16A6E3A7D64__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+
+#define MAX_JXINPUTS 10
+
+class JXInput;
+
+class JXINPUT_API JXInputManager
+{
+public:
+ JXInputManager( HWND hWnd );
+ virtual ~JXInputManager();
+
+ int getNumberOfJXInputs() const;
+ JXInput& getJXInput( int idx ) const;
+
+ //
+ // Numbering methods
+ //
+ int getMaxNumberOfAxes() const;
+ int getMaxNumberOfButtons() const;
+ int getMaxNumberOfDirectionals() const;
+
+private:
+ LPDIRECTINPUT8 mpDI;
+ HWND mhWnd;
+ JXInput* mDevices[ MAX_JXINPUTS ];
+ int mDeviceCounter;
+
+ HRESULT InitDirectInput( HWND hWnd = NULL );
+ HRESULT FreeDirectInput();
+
+ static BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance,
+ VOID* pContext );
+ void addJXInput( JXInput* pJ );
+};
+
+#endif // !defined(AFX_JXINPUTMANAGER_H__24862402_14C9_407D_8532_A16A6E3A7D64__INCLUDED_)
diff --git a/vendor/JXInput/0.3.4/c/ReadMe.txt b/vendor/JXInput/0.3.4/c/ReadMe.txt
new file mode 100644
index 0000000..755cd4c
--- /dev/null
+++ b/vendor/JXInput/0.3.4/c/ReadMe.txt
@@ -0,0 +1,37 @@
+========================================================================
+ DYNAMIC LINK LIBRARY : jxinput
+========================================================================
+
+
+Diese jxinput-DLL hat der Anwendungs-Assistent für Sie erstellt.
+
+Diese Datei enthält eine Zusammenfassung dessen, was Sie in jeder der Dateien
+finden, die Ihre jxinput-Anwendung bilden.
+
+jxinput.dsp
+ Diese Datei (Projektdatei) enthält Informationen auf Projektebene und wird zur
+ Erstellung eines einzelnen Projekts oder Teilprojekts verwendet. Andere Benutzer können
+ die Projektdatei (.dsp) gemeinsam nutzen, sollten aber die Makefiles lokal exportieren.
+
+jxinput.cpp
+ Dies ist die Hauptquellcodedatei für die DLL.
+
+jxinput.h
+ Diese Datei enthält Ihre DLL-Exporte.
+
+/////////////////////////////////////////////////////////////////////////////
+Weitere Standarddateien:
+
+StdAfx.h, StdAfx.cpp
+ Diese Dateien werden zum Erstellen einer vorkompilierten Header-Datei (PCH) namens
+ jxinput.pch und einer vorkompilierten Typdatei namens StdAfx.obj verwendet.
+
+
+/////////////////////////////////////////////////////////////////////////////
+Weitere Hinweise:
+
+Der Anwendungs-Assistent verwendet "ZU ERLEDIGEN:", um Bereiche des Quellcodes zu
+kennzeichnen, die Sie hinzufügen oder anpassen sollten.
+
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/vendor/JXInput/0.3.4/c/StdAfx.cpp b/vendor/JXInput/0.3.4/c/StdAfx.cpp
new file mode 100644
index 0000000..a144a09
--- /dev/null
+++ b/vendor/JXInput/0.3.4/c/StdAfx.cpp
@@ -0,0 +1,9 @@
+// stdafx.cpp : Quelltextdatei, die nur die Standard-Includes einbindet
+// jxinput.pch ist die vorkompilierte Header-Datei
+// stdafx.obj enthält die vorkompilierte Typinformation
+
+#include "stdafx.h"
+
+// ZU ERLEDIGEN: Verweis auf alle zusätzlichen Header-Dateien, die Sie in STDAFX.H
+// und nicht in dieser Datei benötigen
+
diff --git a/vendor/JXInput/0.3.4/c/StdAfx.h b/vendor/JXInput/0.3.4/c/StdAfx.h
new file mode 100644
index 0000000..e139c4c
--- /dev/null
+++ b/vendor/JXInput/0.3.4/c/StdAfx.h
@@ -0,0 +1,32 @@
+// stdafx.h : Include-Datei für Standard-System-Include-Dateien,
+// oder projektspezifische Include-Dateien, die häufig benutzt, aber
+// in unregelmäßigen Abständen geändert werden.
+//
+
+#if !defined(AFX_STDAFX_H__68E14C76_098F_47ED_932B_4C01E8E9EFFB__INCLUDED_)
+#define AFX_STDAFX_H__68E14C76_098F_47ED_932B_4C01E8E9EFFB__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+
+// Fügen Sie hier Ihre Header-Dateien ein
+#define WIN32_LEAN_AND_MEAN // Selten benutzte Teile der Windows-Header nicht einbinden
+#define STRICT
+#include
+ *
+ *
+ *
+ * There are no concrete classes directly derived from
+ * A JXInputDevice represents one physical device like a joystick, a gamepad or
+ * even some emulation (e.g. using keyboard) that implements the interface.
+ *
+ * The basis task of a
+ * An additional task is to provide basic device features information like number of axes, buttons
+ * and directional features.
+ *
+ * @see Feature
+ * @see JXInputManager
+ *
+ * @author Herkules
+ * @version 0.2beta
+ */
+public interface JXInputDevice
+{
+ /**
+ * @directed
+ */
+ /*#Features lnkFeatures;*/
+
+ /**
+ *@link aggregationByValue
+ */
+ /*#Feature lnkFeature;*/
+
+ /**
+ * Devices may have a name.
+ * This name might be provided by a system dependant driver.
+ */
+ String getName();
+
+ /** Actual number of available axes. */
+ int getNumberOfAxes();
+
+ /** Actual number of available buttons. */
+ int getNumberOfButtons();
+
+ /** Actual number of available directional features. */
+ int getNumberOfDirectionals();
+
+ /** Maximum number of axes as an upper bound for index values. */
+ int getMaxNumberOfAxes();
+
+ /** Maximum number of buttons as an upper bound for index values. */
+ int getMaxNumberOfButtons();
+
+ /** Maximum number of directional features as an upper bound for index values. */
+ int getMaxNumberOfDirectionals();
+
+ Axis getAxis( int idx );
+ Button getButton( int idx );
+ Directional getDirectional( int idx );
+}
+
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/JXInputManager.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/JXInputManager.java
new file mode 100644
index 0000000..8c3e050
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/JXInputManager.java
@@ -0,0 +1,233 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 29. Dezember 2001, 02:17
+//**********************************************************************************************
+package de.hardcode.jxinput;
+
+//
+// Import driver stuff
+//
+import de.hardcode.jxinput.directinput.DirectInputDevice;
+import de.hardcode.jxinput.event.JXInputEventManager;
+import de.hardcode.jxinput.keyboard.JXKeyboardInputDevice;
+import de.hardcode.jxinput.virtual.JXVirtualInputDevice;
+
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.awt.Component;
+
+
+/**
+ * Manages the available instances of JXInputDevice.
+ * It holds the one central update method which synchronizes with the physical device.
+ * @author Herkules
+ */
+public class JXInputManager
+{
+
+ /** Remember when the last update took place. */
+ private static long mTimeOfLastUpdate;
+
+ /** Maintain a list of devices. */
+ private final static ArrayList mDevices = new ArrayList();
+
+ /** Maintain a list of direct input devices. */
+ private final static ArrayList mDIDevices = new ArrayList();
+
+ /** Maintain a list of virtual devices. */
+ private final static ArrayList mVirtualDevices = new ArrayList();
+
+ /** Maintain a list of keyboard devices. */
+ private final static ArrayList mKBDevices = new ArrayList();
+
+ /**
+ * Statically retrieve all DirectInputDevices available.
+ */
+ static
+ {
+ reset();
+ }
+
+
+ /**
+ * @directed
+ */
+ /*#JXInputDevice lnkJXInputDevice;*/
+
+ /**
+ * Creates a new instance of JXInputManager.
+ * This is prohibited - it only has static members.
+ */
+ private JXInputManager()
+ {
+ }
+
+
+ /**
+ * Retrieve the number of available input devices.
+ */
+ public static int getNumberOfDevices()
+ {
+ return mDevices.size();
+ }
+
+ /**
+ * Delivers the JXInputDevice with the desired index.
+ *
+ * Take care that A simple logging interface abstracting logging APIs. In order to be
+ * instantiated successfully by {@link LogFactory}, classes that implement
+ * this interface must have a constructor that takes a single String
+ * parameter representing the "name" of this Log. The six logging levels used by TRANSLATION typed axes denote a translational deviation from a center
+ * position. This can be e.g. the common, basic joystick axes.
+ * The range of getValue() is [-1.0,1.0].
+ * ROTATION typed axes denote a rotational deviation from a center
+ * position. Something on the stick is turned or twisted.
+ * The range of getValue() is [-1.0,1.0].
+ * SLIDER typed axes denote a shifting device without a center position.
+ * A good sample is a throttle control.
+ * The range of getValue() is [0.0,1.0].
+ *
+ * @return [ TRANSLATION | ROTATION | SLIDER ]
+ */
+ int getType();
+
+ /**
+ * Returns the current value of the axis.
+ * The range of the result depends on the axis type.
+ *
+ * @return value [-1.0,1.0] or [0.0,1.0]
+ */
+ double getValue();
+
+
+ /**
+ * Inform about the resolution of the axis.
+ *
+ * @return resolution, e.g. 2^-16
+ */
+ double getResolution();
+
+}
+
+
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/Button.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/Button.java
new file mode 100644
index 0000000..418e2b6
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/Button.java
@@ -0,0 +1,35 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 19. Dezember 2001, 21:58
+//**********************************************************************************************
+package de.hardcode.jxinput;
+
+/**
+ *
+ * @author Herkules
+ */
+public interface Button extends Feature
+{
+ // Enumeration of button types
+ final static int PUSHBUTTON = 0;
+ final static int TOGGLEBUTTON = 1;
+
+ /**
+ * Retrieve the type of the button.
+ * Pushbutton will deliver true==getState() as long as they are pressed down.
+ * Togglebuttons will change their state once they are pressed and keep that state
+ * until they are pressed again.
+ * @return [ PUSHBUTTON | TOGGLEBUTTON ]
+ */
+ int getType();
+
+ /**
+ * Tells the state of the button at last update.
+ */
+ boolean getState();
+}
+
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/Directional.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/Directional.java
new file mode 100644
index 0000000..ccd27c1
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/Directional.java
@@ -0,0 +1,45 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 27. Dezember 2001, 23:33
+//**********************************************************************************************
+package de.hardcode.jxinput;
+
+/**
+ *
+ * @author Herkules
+ */
+public interface Directional extends Feature
+{
+ /**
+ * If the Directional has a center position where it points to no direction, this
+ * flag is true when this position is reached.
+ */
+ boolean isCentered();
+
+ /**
+ * Retrieve the direction pointed to.
+ * Value is given in 1/100 degree, [0,36000]
+ */
+ int getDirection();
+
+ /**
+ * Retrieve the analog value pointing to the angle described by
+ * getDirection().
+ * For coolie hats this will be either 1,0 for any direction or 0.0
+ * when isCentered()==true.
+ */
+ double getValue();
+
+ /**
+ * Inform about the resolution of the value returned by getValue().
+ *
+ * @return resolution, e.g. 1.0 for coolie hats
+ */
+ double getResolution();
+
+}
+
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/Feature.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/Feature.java
new file mode 100644
index 0000000..20c396f
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/Feature.java
@@ -0,0 +1,38 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 27. Dezember 2001, 00:19
+//**********************************************************************************************
+package de.hardcode.jxinput;
+
+/**
+ * An input device offers a set of features (otherwise it would be pretty useless).
+ * Features in this sense can be axes, buttons and a feature callede Feature - it only
+ * provides a basis for other interfaces.
+ *
+ * @see Axis
+ * @see Button
+ * @see Directional
+ *
+ * @author Herkules
+ */
+public abstract interface Feature
+{
+ /**
+ * Features may have a name provided e.g. by the driver.
+ */
+ String getName();
+
+ /**
+ * Denote wether this feature has changed beyond it's resolution since it got last
+ * updated.
+ */
+ boolean hasChanged();
+}
+
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/JXInputDevice.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/JXInputDevice.java
new file mode 100644
index 0000000..d8a8bc8
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/JXInputDevice.java
@@ -0,0 +1,71 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 19. Dezember 2001, 21:47
+//**********************************************************************************************
+package de.hardcode.jxinput;
+
+/**
+ * The JXInputDevise is the main entrypoint to the jxinput package.
+ * JXInputDevise is to maintain a consistent state of all its features.
+ *
+ * It is save to distribute the Feature objects into application without worrying
+ * about someone else performing an update method and thereby destructing the consistent state.
+ * idx < getNumberOfDevices()!
+ */
+ public static JXInputDevice getJXInputDevice( int idx )
+ {
+ //
+ // Be well-behaved even if idx is out of range.
+ //
+ if ( idx >= mDevices.size() )
+ return null;
+ return (JXInputDevice)mDevices.get( idx );
+ }
+
+
+ /**
+ * Master reset for all devices and events.
+ * After calling reset(), better forget all devices created or retrieved.
+ * They are no longer valid.
+ * Event listeners will no longer be called and should be discarded.
+ */
+ synchronized public static void reset()
+ {
+ JXInputEventManager.reset();
+
+ mDevices.clear();
+
+ mVirtualDevices.clear();
+ mDIDevices.clear();
+
+ DirectInputDevice.reset();
+
+ for ( int i = 0; i < DirectInputDevice.getNumberOfDevices(); ++i )
+ {
+ DirectInputDevice dev = new DirectInputDevice( i );
+ mDevices.add( dev );
+ mDIDevices.add( dev );
+ }
+
+ // I have to call updateFeatures one time here during initialization
+ // bc. I experienced difficulties otherwise while running with the
+ // J3D sensoring stuff!
+// updateFeatures();
+ DirectInputDevice.update();
+
+ int n = mKBDevices.size();
+ for ( int i = 0; i < n; ++i )
+ ((JXKeyboardInputDevice)mKBDevices.get( i )).shutdown();
+ mKBDevices.clear();
+ }
+
+
+ /**
+ * Update the (shared) state of all features in one step.
+ * This method asks the actual device for a consistant state.
+ * After calling this method, all features may have new values.
+ * updateFeatures() is meant to be called e.g. once per frame in a gaming environment.
+ */
+ public static void updateFeatures()
+ {
+ // Get timing
+ long now = System.currentTimeMillis();
+ long deltaT = now - mTimeOfLastUpdate;
+
+ // Update available driver
+ DirectInputDevice.update();
+
+ //
+ // Update the virtual devices.
+ //
+ Iterator vdevices = mVirtualDevices.iterator();
+ while ( vdevices.hasNext() )
+ {
+ ((JXVirtualInputDevice)vdevices.next()).update( deltaT );
+ }
+
+ // Remember time
+ mTimeOfLastUpdate = now;
+
+ // Fire all events.
+ JXInputEventManager.trigger();
+ }
+
+
+
+ /**
+ * Get time when last update occurred.
+ * @return tickervalue in milliseconds
+ */
+ public static long getLastUpdateTime()
+ {
+ return mTimeOfLastUpdate;
+ }
+
+
+ /**
+ * Create a new pseudo-device.
+ */
+ public static JXKeyboardInputDevice createKeyboardDevice()
+ {
+ JXKeyboardInputDevice d = new JXKeyboardInputDevice();
+ mDevices.add( d );
+ mKBDevices.add( d );
+ return d;
+ }
+
+
+ /**
+ * Create a new pseudo-device listening to a Swing component.
+ * Make sure that the component also has the keyboard focus!!
+ */
+ public static JXKeyboardInputDevice createKeyboardDevice( Component comp )
+ {
+ JXKeyboardInputDevice d = new JXKeyboardInputDevice( comp );
+ mDevices.add( d );
+ mKBDevices.add( d );
+ return d;
+ }
+
+
+ /**
+ * Delete a keyboard device again e.g. when the corresponding
+ * JComponent gets deleted.
+ */
+ public static void deleteKeyboardDevice( JXKeyboardInputDevice dev )
+ {
+ mDevices.remove( dev );
+ mKBDevices.remove( dev );
+ ((JXKeyboardInputDevice)dev).shutdown();
+ }
+
+
+ /**
+ * Create a new pseudo-device.
+ */
+ public static JXVirtualInputDevice createVirtualDevice()
+ {
+ JXVirtualInputDevice d = new JXVirtualInputDevice();
+ mDevices.add( d );
+ mVirtualDevices.add( d );
+ return d;
+ }
+
+
+ /**
+ * Delete a virtual device again.
+ */
+ public static void deleteVirtualDevice( JXVirtualInputDevice dev )
+ {
+ mDevices.remove( dev );
+ mVirtualDevices.remove( dev );
+ }
+
+}
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/directinput/DIAxis.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/directinput/DIAxis.java
new file mode 100644
index 0000000..a6d0eac
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/directinput/DIAxis.java
@@ -0,0 +1,70 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 27. Dezember 2001, 00:14
+//**********************************************************************************************
+package de.hardcode.jxinput.directinput;
+
+import de.hardcode.jxinput.Axis;
+
+/**
+ *
+ * @author Herkules
+ */
+class DIAxis implements Axis
+{
+ private final int mDeviceIdx;
+ private final int mIdx;
+
+ /**
+ * Creates a new instance of DIAxis.
+ */
+ DIAxis( int devidx, int idx )
+ {
+ mDeviceIdx = devidx;
+ mIdx = idx;
+ }
+
+ public String getName()
+ {
+ return DirectInputDriver.getAxisName( mDeviceIdx, mIdx );
+ }
+
+
+ /**
+ * Denote wether this feature has changed beyond it's resolution since it got last
+ * updated.
+ */
+ public boolean hasChanged()
+ {
+ return true;
+ }
+
+ public double getValue()
+ {
+ return DirectInputDriver.getAxisValue( mDeviceIdx, mIdx );
+ }
+
+ public int getType()
+ {
+ return DirectInputDriver.getAxisType( mDeviceIdx, mIdx );
+ }
+
+ /**
+ * Inform about the resolution of the axis.
+ *
+ * @return resolution, e.g. 2^-16
+ */
+ public double getResolution()
+ {
+ // extend the driver here!!
+ // Here I assume typical 16 bit resolution
+ return ( getType() == Axis.SLIDER ? 1.0/65536.0 : 2.0/65536.0 ) ;
+ }
+
+}
+
+
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/directinput/DIButton.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/directinput/DIButton.java
new file mode 100644
index 0000000..5419550
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/directinput/DIButton.java
@@ -0,0 +1,55 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 27. Dezember 2001, 00:14
+//**********************************************************************************************
+package de.hardcode.jxinput.directinput;
+
+import de.hardcode.jxinput.Button;
+
+
+/**
+ *
+ * @author Herkules
+ */
+class DIButton implements Button
+{
+ private final int mDeviceIdx;
+ private final int mIdx;
+
+ /**
+ * Creates a new instance of DIButton.
+ */
+ DIButton( int devidx, int idx )
+ {
+ mDeviceIdx = devidx;
+ mIdx = idx;
+ }
+
+ public String getName()
+ {
+ return DirectInputDriver.getButtonName( mDeviceIdx, mIdx );
+ }
+
+ /**
+ * Denote wether this feature has changed beyond it's resolution since it got last
+ * updated.
+ */
+ public boolean hasChanged()
+ {
+ return true;
+ }
+
+ public int getType()
+ {
+ return DirectInputDriver.getButtonType( mDeviceIdx, mIdx );
+ }
+
+ public boolean getState()
+ {
+ return DirectInputDriver.getButtonState( mDeviceIdx, mIdx );
+ }
+}
\ No newline at end of file
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/directinput/DIDirectional.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/directinput/DIDirectional.java
new file mode 100644
index 0000000..9da2d3d
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/directinput/DIDirectional.java
@@ -0,0 +1,78 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 27. Dezember 2001, 23:40
+//**********************************************************************************************
+package de.hardcode.jxinput.directinput;
+
+import de.hardcode.jxinput.Directional;
+
+/**
+ *
+ * @author Herkules
+ */
+class DIDirectional implements Directional
+{
+ private final int mDeviceIdx;
+ private final int mIdx;
+
+ /**
+ * Creates a new instance of DIDirectional.
+ */
+ DIDirectional( int devidx, int idx )
+ {
+ mDeviceIdx = devidx;
+ mIdx = idx;
+ }
+
+ /** Features may have a name provided e.g. by the driver. */
+ public String getName()
+ {
+ return DirectInputDriver.getDirectionalName( mDeviceIdx, mIdx );
+ }
+
+ /**
+ * Denote wether this feature has changed beyond it's resolution since it got last
+ * updated.
+ */
+ public boolean hasChanged()
+ {
+ return true;
+ }
+
+
+ public boolean isCentered()
+ {
+ return ( 0xffff == (DirectInputDriver.getDirection( mDeviceIdx, mIdx ) & 0xffff) );
+ }
+
+ public int getDirection()
+ {
+ return isCentered() ? 0 : DirectInputDriver.getDirection( mDeviceIdx, mIdx );
+ }
+
+ public double getValue()
+ {
+ if ( isCentered() )
+ return 0.0;
+ return 1.0;
+ }
+
+ /**
+ * Inform about the resolution of the value returned by getValue().
+ *
+ * @return resolution, e.g. 1.0 for coolie hats
+ */
+ public double getResolution()
+ {
+ // DI POV always return 0.0 or 1.0, so the resolution is 1.0.
+ return 1.0;
+ }
+
+
+}
+
+
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/directinput/DirectInputDevice.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/directinput/DirectInputDevice.java
new file mode 100644
index 0000000..a20eab3
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/directinput/DirectInputDevice.java
@@ -0,0 +1,170 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 26. Dezember 2001, 00:40
+//**********************************************************************************************
+package de.hardcode.jxinput.directinput;
+
+import de.hardcode.jxinput.JXInputDevice;
+import de.hardcode.jxinput.Axis;
+import de.hardcode.jxinput.Directional;
+import de.hardcode.jxinput.Button;
+
+/**
+ *
+ * @author Herkules
+ */
+public class DirectInputDevice implements JXInputDevice
+{
+ int mDeviceIdx;
+
+ private DIAxis[] mAxes;
+ private DIButton[] mButtons;
+ private DIDirectional[] mDirectionals;
+
+ /**
+ * The number of DirectInput devices available with the driver.
+ */
+ public static int getNumberOfDevices()
+ {
+ if ( DirectInputDriver.isAvailable() )
+ return DirectInputDriver.getNumberOfDevices();
+ return 0;
+ }
+
+
+ /**
+ * Update the state of all devices.
+ */
+ public static void update()
+ {
+ if ( DirectInputDriver.isAvailable() )
+ DirectInputDriver.nativeupdate();
+ }
+
+
+
+
+ /**
+ * Creates a new instance of DirectInputDevice.
+ */
+ public DirectInputDevice( int devidx )
+ {
+ mDeviceIdx = devidx;
+
+ init();
+ }
+
+ /**
+ * Reset the DirectInput connection.
+ */
+ public static void reset()
+ {
+ if ( DirectInputDriver.isAvailable() )
+ DirectInputDriver.reset();
+ }
+
+
+ /**
+ * Initialisation of fields.
+ */
+ private final void init()
+ {
+ //
+ // Allocate arrays for max. number of features
+ //
+ mAxes = new DIAxis [ getMaxNumberOfAxes() ];
+ mButtons = new DIButton [ getMaxNumberOfButtons() ];
+ mDirectionals = new DIDirectional [ getMaxNumberOfDirectionals() ];
+
+ //
+ // Fill arrays due to the state of the driver.
+ //
+ for ( int i = 0; i < mAxes.length; ++i )
+ {
+ if ( DirectInputDriver.isAxisAvailable( mDeviceIdx, i ) )
+ mAxes[ i ] = new DIAxis( mDeviceIdx, i );
+ }
+
+ for ( int i = 0; i < mButtons.length; ++i )
+ {
+ if ( DirectInputDriver.isButtonAvailable( mDeviceIdx, i ) )
+ mButtons[ i ] = new DIButton( mDeviceIdx, i );
+ }
+
+ for ( int i = 0; i < mDirectionals.length; ++i )
+ {
+ if ( DirectInputDriver.isDirectionalAvailable( mDeviceIdx, i ) )
+ mDirectionals[ i ] = new DIDirectional( mDeviceIdx, i );
+ }
+ }
+
+ /** Devices may have a name. */
+ public String getName()
+ {
+ String name = DirectInputDriver.getName( mDeviceIdx );
+ if ( null == name )
+ return "Win32 DirectInput Joystick";
+ return name;
+ }
+
+
+ /** Actual number of available buttons. */
+ public int getNumberOfButtons()
+ {
+ return DirectInputDriver.getNumberOfButtons( mDeviceIdx );
+ }
+
+ /** Actual number of available axes. */
+ public int getNumberOfAxes()
+ {
+ return DirectInputDriver.getNumberOfAxes( mDeviceIdx );
+ }
+
+ /** Actual number of available directional features. */
+ public int getNumberOfDirectionals()
+ {
+ return DirectInputDriver.getNumberOfDirectionals( mDeviceIdx );
+ }
+
+ /** Maximum number of buttons as an upper bound for index values. */
+ public int getMaxNumberOfButtons()
+ {
+ return DirectInputDriver.getMaxNumberOfButtons();
+ }
+
+ /** Maximum number of axes as an upper bound for index values. */
+ public int getMaxNumberOfAxes()
+ {
+ return DirectInputDriver.getMaxNumberOfAxes();
+ }
+
+ /** Maximum number of available directional features. */
+ public int getMaxNumberOfDirectionals()
+ {
+ return DirectInputDriver.getMaxNumberOfDirectionals();
+ }
+
+
+ public Axis getAxis(int idx)
+ {
+ return mAxes[ idx ];
+ }
+
+ public Button getButton(int idx)
+ {
+ return mButtons[ idx ];
+ }
+
+ public Directional getDirectional(int idx)
+ {
+ return mDirectionals[ idx ];
+ }
+
+}
+
+
+
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/directinput/DirectInputDriver.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/directinput/DirectInputDriver.java
new file mode 100644
index 0000000..558f7d8
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/directinput/DirectInputDriver.java
@@ -0,0 +1,184 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 19. Dezember 2001, 22:44
+//**********************************************************************************************
+package de.hardcode.jxinput.directinput;
+
+import java.lang.reflect.Array;
+
+/**
+ * DirectInputDriver: the connection to the Win32 joystick.
+ * There is only one allowed, so the layout of this class is merely static.
+ *
+ * History:
+ *
+ * Changes since 0.1beta:
+ * - support of multiple devices addressed by the dev index
+ *
+ *
+ * @author Herkules
+ * @version 0.2beta
+ */
+class DirectInputDriver
+{
+ private final static String NATIVE_LIB_NAME = "jxinput";
+
+ /** Remember wether nativeinit() succeeded. */
+ static boolean sIsOperational = false;
+
+ //
+ // Static arrays to hold the values.
+ //
+ private static double [][] sAxisValues;
+ private static boolean [][] sButtonStates;
+ private static int [][] sDirectionalValues;
+
+ /**
+ * Perform the static initialization.
+ */
+ static
+ {
+ try
+ {
+ // Load the native lib.
+ System.loadLibrary( NATIVE_LIB_NAME );
+
+ init();
+ }
+ catch( SecurityException e )
+ {
+ Log.logger.warning("Native library jxinput not loaded due to a SecurityException.");
+ }
+ catch( UnsatisfiedLinkError e )
+ {
+ Log.logger.info("Native library jxinput not loaded due to an UnsatisfiedLinkError.");
+ }
+ }
+
+
+ private final static void init()
+ {
+ sIsOperational = false;
+ //
+ // Initialize it.
+ //
+ if ( nativeinit() )
+ {
+ int devs = getNumberOfDevices();
+ sAxisValues = new double [ devs ][ DirectInputDriver.getMaxNumberOfAxes() ];
+ sButtonStates = new boolean [ devs ][ DirectInputDriver.getMaxNumberOfButtons() ];
+ sDirectionalValues = new int [ devs ][ DirectInputDriver.getMaxNumberOfDirectionals() ];
+
+ // Bind the native lib to my variables.
+ bind();
+
+ // Remember I am fine.
+ sIsOperational = true;
+ }
+
+ }
+
+
+ /**
+ * Static ctor of DirectInputDriver.
+ * No object will be created due to the static layout.
+ */
+ private DirectInputDriver()
+ {
+ }
+
+ // Administration
+ private static native boolean nativeinit();
+ private static native void nativeexit();
+ private static native void bind();
+
+ static native int getNumberOfDevices();
+
+ // Configuration
+ static native String getName( int dev );
+ static native int getNumberOfAxes( int dev );
+ static native int getNumberOfButtons( int dev );
+ static native int getNumberOfDirectionals( int dev );
+ static native int getMaxNumberOfAxes();
+ static native int getMaxNumberOfButtons();
+ static native int getMaxNumberOfDirectionals();
+
+ static native boolean isAxisAvailable( int dev, int idx );
+ static native String getAxisName( int dev, int idx );
+ static native int getAxisType( int dev, int idx );
+
+ static native boolean isButtonAvailable( int dev, int idx );
+ static native String getButtonName( int dev, int idx );
+ static native int getButtonType( int dev, int idx );
+
+ static native boolean isDirectionalAvailable( int dev, int idx );
+ static native String getDirectionalName( int dev, int idx );
+
+ // Operation
+ static native void nativeupdate();
+
+
+ public static boolean isAvailable()
+ {
+ return sIsOperational;
+ }
+
+
+ /**
+ * Shutdown the device and free all Win32 resources.
+ * It is not a good idea to access any joystick features after
+ * shutdown().
+ */
+ static void shutdown()
+ {
+ nativeexit();
+ sAxisValues = null;
+ sButtonStates = null;
+ sDirectionalValues = null;
+ }
+
+
+ /**
+ * Reset the device and free all Win32 resources.
+ */
+ static void reset()
+ {
+ shutdown();
+ init();
+ }
+
+ static double getAxisValue( int dev, int idx )
+ {
+ return sAxisValues[ dev ][ idx ];
+ }
+
+ static boolean getButtonState( int dev, int idx )
+ {
+ return sButtonStates[ dev ][ idx ];
+ }
+
+ static int getDirection( int dev, int idx )
+ {
+ return sDirectionalValues[ dev ][ idx ];
+ }
+
+ /**
+ * @param args the command line arguments
+ */
+ public static void main (String args[])
+ {
+
+ if ( ! sIsOperational )
+ return;
+
+ for( int i = 0; i < 5000; ++i )
+ nativeupdate();
+
+ shutdown();
+ }
+
+}
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/directinput/Log.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/directinput/Log.java
new file mode 100644
index 0000000..95e586c
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/directinput/Log.java
@@ -0,0 +1,34 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 29. Oktober 2002, 22:57
+//**********************************************************************************************
+package de.hardcode.jxinput.directinput;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ *
+ * @author Herkules
+ */
+public class Log
+{
+ public final static Logger logger = Logger.getLogger( Log.class.getPackage().getName() );
+
+// static
+// {
+// logger.setLevel( Level.ALL );
+// }
+
+ /**
+ * Creates a new instance of Log.
+ */
+ private Log()
+ {
+ }
+
+}
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/event/JXInputAxisEvent.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/event/JXInputAxisEvent.java
new file mode 100644
index 0000000..c353b5e
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/event/JXInputAxisEvent.java
@@ -0,0 +1,48 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 31. Januar 2002, 23:33
+//**********************************************************************************************
+package de.hardcode.jxinput.event;
+
+import de.hardcode.jxinput.JXInputDevice;
+import de.hardcode.jxinput.Axis;
+
+/**
+ * Represents an event coming from an axis.
+ * @author Joerg Plewe
+ */
+public class JXInputAxisEvent
+{
+ private final Axis mAxis;
+ double mDelta;
+
+ /**
+ * Creates a new instance of JXInputEvent.
+ */
+ JXInputAxisEvent( Axis axis )
+ {
+ mAxis = axis;
+ }
+
+ /**
+ * The feature that caused the event.
+ */
+ public final Axis getAxis()
+ {
+ return mAxis;
+ }
+
+
+ /**
+ * Return the change in value that caused the event.
+ */
+ public double getDelta()
+ {
+ return mDelta;
+ }
+
+}
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/event/JXInputAxisEventListener.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/event/JXInputAxisEventListener.java
new file mode 100644
index 0000000..d8adf46
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/event/JXInputAxisEventListener.java
@@ -0,0 +1,19 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 31. Januar 2002, 23:54
+//**********************************************************************************************
+package de.hardcode.jxinput.event;
+
+/**
+ *
+ * @author Herkules
+ */
+public interface JXInputAxisEventListener
+{
+ void changed( JXInputAxisEvent ev );
+}
+
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/event/JXInputButtonEvent.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/event/JXInputButtonEvent.java
new file mode 100644
index 0000000..d82d0b9
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/event/JXInputButtonEvent.java
@@ -0,0 +1,38 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 31. Januar 2002, 23:33
+//**********************************************************************************************
+package de.hardcode.jxinput.event;
+
+import de.hardcode.jxinput.JXInputDevice;
+import de.hardcode.jxinput.Button;
+
+/**
+ * Represents event coming from a button.
+ * @author Joerg Plewe
+ */
+public class JXInputButtonEvent
+{
+ final Button mButton;
+
+ /**
+ * Creates a new instance of JXInputEvent.
+ */
+ JXInputButtonEvent( Button button )
+ {
+ mButton = button;
+ }
+
+ /**
+ * The feature that caused the event.
+ */
+ public final Button getButton()
+ {
+ return mButton;
+ }
+
+}
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/event/JXInputButtonEventListener.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/event/JXInputButtonEventListener.java
new file mode 100644
index 0000000..afdc323
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/event/JXInputButtonEventListener.java
@@ -0,0 +1,19 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 31. Januar 2002, 23:54
+//**********************************************************************************************
+package de.hardcode.jxinput.event;
+
+/**
+ *
+ * @author Herkules
+ */
+public interface JXInputButtonEventListener
+{
+ void changed( JXInputButtonEvent ev );
+}
+
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/event/JXInputDirectionalEvent.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/event/JXInputDirectionalEvent.java
new file mode 100644
index 0000000..70e6bcd
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/event/JXInputDirectionalEvent.java
@@ -0,0 +1,56 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 31. Januar 2002, 23:33
+//**********************************************************************************************
+package de.hardcode.jxinput.event;
+
+import de.hardcode.jxinput.JXInputDevice;
+import de.hardcode.jxinput.Directional;
+
+/**
+ * Represents an event coming from an axis.
+ * @author Joerg Plewe
+ */
+public class JXInputDirectionalEvent
+{
+ private final Directional mDirectional;
+ double mValueDelta;
+ int mDirectionDelta;
+
+ /**
+ * Creates a new instance of JXInputEvent.
+ */
+ JXInputDirectionalEvent( Directional directional )
+ {
+ mDirectional = directional;
+ }
+
+ /**
+ * The feature that caused the event.
+ */
+ public final Directional getDirectional()
+ {
+ return mDirectional;
+ }
+
+ /**
+ * Return the change in value that caused the event.
+ */
+ public double getValueDelta()
+ {
+ return mValueDelta;
+ }
+
+ /**
+ * Return the change in direction that caused the event.
+ */
+ public int getDirectionDelta()
+ {
+ return mDirectionDelta;
+ }
+
+}
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/event/JXInputDirectionalEventListener.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/event/JXInputDirectionalEventListener.java
new file mode 100644
index 0000000..65c7efa
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/event/JXInputDirectionalEventListener.java
@@ -0,0 +1,19 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 31. Januar 2002, 23:54
+//**********************************************************************************************
+package de.hardcode.jxinput.event;
+
+/**
+ *
+ * @author Herkules
+ */
+public interface JXInputDirectionalEventListener
+{
+ void changed( JXInputDirectionalEvent ev );
+}
+
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/event/JXInputEventManager.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/event/JXInputEventManager.java
new file mode 100644
index 0000000..aa196d7
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/event/JXInputEventManager.java
@@ -0,0 +1,284 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 31. Januar 2002, 23:42
+//**********************************************************************************************
+package de.hardcode.jxinput.event;
+
+import de.hardcode.jxinput.JXInputManager;
+import de.hardcode.jxinput.JXInputDevice;
+
+import java.util.ArrayList;
+import de.hardcode.jxinput.Axis;
+import java.util.Iterator;
+import de.hardcode.jxinput.Button;
+import de.hardcode.jxinput.Directional;
+
+/**
+ * Handles all events and listeners.
+ * JXInputEventManager is layed out a static singleton.
+ * @author Herkules
+ */
+public class JXInputEventManager
+{
+
+ private final static ArrayList mAxisEventListeners = new ArrayList();
+ private final static ArrayList mButtonEventListeners = new ArrayList();
+ private final static ArrayList mDirectionalEventListeners = new ArrayList();
+
+ private static autotrigger mAutoTrigger = null;
+
+ /**
+ * Inner class combining a listener with its scheduling parameters.
+ */
+ private static class axislistener
+ {
+ final JXInputAxisEventListener mListener;
+ final double mTreshold;
+ final JXInputAxisEvent mEvent;
+ double mLastValueFired = 0.0;
+
+ axislistener( JXInputAxisEventListener l, Axis axis, double treshold )
+ {
+ mListener = l;
+ mTreshold = treshold;
+ mEvent = new JXInputAxisEvent( axis );
+ }
+
+ final void checkTrigger()
+ {
+ double curval = mEvent.getAxis().getValue();
+ double delta = curval - mLastValueFired;
+
+ if ( Math.abs( delta ) >= mTreshold )
+ {
+ mLastValueFired = curval;
+ mEvent.mDelta = delta;
+ mListener.changed( mEvent );
+ }
+ }
+ }
+
+ /**
+ * Inner class combining a listener with its scheduling parameters.
+ */
+ private static class buttonlistener
+ {
+ final JXInputButtonEventListener mListener;
+ final JXInputButtonEvent mEvent;
+ boolean mLastValueFired = false;
+
+ buttonlistener( JXInputButtonEventListener l, Button button )
+ {
+ mListener = l;
+ mEvent = new JXInputButtonEvent( button );
+ }
+
+ final void checkTrigger()
+ {
+ boolean curstate = mEvent.getButton().getState();
+ if ( curstate != mLastValueFired )
+ {
+ mLastValueFired = curstate;
+ mListener.changed( mEvent );
+ }
+ }
+ }
+
+
+ private static class directionallistener
+ {
+ final JXInputDirectionalEventListener mListener;
+ final double mValueTreshold;
+ final JXInputDirectionalEvent mEvent;
+ double mLastValueFired = 0.0;
+ boolean mLastCenteredFired = true;
+ int mLastDirectionFired = 0;
+
+ directionallistener( JXInputDirectionalEventListener l, Directional directional, double valuetreshold )
+ {
+ mListener = l;
+ mValueTreshold = valuetreshold;
+ mEvent = new JXInputDirectionalEvent( directional );
+ }
+
+ final void checkTrigger()
+ {
+ double curval = mEvent.getDirectional().getValue();
+ int curdir = mEvent.getDirectional().getDirection();
+ boolean curctr = mEvent.getDirectional().isCentered();
+
+ double delta = curval - mLastValueFired;
+ int dirdelta = curdir - mLastDirectionFired;
+ boolean centeredchanged = mLastCenteredFired != curctr;
+
+ if ( Math.abs( delta ) >= mValueTreshold
+ || Math.abs( dirdelta ) > 0
+ || centeredchanged )
+ {
+ mLastValueFired = curval;
+ mLastDirectionFired = curdir;
+ mLastCenteredFired = curctr;
+
+ mEvent.mValueDelta = delta;
+ mEvent.mDirectionDelta = dirdelta;
+ mListener.changed( mEvent );
+ }
+ }
+ }
+
+ /**
+ * Creates a new instance of JXInputEventManager.
+ */
+ private JXInputEventManager()
+ {
+ }
+
+
+ /**
+ * Remove all listeners at once.
+ */
+ public static void reset()
+ {
+ mAxisEventListeners.clear();
+ mButtonEventListeners.clear();
+ mDirectionalEventListeners.clear();
+ }
+
+
+ /**
+ * Query devices and fire all occuring events.
+ * trigger() is thought to be called by JXInputManager#updateFeatures().
+ */
+ public static void trigger()
+ {
+ int n = mAxisEventListeners.size();
+ for ( int i = 0; i < n; i++ )
+ {
+ axislistener l = (axislistener)mAxisEventListeners.get( i );
+ l.checkTrigger();
+ }
+
+ n = mButtonEventListeners.size();
+ for ( int i = 0; i < n; i++ )
+ {
+ buttonlistener l = (buttonlistener)mButtonEventListeners.get( i );
+ l.checkTrigger();
+ }
+
+ n = mDirectionalEventListeners.size();
+ for ( int i = 0; i < n; i++ )
+ {
+ directionallistener l = (directionallistener)mDirectionalEventListeners.get( i );
+ l.checkTrigger();
+ }
+ }
+
+
+ private final static class autotrigger extends Thread
+ {
+ boolean mFinish = false;
+ final int mDelay;
+
+ autotrigger( int delay )
+ {
+ mDelay = delay;
+ }
+
+ public void run()
+ {
+ while ( ! mFinish )
+ {
+ try
+ {
+ Thread.sleep( mDelay );
+ JXInputManager.updateFeatures();
+ }
+ catch ( InterruptedException ex )
+ {
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Set the intervall in ms that is used to check for new values of the features.
+ * Set it to <= 0 to prohibit automatic triggering. Events will then only be fired
+ * when somebody invokes JXInputManager#updateFeatures().
+ */
+ public static void setTriggerIntervall( int ms )
+ {
+ //
+ // Kill current thread, if any
+ //
+ if ( null != mAutoTrigger )
+ {
+ mAutoTrigger.mFinish = true;
+ try
+ {
+ mAutoTrigger.join();
+ }
+ catch ( InterruptedException ex )
+ {
+ }
+ }
+
+ mAutoTrigger = null;
+
+ if ( ms > 0 )
+ {
+ mAutoTrigger = new autotrigger( ms );
+ mAutoTrigger.start();
+ }
+
+ }
+
+
+
+
+ public static void addListener( JXInputAxisEventListener l, Axis axis, double treshold )
+ {
+ mAxisEventListeners.add( new JXInputEventManager.axislistener( l, axis, treshold ) );
+ }
+
+ public static void addListener( JXInputAxisEventListener l, Axis axis )
+ {
+ mAxisEventListeners.add( new JXInputEventManager.axislistener( l, axis, axis.getResolution() ) );
+ }
+
+ public static void removeListener( JXInputAxisEventListener l )
+ {
+ mAxisEventListeners.remove( l );
+ }
+
+
+ public static void addListener( JXInputButtonEventListener l, Button button )
+ {
+ mButtonEventListeners.add( new JXInputEventManager.buttonlistener( l, button ) );
+ }
+
+ public static void removeListener( JXInputButtonEventListener l )
+ {
+ mButtonEventListeners.remove( l );
+ }
+
+ public static void addListener( JXInputDirectionalEventListener l, Directional directional, double valuetreshold )
+ {
+ mDirectionalEventListeners.add( new JXInputEventManager.directionallistener( l, directional, valuetreshold ) );
+ }
+
+ public static void addListener( JXInputDirectionalEventListener l, Directional directional )
+ {
+ mDirectionalEventListeners.add( new JXInputEventManager.directionallistener( l, directional, directional.getResolution() ) );
+ }
+
+ public static void removeListener( JXInputDirectionalEventListener l )
+ {
+ mDirectionalEventListeners.remove( l );
+ }
+
+}
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/j3d/DeviceConfiguration.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/j3d/DeviceConfiguration.java
new file mode 100644
index 0000000..8c1288a
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/j3d/DeviceConfiguration.java
@@ -0,0 +1,95 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 23. Februar 2002, 14:05
+//**********************************************************************************************
+package de.hardcode.jxinput.j3d;
+
+import de.hardcode.jxinput.Axis;
+
+
+/**
+ * Connects JXInput with J3DInputDevice.
+ *
+ * @author Herkules
+ */
+public class DeviceConfiguration
+{
+ public final static int AXIS_X = 0;
+ public final static int AXIS_Y = 1;
+ public final static int AXIS_Z = 2;
+
+ private final static class axisvalue
+ {
+ private final Axis mAxis;
+ private final IsActiveCondition mIsActive;
+ private final IsActiveCondition mIsIncremental;
+ private final double mScale;
+ private final double mOffset;
+ private double mValue;
+
+ axisvalue( Axis axis, IsActiveCondition active, IsActiveCondition incremental, double offset, double scale )
+ {
+ mAxis = axis;
+ mIsActive = active;
+ mIsIncremental = incremental;
+ mValue = mOffset = offset;
+ mScale = scale;
+ }
+
+ double value()
+ {
+ if ( mIsActive.isActive() )
+ {
+ double newval = mAxis.getValue() * mScale;
+
+ if ( mIsIncremental.isActive() )
+ mValue += newval;
+ else
+ mValue = newval + mOffset;
+ }
+ return mValue;
+ }
+ }
+
+ DeviceConfiguration.axisvalue [] mAxisTrans = new DeviceConfiguration.axisvalue[ 3 ];
+ DeviceConfiguration.axisvalue [] mAxisRot = new DeviceConfiguration.axisvalue[ 3 ];
+
+ /**
+ * Creates a new instance of DeviceConfiguration.
+ */
+ public DeviceConfiguration()
+ {
+ }
+
+
+ double getTranslational( int axisid )
+ {
+ DeviceConfiguration.axisvalue val = mAxisTrans[ axisid ];
+ return null == val ? 0.0 : val.value();
+ }
+
+ double getRotational( int axisid )
+ {
+ DeviceConfiguration.axisvalue val = mAxisRot[ axisid ];
+ return null == val ? 0.0 : val.value();
+ }
+
+ public void setTranslational( int axisid, Axis axis, IsActiveCondition active, IsActiveCondition incremental, double offset, double scale )
+ {
+ if ( axisid < 0 || axisid > AXIS_Z )
+ throw new IllegalArgumentException();
+ mAxisTrans[ axisid ] = new DeviceConfiguration.axisvalue( axis, active, incremental, offset, scale );
+ }
+
+ public void setRotational( int axisid, Axis axis, IsActiveCondition active, IsActiveCondition incremental, double offset, double scale )
+ {
+ if ( axisid < 0 || axisid > AXIS_Z )
+ throw new IllegalArgumentException();
+ mAxisRot[ axisid ] = new DeviceConfiguration.axisvalue( axis, active, incremental, offset, scale );
+ }
+
+}
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/j3d/IsActiveCondition.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/j3d/IsActiveCondition.java
new file mode 100644
index 0000000..af6ca08
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/j3d/IsActiveCondition.java
@@ -0,0 +1,25 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 25. Februar 2002, 22:41
+//**********************************************************************************************
+package de.hardcode.jxinput.j3d;
+
+/**
+ *
+ * @author Herkules
+ */
+public interface IsActiveCondition
+{
+ public final static IsActiveCondition ALWAYS = IsAlwaysActiveCondition.ALWAYS;
+ public final static IsActiveCondition NEVER = IsAlwaysActiveCondition.NEVER;
+
+ /**
+ * Tell wether a certain thing is active.
+ */
+ boolean isActive();
+}
+
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/j3d/IsActiveOnButtonCondition.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/j3d/IsActiveOnButtonCondition.java
new file mode 100644
index 0000000..98da7bb
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/j3d/IsActiveOnButtonCondition.java
@@ -0,0 +1,39 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 25. Februar 2002, 22:43
+//**********************************************************************************************
+package de.hardcode.jxinput.j3d;
+
+import de.hardcode.jxinput.Button;
+
+/**
+ *
+ * @author Herkules
+ */
+public class IsActiveOnButtonCondition implements IsActiveCondition
+{
+ private final boolean mActiveState;
+ private final Button mButton;
+
+ /**
+ * Creates a new instance of IsAlwayActiveCondition.
+ */
+ public IsActiveOnButtonCondition( Button button, boolean activestate )
+ {
+ mActiveState = activestate;
+ mButton = button;
+ }
+
+ /**
+ * Tell wether a certain thing is active.
+ */
+ public boolean isActive()
+ {
+ return mButton.getState() == mActiveState;
+ }
+
+}
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/j3d/IsAlwaysActiveCondition.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/j3d/IsAlwaysActiveCondition.java
new file mode 100644
index 0000000..cd8b1fe
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/j3d/IsAlwaysActiveCondition.java
@@ -0,0 +1,38 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 25. Februar 2002, 22:43
+//**********************************************************************************************
+package de.hardcode.jxinput.j3d;
+
+/**
+ *
+ * @author Herkules
+ */
+final class IsAlwaysActiveCondition implements IsActiveCondition
+{
+ private final boolean mIsActive;
+
+ public final static IsActiveCondition ALWAYS = new IsAlwaysActiveCondition( true );
+ public final static IsActiveCondition NEVER = new IsAlwaysActiveCondition( false );
+
+ /**
+ * Creates a new instance of IsAlwayActiveCondition.
+ */
+ private IsAlwaysActiveCondition(boolean isactive)
+ {
+ mIsActive = isactive;
+ }
+
+ /**
+ * Tell wether a certain thing is active.
+ */
+ public boolean isActive()
+ {
+ return mIsActive;
+ }
+
+}
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/j3d/J3DInputDevice.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/j3d/J3DInputDevice.java
new file mode 100644
index 0000000..f5b08f2
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/j3d/J3DInputDevice.java
@@ -0,0 +1,171 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 22. Februar 2002, 13:21
+//**********************************************************************************************
+package de.hardcode.jxinput.j3d;
+
+import javax.media.j3d.InputDevice;
+import javax.media.j3d.Sensor;
+import javax.media.j3d.SensorRead;
+import javax.vecmath.Vector3d;
+import javax.media.j3d.Transform3D;
+import de.hardcode.jxinput.JXInputManager;
+
+
+/**
+ * Implementation of Java3D's InputDevice
+ *
+ * @author Herkules
+ */
+public class J3DInputDevice
+ implements InputDevice
+{
+ private Vector3d mPosition = new Vector3d();
+ private Transform3D mNewTransform = new Transform3D();
+
+ private Transform3D mRotTransX = new Transform3D();
+ private Transform3D mRotTransY = new Transform3D();
+ private Transform3D mRotTransZ = new Transform3D();
+
+ private Vector3d mInitPos = new Vector3d( 0.0, 0.0, 0.0 );
+
+ private Sensor mSensor = new Sensor( this );
+ private SensorRead mSensorRead = new SensorRead();
+
+ private DeviceConfiguration mConfig;
+
+ /**
+ * Creates a new instance of J3DInputDevice.
+ */
+ public J3DInputDevice( DeviceConfiguration config )
+ {
+ mConfig = config;
+ setNominalPositionAndOrientation();
+ }
+
+
+ public void close()
+ {
+ // Intentionally empty
+ }
+
+
+ /**
+ * Retrieve processing mode.
+ * For this device, it always is NON_BLOCKING.
+ */
+ public int getProcessingMode()
+ {
+ return InputDevice.NON_BLOCKING;
+ }
+
+
+ /**
+ * Don't care for the index, I only support one sensor.
+ * And I deliver that.
+ */
+ public Sensor getSensor( int param )
+ {
+ return mSensor;
+ }
+
+
+ /**
+ * Tell the world about the only one sensor I support.
+ */
+ public int getSensorCount()
+ {
+ return 1;
+ }
+
+
+ /**
+ * Well - initialize!
+ * Nothing to do here.
+ */
+ public boolean initialize()
+ {
+ return true;
+ }
+
+
+ /**
+ * The main update method.
+ */
+ public void pollAndProcessInput()
+ {
+ JXInputManager.updateFeatures();
+
+ mSensorRead.setTime( JXInputManager.getLastUpdateTime() );
+
+ mRotTransX.rotX( mConfig.getRotational( DeviceConfiguration.AXIS_X ) );
+ mRotTransY.rotY( mConfig.getRotational( DeviceConfiguration.AXIS_Y ) );
+ mRotTransZ.rotZ( mConfig.getRotational( DeviceConfiguration.AXIS_Z ) );
+
+ mPosition.set(
+ mConfig.getTranslational( DeviceConfiguration.AXIS_X ),
+ mConfig.getTranslational( DeviceConfiguration.AXIS_Y ),
+ mConfig.getTranslational( DeviceConfiguration.AXIS_Z )
+ );
+
+ mNewTransform.set( mPosition );
+
+ mNewTransform.mul( mRotTransX );
+ mNewTransform.mul( mRotTransY );
+ mNewTransform.mul( mRotTransZ );
+
+ mSensorRead.set( mNewTransform );
+ mSensor.setNextSensorRead( mSensorRead );
+ }
+
+
+ /**
+ * Not called by current j3d implementation.
+ */
+ public void processStreamInput()
+ {
+ // Intentionally empty
+ }
+
+
+ /**
+ * Reset state.
+ */
+ public void setNominalPositionAndOrientation()
+ {
+ mSensorRead.setTime( JXInputManager.getLastUpdateTime() );
+
+ mRotTransX.rotX( 0.0 );
+ mRotTransY.rotY( 0.0 );
+ mRotTransZ.rotZ( 0.0 );
+
+ mPosition.set( mInitPos );
+
+ mNewTransform.set( mPosition );
+
+ mNewTransform.mul( mRotTransX );
+ mNewTransform.mul( mRotTransY );
+ mNewTransform.mul( mRotTransZ );
+
+ mSensorRead.set( mNewTransform );
+ mSensor.setNextSensorRead( mSensorRead );
+
+ }
+
+
+ /**
+ * Set the processing mode.
+ * Only NON_BLOCKING is allowed!
+ */
+ public void setProcessingMode(int param)
+ {
+ if ( param != InputDevice.NON_BLOCKING )
+ throw new IllegalArgumentException("Processing mode must be NON_BLOCKING");
+
+ }
+
+}
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/j3d/package.html b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/j3d/package.html
new file mode 100644
index 0000000..9b92964
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/j3d/package.html
@@ -0,0 +1,11 @@
+
+
+
+ true==getState() as long as they are pressed down.
+ * Togglebuttons will change their state once they are pressed and keep that state
+ * until they are pressed again.
+ * @return [ PUSHBUTTON | TOGGLEBUTTON ]
+ */
+ public int getType()
+ {
+ return Button.PUSHBUTTON;
+ }
+
+
+ /**
+ * Denote wether this feature has changed beyond it's resolution since it got last
+ * updated.
+ */
+ public boolean hasChanged()
+ {
+ return true;
+ }
+
+}
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/keyboard/KeyboardDriver.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/keyboard/KeyboardDriver.java
new file mode 100644
index 0000000..7eb6232
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/keyboard/KeyboardDriver.java
@@ -0,0 +1,141 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 9. April 2002, 22:43
+//**********************************************************************************************
+package de.hardcode.jxinput.keyboard;
+
+import java.awt.event.KeyListener;
+import java.awt.event.KeyEvent;
+import java.util.HashMap;
+import java.security.InvalidParameterException;
+
+
+
+/**
+ * Listen to a JComponent handle handle all associated button objects.
+ * This is the main worker class for JXKeyboardInputDevice.
+ *
+ * @author Herkules
+ */
+class KeyboardDriver implements KeyListener
+{
+// HashMap mKeysToObserveMap = new HashMap();
+
+ int mNumberOfKeysObserved = 0;
+ KeyButton [] mKeysObserved = new KeyButton [ 0x100 ];
+
+
+ /**
+ * Creates a new instance of KeyboardDriver.
+ */
+ public KeyboardDriver()
+ {
+ }
+
+
+ /**
+ * How many buttons are registered?
+ */
+ final int getNumberOfButtons()
+ {
+ return mNumberOfKeysObserved;
+// return mKeysToObserveMap.size();
+ }
+
+
+ /**
+ * Place a new button under my observation.
+ */
+ final boolean registerKeyButton( KeyButton b )
+ {
+ final int keycode = b.getKeyCode();
+
+ if ( 0 > keycode || 0x100 < keycode )
+ throw new InvalidKeyCodeException();
+
+ if ( null == mKeysObserved[ keycode ] )
+ {
+ mKeysObserved[ keycode ] = b;
+ mNumberOfKeysObserved++;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+
+// Integer code = new Integer( b.getKeyCode() );
+// if ( ! mKeysToObserveMap.containsKey( code ) )
+// {
+// mKeysToObserveMap.put( code, b );
+// return true;
+// }
+// else
+// {
+// return false;
+// }
+ }
+
+ final void unregisterKeyButton( KeyButton b )
+ {
+ final int keycode = b.getKeyCode();
+
+ if ( 0 > keycode || 0x100 < keycode )
+ throw new InvalidKeyCodeException();
+
+ if ( null != mKeysObserved[ b.getKeyCode() ] )
+ {
+ mKeysObserved[ keycode ] = null;
+ mNumberOfKeysObserved--;
+ }
+
+// Integer code = new Integer( b.getKeyCode() );
+// mKeysToObserveMap.remove( code );
+ }
+
+
+ /**
+ * Retrieve the button from its keycode.
+ */
+ final KeyButton getButton( int keycode )
+ {
+ if ( 0 > keycode || 0x100 < keycode )
+ throw new InvalidKeyCodeException();
+
+ return mKeysObserved[ keycode ];
+
+// Integer code = new Integer( keycode );
+// return (KeyButton)mKeysToObserveMap.get( code );
+ }
+
+
+ //*********************************************************************************************
+ //
+ // Implement KeyListener
+ //
+ //*********************************************************************************************
+
+ public void keyPressed( KeyEvent keyEvent )
+ {
+ KeyButton b = getButton( keyEvent.getKeyCode() );
+ if ( null != b )
+ b.setIsPressed( true );
+ }
+
+ public void keyReleased( KeyEvent keyEvent )
+ {
+ KeyButton b = getButton( keyEvent.getKeyCode() );
+ if ( null != b )
+ b.setIsPressed( false );
+ }
+
+ public void keyTyped( KeyEvent keyEvent )
+ {
+ // Intentionally empty.
+ }
+
+}
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/keyboard/package.html b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/keyboard/package.html
new file mode 100644
index 0000000..e1021d1
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/keyboard/package.html
@@ -0,0 +1,10 @@
+
+
+
+
+ Axis.ROTATION,
+ * Axis.TRANSLATION or Axis.SLIDER.
+ */
+ public void setType( int type )
+ {
+ if ( Axis.ROTATION != type
+ && Axis.TRANSLATION != type
+ && Axis.SLIDER != type
+ )
+ throw new InvalidParameterException( "Invalid type for axis!" );
+
+ mType = type;
+ }
+
+ /**
+ * Update features under my control.
+ */
+ final void update( long deltaT )
+ {
+ double change = mSpeed * deltaT;
+ double springchange = mSpringSpeed * deltaT;
+ boolean doincrease = ( null != mButtonIncrease && mButtonIncrease.getState() );
+ boolean dodecrease = ( null != mButtonDecrease && mButtonDecrease.getState() );
+ boolean iscontrolled = doincrease || dodecrease;
+
+ double controlledchange = 0.0;
+ if ( doincrease )
+ controlledchange += change;
+ if ( dodecrease )
+ controlledchange -= change;
+
+ mCurrentValue += controlledchange;
+
+ if ( mCurrentValue > 0.0 && ! doincrease )
+ {
+ springchange = Math.min( mCurrentValue, springchange );
+ mCurrentValue -= springchange;
+ }
+ if ( mCurrentValue < 0.0 && ! dodecrease )
+ {
+ springchange = Math.min( -mCurrentValue, springchange );
+ mCurrentValue += springchange;
+ }
+
+ //
+ // Hold value within range
+ //
+ if ( mCurrentValue > 1.0 )
+ mCurrentValue = 1.0;
+ double lowerlimit = Axis.SLIDER == mType ? 0.0 : -1.0;
+ if ( mCurrentValue < lowerlimit )
+ mCurrentValue = lowerlimit;
+ }
+
+
+ /**
+ * Set the button to increase the axis for a single button axis.
+ */
+ public final void setIncreaseButton( Button b )
+ {
+ if ( null == b )
+ throw new InvalidParameterException( "Button may not be null!" );
+
+ mButtonIncrease = b;
+ }
+
+
+ /**
+ * Set the buttons to increase and descrease the axis.
+ */
+ public final void setButtons( Button increase, Button decrease )
+ {
+ if ( null == increase || null == decrease )
+ throw new InvalidParameterException( "Buttons may not be null!" );
+
+ mButtonIncrease = increase;
+ mButtonDecrease = decrease;
+ }
+
+
+ public final void setSpeed( double speed )
+ {
+ mSpeed = speed;
+ }
+
+ public final void setSpringSpeed( double springspeed )
+ {
+ mSpringSpeed = springspeed;
+ }
+
+
+ public final void setTimeFor0To1( int ms )
+ {
+ if ( 0 >= ms )
+ mSpeed = 0.0;
+ else
+ mSpeed = 1.0/ ms;
+ }
+ public final void setTimeFor1To0( int ms )
+ {
+ if ( 0 >= ms )
+ mSpringSpeed = 0.0;
+ else
+ mSpringSpeed = 1.0/ ms;
+ }
+
+
+ public final void setName( String name )
+ {
+ mName = name;
+ }
+
+ //*********************************************************************************************
+ //
+ // Implement Axis
+ //
+ //*********************************************************************************************
+
+ /**
+ * Features may have a name provided e.g. by the driver.
+ */
+ public String getName()
+ {
+ return mName;
+ }
+
+ /**
+ * Inform about the resolution of the axis.
+ *
+ * @return resolution, e.g. 2^-16
+ */
+ public double getResolution()
+ {
+ return 1.0/65536.0;
+ }
+
+
+ /**
+ * Retrieve the type of the axis.
+ * @return [ TRANSLATION | ROTATION | SLIDER ]
+ */
+ public int getType()
+ {
+ return mType;
+ }
+
+ /** Returns the current value of the axis.
+ * The range of the result depends on the axis type.
+ *
+ * @return value [-1.0,1.0] or [0.0,1.0]
+ */
+ public double getValue()
+ {
+ return mCurrentValue;
+ }
+
+ /** Denote wether this feature has changed beyond it's resolution since it got last
+ * updated.
+ */
+ public boolean hasChanged()
+ {
+ return true;
+ }
+
+}
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/virtual/VirtualDriver.java b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/virtual/VirtualDriver.java
new file mode 100644
index 0000000..5952eff
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/virtual/VirtualDriver.java
@@ -0,0 +1,95 @@
+//**********************************************************************************************
+// (C) Copyright 2002 by Dipl. Phys. Joerg Plewe, HARDCODE Development
+// All rights reserved. Copying, modification,
+// distribution or publication without the prior written
+// consent of the author is prohibited.
+//
+// Created on 9. April 2002, 22:43
+//**********************************************************************************************
+package de.hardcode.jxinput.virtual;
+
+import java.util.ArrayList;
+import de.hardcode.jxinput.Axis;
+
+
+
+/**
+ * This is the main worker class for JXVirtualInputDevice.
+ *
+ * @author Herkules
+ */
+class VirtualDriver
+{
+
+ private final VirtualAxis[] mVAxes = new VirtualAxis[ Axis.NUMBER_OF_ID ];
+
+ /**
+ * Creates a new instance of KeyboardDriver.
+ */
+ VirtualDriver()
+ {
+ }
+
+
+ /**
+ * Update features under my control.
+ */
+ final void update( long deltaT )
+ {
+ //
+ // Delegate the update call to the axes in use.
+ //
+ for ( int i = 0; i < mVAxes.length; i++ )
+ {
+ if ( null != mVAxes[ i ] )
+ mVAxes[ i ].update( deltaT );
+ }
+ }
+
+
+ /**
+ * How many axes are registered?
+ */
+ final int getNumberOfAxes()
+ {
+ int ctr = 0;
+ for ( int i = 0; i < mVAxes.length; i++ )
+ {
+ if ( null != mVAxes[ i ] )
+ ctr++;
+ }
+ return ctr;
+ }
+
+ Axis getAxis(int idx)
+ {
+ return mVAxes[ idx ];
+ }
+
+
+ /**
+ * Place a new axis under my observation.
+ */
+ final void registerVirtualAxis( int id, VirtualAxis a )
+ {
+ mVAxes[ id ] = a;
+ }
+
+
+ /**
+ * Remove an axis from my control.
+ */
+ final void unregisterVirtualAxis( VirtualAxis a )
+ {
+ for ( int i = 0; i < mVAxes.length; ++i )
+ {
+ if ( mVAxes[ i ] == a )
+ {
+ mVAxes[ i ] = null;
+ break;
+ }
+ }
+ }
+
+
+}
diff --git a/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/virtual/package.html b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/virtual/package.html
new file mode 100644
index 0000000..d8e1d6a
--- /dev/null
+++ b/vendor/JXInput/0.3.4/java/de/hardcode/jxinput/virtual/package.html
@@ -0,0 +1,11 @@
+
+
+
+
+ Package Specification
+
+
+
+
+
diff --git a/vendor/JavaWinampApi/1.1/java/com/qotsa/jni/controller/JNIWinamp.java b/vendor/JavaWinampApi/1.1/java/com/qotsa/jni/controller/JNIWinamp.java
new file mode 100644
index 0000000..8da725e
--- /dev/null
+++ b/vendor/JavaWinampApi/1.1/java/com/qotsa/jni/controller/JNIWinamp.java
@@ -0,0 +1,227 @@
+/*
+ * JNIWinamp.java
+ *
+ * Created on 23 de Abril de 2007, 20:41
+ *
+ * To change this template, choose Tools | Template Manager
+ * and open the template in the editor.
+ */
+
+package com.qotsa.jni.controller;
+
+import java.io.IOException;
+
+/**
+ *
+ * @author Francisco Guimarães
+ */
+final class JNIWinamp {
+
+ static {
+ System.loadLibrary("wpcom");
+ }
+
+ /**
+ * Verify if Winamp is started
+ * and if not started, starts it
+ * @return True - if successful run Winamp
+ * False - if not successful run Winamp
+ */
+
+ protected static native boolean run() throws UnsatisfiedLinkError;
+
+ /*
+ * Exit Winamp
+ * @return True - if successful exit
+ * False - if not successful exit
+ */
+ protected static native boolean exit() throws UnsatisfiedLinkError;
+
+ /**
+ * Play Winamp.
+ *
+ */
+ protected static native boolean play() throws UnsatisfiedLinkError;
+
+ /**
+ * Stop Winamp.
+ *
+ */
+ protected static native boolean stop() throws UnsatisfiedLinkError;
+
+ /**
+ * Resume Winamp.
+ *
+ */
+ protected static native boolean resume() throws UnsatisfiedLinkError;
+
+ /**
+ * Pause Winamp.
+ *
+ */
+ protected static native boolean pause() throws UnsatisfiedLinkError;
+
+ /**
+ * Go to Previous Track.
+ *
+ */
+ protected static native boolean previousTrack() throws UnsatisfiedLinkError;
+
+ /**
+ * Go to Next Track.
+ *
+ */
+ protected static native boolean nextTrack() throws UnsatisfiedLinkError;
+
+ /**
+ * Fowards 5 seconds on the current song.
+ *
+ */
+ protected static native boolean fwd5Secs() throws UnsatisfiedLinkError;
+
+ /**
+ * Rewinds 5 seconds on the current song.
+ *
+ */
+ protected static native boolean rew5Secs() throws UnsatisfiedLinkError;
+
+ /**
+ * Increase Volume.
+ *
+ */
+ protected static native boolean increaseVolume() throws UnsatisfiedLinkError;
+
+ /**
+ * Decrease Volume.
+ *
+ */
+ protected static native boolean decreaseVolume() throws UnsatisfiedLinkError;
+
+ /**
+ * Increase Volume.
+ * @param percent Percent to Increase.
+ */
+ protected static native boolean increaseVolumePercent(int percent) throws UnsatisfiedLinkError;
+
+ /**
+ * Decrease Volume.
+ * @param percent Percent to Decrease.
+ */
+ protected static native boolean decreaseVolumePercent(int percent) throws UnsatisfiedLinkError;
+
+ /**
+ * Adjust Volume
+ * @param pos Position to Set Volume between 0 and 99.
+ */
+ protected static native boolean setVolume(int pos) throws UnsatisfiedLinkError;
+
+ /**
+ * Get Volume.
+ * @return volume.
+ */
+ protected static native int getVolume() throws UnsatisfiedLinkError;
+
+ /**
+ * Go to a Specified Position in the List.
+ * @param pos Position.
+ */
+ protected static native boolean setPlaylistPosition(int pos) throws UnsatisfiedLinkError;
+
+ /**
+ * Clear List.
+ *
+ */
+ protected static native boolean clearPlayList() throws UnsatisfiedLinkError;
+
+ /**
+ * Refresh List´s Cache.
+ *
+ */
+ protected static native boolean refreshPlayListCache() throws UnsatisfiedLinkError;
+
+ /**
+ * Return the PlayListLength.
+ * @return List Length.
+ */
+ protected static native int getPlayListLength() throws UnsatisfiedLinkError;
+
+ /**
+ * Write a Playlist in Package Specification
+
+
+
+
+
diff --git a/vendor/commons-logging/1.1.1/commons-logging-1.1.1.jar b/vendor/commons-logging/1.1.1/commons-logging-1.1.1.jar
new file mode 100644
index 0000000..8758a96
Binary files /dev/null and b/vendor/commons-logging/1.1.1/commons-logging-1.1.1.jar differ
diff --git a/vendor/commons-logging/1.1.1/commons-logging-adapters-1.1.1.jar b/vendor/commons-logging/1.1.1/commons-logging-adapters-1.1.1.jar
new file mode 100644
index 0000000..2f23c35
Binary files /dev/null and b/vendor/commons-logging/1.1.1/commons-logging-adapters-1.1.1.jar differ
diff --git a/vendor/commons-logging/1.1.1/commons-logging-api-1.1.1.jar b/vendor/commons-logging/1.1.1/commons-logging-api-1.1.1.jar
new file mode 100644
index 0000000..bd45116
Binary files /dev/null and b/vendor/commons-logging/1.1.1/commons-logging-api-1.1.1.jar differ
diff --git a/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/Log.java b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/Log.java
new file mode 100644
index 0000000..1fef2f0
--- /dev/null
+++ b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/Log.java
@@ -0,0 +1,246 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.commons.logging;
+
+/**
+ * Log are (in order):
+ *
+ *
+ * The mapping of these log levels to the concepts used by the underlying
+ * logging system is implementation dependent.
+ * The implemention should ensure, though, that this ordering behaves
+ * as expected.
Performance is often a logging concern. + * By examining the appropriate property, + * a component can avoid expensive operations (producing information + * to be logged).
+ * + * For example,
+ *
+ *
+ * if (log.isDebugEnabled()) {
+ * ... do something expensive ...
+ * log.debug(theResult);
+ * }
+ *
Configuration of the underlying logging system will generally be done + * external to the Logging APIs, through whatever mechanism is supported by + * that system.
+ * + * @author Scott Sanders + * @author Rod Waldhoff + * @version $Id: Log.java 424107 2006-07-20 23:15:42Z skitching $ + */ +public interface Log { + + + // ----------------------------------------------------- Logging Properties + + + /** + *Is debug logging currently enabled?
+ * + * Call this method to prevent having to perform expensive operations
+ * (for example, String concatenation)
+ * when the log level is more than debug.
Is error logging currently enabled?
+ * + * Call this method to prevent having to perform expensive operations
+ * (for example, String concatenation)
+ * when the log level is more than error.
Is fatal logging currently enabled?
+ * + * Call this method to prevent having to perform expensive operations
+ * (for example, String concatenation)
+ * when the log level is more than fatal.
Is info logging currently enabled?
+ * + * Call this method to prevent having to perform expensive operations
+ * (for example, String concatenation)
+ * when the log level is more than info.
Is trace logging currently enabled?
+ * + * Call this method to prevent having to perform expensive operations
+ * (for example, String concatenation)
+ * when the log level is more than trace.
Is warn logging currently enabled?
+ * + * Call this method to prevent having to perform expensive operations
+ * (for example, String concatenation)
+ * when the log level is more than warn.
Log a message with trace log level.
+ * + * @param message log this message + */ + public void trace(Object message); + + + /** + *Log an error with trace log level.
+ * + * @param message log this message + * @param t log this cause + */ + public void trace(Object message, Throwable t); + + + /** + *Log a message with debug log level.
+ * + * @param message log this message + */ + public void debug(Object message); + + + /** + *Log an error with debug log level.
+ * + * @param message log this message + * @param t log this cause + */ + public void debug(Object message, Throwable t); + + + /** + *Log a message with info log level.
+ * + * @param message log this message + */ + public void info(Object message); + + + /** + *Log an error with info log level.
+ * + * @param message log this message + * @param t log this cause + */ + public void info(Object message, Throwable t); + + + /** + *Log a message with warn log level.
+ * + * @param message log this message + */ + public void warn(Object message); + + + /** + *Log an error with warn log level.
+ * + * @param message log this message + * @param t log this cause + */ + public void warn(Object message, Throwable t); + + + /** + *Log a message with error log level.
+ * + * @param message log this message + */ + public void error(Object message); + + + /** + *Log an error with error log level.
+ * + * @param message log this message + * @param t log this cause + */ + public void error(Object message, Throwable t); + + + /** + *Log a message with fatal log level.
+ * + * @param message log this message + */ + public void fatal(Object message); + + + /** + *Log an error with fatal log level.
+ * + * @param message log this message + * @param t log this cause + */ + public void fatal(Object message, Throwable t); + + +} diff --git a/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/LogConfigurationException.java b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/LogConfigurationException.java new file mode 100644 index 0000000..419725d --- /dev/null +++ b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/LogConfigurationException.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.logging; + + +/** + *An exception that is thrown only if a suitable LogFactory
+ * or Log instance cannot be created by the corresponding
+ * factory methods.
null as its detail message.
+ */
+ public LogConfigurationException() {
+
+ super();
+
+ }
+
+
+ /**
+ * Construct a new exception with the specified detail message.
+ *
+ * @param message The detail message
+ */
+ public LogConfigurationException(String message) {
+
+ super(message);
+
+ }
+
+
+ /**
+ * Construct a new exception with the specified cause and a derived
+ * detail message.
+ *
+ * @param cause The underlying cause
+ */
+ public LogConfigurationException(Throwable cause) {
+
+ this((cause == null) ? null : cause.toString(), cause);
+
+ }
+
+
+ /**
+ * Construct a new exception with the specified detail message and cause.
+ *
+ * @param message The detail message
+ * @param cause The underlying cause
+ */
+ public LogConfigurationException(String message, Throwable cause) {
+
+ super(message + " (Caused by " + cause + ")");
+ this.cause = cause; // Two-argument version requires JDK 1.4 or later
+
+ }
+
+
+ /**
+ * The underlying cause of this exception.
+ */
+ protected Throwable cause = null;
+
+
+ /**
+ * Return the underlying cause of this exception (if any).
+ */
+ public Throwable getCause() {
+
+ return (this.cause);
+
+ }
+
+
+}
diff --git a/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/LogFactory.java b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/LogFactory.java
new file mode 100644
index 0000000..60522af
--- /dev/null
+++ b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/LogFactory.java
@@ -0,0 +1,1824 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.logging;
+
+
+import java.io.BufferedReader;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+
+
+/**
+ * Factory for creating {@link Log} instances, with discovery and + * configuration features similar to that employed by standard Java APIs + * such as JAXP.
+ * + *IMPLEMENTATION NOTE - This implementation is heavily + * based on the SAXParserFactory and DocumentBuilderFactory implementations + * (corresponding to the JAXP pluggability APIs) found in Apache Xerces.
+ * + * @author Craig R. McClanahan + * @author Costin Manolache + * @author Richard A. Sitze + * @version $Revision: 593798 $ $Date: 2007-11-10 18:40:43 +0100 $ + */ + +public abstract class LogFactory { + // Implementation note re AccessController usage + // + // It is important to keep code invoked via an AccessController to small + // auditable blocks. Such code must carefully evaluate all user input + // (parameters, system properties, config file contents, etc). As an + // example, a Log implementation should not write to its logfile + // with an AccessController anywhere in the call stack, otherwise an + // insecure application could configure the log implementation to write + // to a protected file using the privileges granted to JCL rather than + // to the calling application. + // + // Under no circumstance should a non-private method return data that is + // retrieved via an AccessController. That would allow an insecure app + // to invoke that method and obtain data that it is not permitted to have. + // + // Invoking user-supplied code with an AccessController set is not a major + // issue (eg invoking the constructor of the class specified by + // HASHTABLE_IMPLEMENTATION_PROPERTY). That class will be in a different + // trust domain, and therefore must have permissions to do whatever it + // is trying to do regardless of the permissions granted to JCL. There is + // a slight issue in that untrusted code may point that environment var + // to another trusted library, in which case the code runs if both that + // lib and JCL have the necessary permissions even when the untrusted + // caller does not. That's a pretty hard route to exploit though. + + + // ----------------------------------------------------- Manifest Constants + + /** + * The name (priority) of the key in the config file used to
+ * specify the priority of that particular config file. The associated value
+ * is a floating-point number; higher values take priority over lower values.
+ */
+ public static final String PRIORITY_KEY = "priority";
+
+ /**
+ * The name (use_tccl) of the key in the config file used
+ * to specify whether logging classes should be loaded via the thread
+ * context class loader (TCCL), or not. By default, the TCCL is used.
+ */
+ public static final String TCCL_KEY = "use_tccl";
+
+ /**
+ * The name (org.apache.commons.logging.LogFactory) of the property
+ * used to identify the LogFactory implementation
+ * class name. This can be used as a system property, or as an entry in a
+ * configuration properties file.
+ */
+ public static final String FACTORY_PROPERTY =
+ "org.apache.commons.logging.LogFactory";
+
+ /**
+ * The fully qualified class name of the fallback LogFactory
+ * implementation class to use, if no other can be found.
+ */
+ public static final String FACTORY_DEFAULT =
+ "org.apache.commons.logging.impl.LogFactoryImpl";
+
+ /**
+ * The name (commons-logging.properties) of the properties file to search for.
+ */
+ public static final String FACTORY_PROPERTIES =
+ "commons-logging.properties";
+
+ /**
+ * JDK1.3+
+ * 'Service Provider' specification.
+ *
+ */
+ protected static final String SERVICE_ID =
+ "META-INF/services/org.apache.commons.logging.LogFactory";
+
+ /**
+ * The name (org.apache.commons.logging.diagnostics.dest)
+ * of the property used to enable internal commons-logging
+ * diagnostic output, in order to get information on what logging
+ * implementations are being discovered, what classloaders they
+ * are loaded through, etc.
+ * + * If a system property of this name is set then the value is + * assumed to be the name of a file. The special strings + * STDOUT or STDERR (case-sensitive) indicate output to + * System.out and System.err respectively. + *
+ * Diagnostic logging should be used only to debug problematic + * configurations and should not be set in normal production use. + */ + public static final String DIAGNOSTICS_DEST_PROPERTY = + "org.apache.commons.logging.diagnostics.dest"; + + /** + * When null (the usual case), no diagnostic output will be + * generated by LogFactory or LogFactoryImpl. When non-null, + * interesting events will be written to the specified object. + */ + private static PrintStream diagnosticsStream = null; + + /** + * A string that gets prefixed to every message output by the + * logDiagnostic method, so that users can clearly see which + * LogFactory class is generating the output. + */ + private static String diagnosticPrefix; + + /** + *
Setting this system property
+ * (org.apache.commons.logging.LogFactory.HashtableImpl)
+ * value allows the Hashtable used to store
+ * classloaders to be substituted by an alternative implementation.
+ *
+ * Note: LogFactory will print:
+ *
+ * to system error and then continue using a standard Hashtable.
+ *
+ * [ERROR] LogFactory: Load of custom hashtable failed
+ *
+ * Usage: Set this property when Java is invoked
+ * and LogFactory will attempt to load a new instance
+ * of the given implementation class.
+ * For example, running the following ant scriplet:
+ *
+ * will mean that
+ * <java classname="${test.runner}" fork="yes" failonerror="${test.failonerror}">
+ * ...
+ * <sysproperty
+ * key="org.apache.commons.logging.LogFactory.HashtableImpl"
+ * value="org.apache.commons.logging.AltHashtable"/>
+ * </java>
+ * LogFactory will load an instance of
+ * org.apache.commons.logging.AltHashtable.
+ *
+ * A typical use case is to allow a custom + * Hashtable implementation using weak references to be substituted. + * This will allow classloaders to be garbage collected without + * the need to release them (on 1.3+ JVMs only, of course ;) + *
+ */ + public static final String HASHTABLE_IMPLEMENTATION_PROPERTY = + "org.apache.commons.logging.LogFactory.HashtableImpl"; + /** Name used to load the weak hashtable implementation by names */ + private static final String WEAK_HASHTABLE_CLASSNAME = + "org.apache.commons.logging.impl.WeakHashtable"; + + /** + * A reference to the classloader that loaded this class. This is the + * same as LogFactory.class.getClassLoader(). However computing this + * value isn't quite as simple as that, as we potentially need to use + * AccessControllers etc. It's more efficient to compute it once and + * cache it here. + */ + private static ClassLoader thisClassLoader; + + // ----------------------------------------------------------- Constructors + + + /** + * Protected constructor that is not available for public use. + */ + protected LogFactory() { + } + + // --------------------------------------------------------- Public Methods + + + /** + * Return the configuration attribute with the specified name (if any), + * ornull if there is no such attribute.
+ *
+ * @param name Name of the attribute to return
+ */
+ public abstract Object getAttribute(String name);
+
+
+ /**
+ * Return an array containing the names of all currently defined
+ * configuration attributes. If there are no such attributes, a zero
+ * length array is returned.
+ */
+ public abstract String[] getAttributeNames();
+
+
+ /**
+ * Convenience method to derive a name from the specified class and
+ * call getInstance(String) with it.
+ *
+ * @param clazz Class for which a suitable Log name will be derived
+ *
+ * @exception LogConfigurationException if a suitable Log
+ * instance cannot be returned
+ */
+ public abstract Log getInstance(Class clazz)
+ throws LogConfigurationException;
+
+
+ /**
+ * Construct (if necessary) and return a Log instance,
+ * using the factory's current set of configuration attributes.
NOTE - Depending upon the implementation of
+ * the LogFactory you are using, the Log
+ * instance you are returned may or may not be local to the current
+ * application, and may or may not be returned again on a subsequent
+ * call with the same name argument.
Log instance to be
+ * returned (the meaning of this name is only known to the underlying
+ * logging implementation that is being wrapped)
+ *
+ * @exception LogConfigurationException if a suitable Log
+ * instance cannot be returned
+ */
+ public abstract Log getInstance(String name)
+ throws LogConfigurationException;
+
+
+ /**
+ * Release any internal references to previously created {@link Log}
+ * instances returned by this factory. This is useful in environments
+ * like servlet containers, which implement application reloading by
+ * throwing away a ClassLoader. Dangling references to objects in that
+ * class loader would prevent garbage collection.
+ */
+ public abstract void release();
+
+
+ /**
+ * Remove any configuration attribute associated with the specified name.
+ * If there is no such attribute, no action is taken.
+ *
+ * @param name Name of the attribute to remove
+ */
+ public abstract void removeAttribute(String name);
+
+
+ /**
+ * Set the configuration attribute with the specified name. Calling
+ * this with a null value is equivalent to calling
+ * removeAttribute(name).
+ *
+ * @param name Name of the attribute to set
+ * @param value Value of the attribute to set, or null
+ * to remove any setting for this attribute
+ */
+ public abstract void setAttribute(String name, Object value);
+
+
+ // ------------------------------------------------------- Static Variables
+
+
+ /**
+ * The previously constructed LogFactory instances, keyed by
+ * the ClassLoader with which it was created.
+ */
+ protected static Hashtable factories = null;
+
+ /**
+ * Prevously constructed LogFactory instance as in the
+ * factories map, but for the case where
+ * getClassLoader returns null.
+ * This can happen when:
+ * factories is a Hashtable (not a HashMap),
+ * and hashtables don't allow null as a key.
+ */
+ protected static LogFactory nullClassLoaderFactory = null;
+
+ /**
+ * Create the hashtable which will be used to store a map of
+ * (context-classloader -> logfactory-object). Version 1.2+ of Java
+ * supports "weak references", allowing a custom Hashtable class
+ * to be used which uses only weak references to its keys. Using weak
+ * references can fix memory leaks on webapp unload in some cases (though
+ * not all). Version 1.1 of Java does not support weak references, so we
+ * must dynamically determine which we are using. And just for fun, this
+ * code also supports the ability for a system property to specify an
+ * arbitrary Hashtable implementation name.
+ * + * Note that the correct way to ensure no memory leaks occur is to ensure + * that LogFactory.release(contextClassLoader) is called whenever a + * webapp is undeployed. + */ + private static final Hashtable createFactoryStore() { + Hashtable result = null; + String storeImplementationClass; + try { + storeImplementationClass = getSystemProperty(HASHTABLE_IMPLEMENTATION_PROPERTY, null); + } catch(SecurityException ex) { + // Permissions don't allow this to be accessed. Default to the "modern" + // weak hashtable implementation if it is available. + storeImplementationClass = null; + } + + if (storeImplementationClass == null) { + storeImplementationClass = WEAK_HASHTABLE_CLASSNAME; + } + try { + Class implementationClass = Class.forName(storeImplementationClass); + result = (Hashtable) implementationClass.newInstance(); + + } catch (Throwable t) { + // ignore + if (!WEAK_HASHTABLE_CLASSNAME.equals(storeImplementationClass)) { + // if the user's trying to set up a custom implementation, give a clue + if (isDiagnosticsEnabled()) { + // use internal logging to issue the warning + logDiagnostic("[ERROR] LogFactory: Load of custom hashtable failed"); + } else { + // we *really* want this output, even if diagnostics weren't + // explicitly enabled by the user. + System.err.println("[ERROR] LogFactory: Load of custom hashtable failed"); + } + } + } + if (result == null) { + result = new Hashtable(); + } + return result; + } + + + // --------------------------------------------------------- Static Methods + + /** Utility method to safely trim a string. */ + private static String trim(String src) { + if (src == null) { + return null; + } + return src.trim(); + } + + /** + *
Construct (if necessary) and return a LogFactory
+ * instance, using the following ordered lookup procedure to determine
+ * the name of the implementation class to be loaded.
org.apache.commons.logging.LogFactory system
+ * property.commons-logging.properties
+ * file, if found in the class path of this class. The configuration
+ * file is in standard java.util.Properties format and
+ * contains the fully qualified name of the implementation class
+ * with the key being the system property defined above.org.apache.commons.logging.impl.LogFactoryImpl).NOTE - If the properties file method of identifying the
+ * LogFactory implementation class is utilized, all of the
+ * properties defined in this file will be set as configuration attributes
+ * on the corresponding LogFactory instance.
NOTE - In a multithreaded environment it is possible + * that two different instances will be returned for the same + * classloader environment. + *
+ * + * @exception LogConfigurationException if the implementation class is not + * available or cannot be instantiated. + */ + public static LogFactory getFactory() throws LogConfigurationException { + // Identify the class loader we will be using + ClassLoader contextClassLoader = getContextClassLoaderInternal(); + + if (contextClassLoader == null) { + // This is an odd enough situation to report about. This + // output will be a nuisance on JDK1.1, as the system + // classloader is null in that environment. + if (isDiagnosticsEnabled()) { + logDiagnostic("Context classloader is null."); + } + } + + // Return any previously registered factory for this class loader + LogFactory factory = getCachedFactory(contextClassLoader); + if (factory != null) { + return factory; + } + + if (isDiagnosticsEnabled()) { + logDiagnostic( + "[LOOKUP] LogFactory implementation requested for the first time for context classloader " + + objectId(contextClassLoader)); + logHierarchy("[LOOKUP] ", contextClassLoader); + } + + // Load properties file. + // + // If the properties file exists, then its contents are used as + // "attributes" on the LogFactory implementation class. One particular + // property may also control which LogFactory concrete subclass is + // used, but only if other discovery mechanisms fail.. + // + // As the properties file (if it exists) will be used one way or + // another in the end we may as well look for it first. + + Properties props = getConfigurationFile(contextClassLoader, FACTORY_PROPERTIES); + + // Determine whether we will be using the thread context class loader to + // load logging classes or not by checking the loaded properties file (if any). + ClassLoader baseClassLoader = contextClassLoader; + if (props != null) { + String useTCCLStr = props.getProperty(TCCL_KEY); + if (useTCCLStr != null) { + // The Boolean.valueOf(useTCCLStr).booleanValue() formulation + // is required for Java 1.2 compatability. + if (Boolean.valueOf(useTCCLStr).booleanValue() == false) { + // Don't use current context classloader when locating any + // LogFactory or Log classes, just use the class that loaded + // this abstract class. When this class is deployed in a shared + // classpath of a container, it means webapps cannot deploy their + // own logging implementations. It also means that it is up to the + // implementation whether to load library-specific config files + // from the TCCL or not. + baseClassLoader = thisClassLoader; + } + } + } + + // Determine which concrete LogFactory subclass to use. + // First, try a global system property + if (isDiagnosticsEnabled()) { + logDiagnostic( + "[LOOKUP] Looking for system property [" + FACTORY_PROPERTY + + "] to define the LogFactory subclass to use..."); + } + + try { + String factoryClass = getSystemProperty(FACTORY_PROPERTY, null); + if (factoryClass != null) { + if (isDiagnosticsEnabled()) { + logDiagnostic( + "[LOOKUP] Creating an instance of LogFactory class '" + factoryClass + + "' as specified by system property " + FACTORY_PROPERTY); + } + + factory = newFactory(factoryClass, baseClassLoader, contextClassLoader); + } else { + if (isDiagnosticsEnabled()) { + logDiagnostic( + "[LOOKUP] No system property [" + FACTORY_PROPERTY + + "] defined."); + } + } + } catch (SecurityException e) { + if (isDiagnosticsEnabled()) { + logDiagnostic( + "[LOOKUP] A security exception occurred while trying to create an" + + " instance of the custom factory class" + + ": [" + trim(e.getMessage()) + + "]. Trying alternative implementations..."); + } + ; // ignore + } catch(RuntimeException e) { + // This is not consistent with the behaviour when a bad LogFactory class is + // specified in a services file. + // + // One possible exception that can occur here is a ClassCastException when + // the specified class wasn't castable to this LogFactory type. + if (isDiagnosticsEnabled()) { + logDiagnostic( + "[LOOKUP] An exception occurred while trying to create an" + + " instance of the custom factory class" + + ": [" + trim(e.getMessage()) + + "] as specified by a system property."); + } + throw e; + } + + + // Second, try to find a service by using the JDK1.3 class + // discovery mechanism, which involves putting a file with the name + // of an interface class in the META-INF/services directory, where the + // contents of the file is a single line specifying a concrete class + // that implements the desired interface. + + if (factory == null) { + if (isDiagnosticsEnabled()) { + logDiagnostic( + "[LOOKUP] Looking for a resource file of name [" + SERVICE_ID + + "] to define the LogFactory subclass to use..."); + } + try { + InputStream is = getResourceAsStream(contextClassLoader, + SERVICE_ID); + + if( is != null ) { + // This code is needed by EBCDIC and other strange systems. + // It's a fix for bugs reported in xerces + BufferedReader rd; + try { + rd = new BufferedReader(new InputStreamReader(is, "UTF-8")); + } catch (java.io.UnsupportedEncodingException e) { + rd = new BufferedReader(new InputStreamReader(is)); + } + + String factoryClassName = rd.readLine(); + rd.close(); + + if (factoryClassName != null && + ! "".equals(factoryClassName)) { + if (isDiagnosticsEnabled()) { + logDiagnostic( + "[LOOKUP] Creating an instance of LogFactory class " + factoryClassName + + " as specified by file '" + SERVICE_ID + + "' which was present in the path of the context" + + " classloader."); + } + factory = newFactory(factoryClassName, baseClassLoader, contextClassLoader ); + } + } else { + // is == null + if (isDiagnosticsEnabled()) { + logDiagnostic( + "[LOOKUP] No resource file with name '" + SERVICE_ID + + "' found."); + } + } + } catch( Exception ex ) { + // note: if the specified LogFactory class wasn't compatible with LogFactory + // for some reason, a ClassCastException will be caught here, and attempts will + // continue to find a compatible class. + if (isDiagnosticsEnabled()) { + logDiagnostic( + "[LOOKUP] A security exception occurred while trying to create an" + + " instance of the custom factory class" + + ": [" + trim(ex.getMessage()) + + "]. Trying alternative implementations..."); + } + ; // ignore + } + } + + + // Third try looking into the properties file read earlier (if found) + + if (factory == null) { + if (props != null) { + if (isDiagnosticsEnabled()) { + logDiagnostic( + "[LOOKUP] Looking in properties file for entry with key '" + + FACTORY_PROPERTY + + "' to define the LogFactory subclass to use..."); + } + String factoryClass = props.getProperty(FACTORY_PROPERTY); + if (factoryClass != null) { + if (isDiagnosticsEnabled()) { + logDiagnostic( + "[LOOKUP] Properties file specifies LogFactory subclass '" + + factoryClass + "'"); + } + factory = newFactory(factoryClass, baseClassLoader, contextClassLoader); + + // TODO: think about whether we need to handle exceptions from newFactory + } else { + if (isDiagnosticsEnabled()) { + logDiagnostic( + "[LOOKUP] Properties file has no entry specifying LogFactory subclass."); + } + } + } else { + if (isDiagnosticsEnabled()) { + logDiagnostic( + "[LOOKUP] No properties file available to determine" + + " LogFactory subclass from.."); + } + } + } + + + // Fourth, try the fallback implementation class + + if (factory == null) { + if (isDiagnosticsEnabled()) { + logDiagnostic( + "[LOOKUP] Loading the default LogFactory implementation '" + FACTORY_DEFAULT + + "' via the same classloader that loaded this LogFactory" + + " class (ie not looking in the context classloader)."); + } + + // Note: unlike the above code which can try to load custom LogFactory + // implementations via the TCCL, we don't try to load the default LogFactory + // implementation via the context classloader because: + // * that can cause problems (see comments in newFactory method) + // * no-one should be customising the code of the default class + // Yes, we do give up the ability for the child to ship a newer + // version of the LogFactoryImpl class and have it used dynamically + // by an old LogFactory class in the parent, but that isn't + // necessarily a good idea anyway. + factory = newFactory(FACTORY_DEFAULT, thisClassLoader, contextClassLoader); + } + + if (factory != null) { + /** + * Always cache using context class loader. + */ + cacheFactory(contextClassLoader, factory); + + if( props!=null ) { + Enumeration names = props.propertyNames(); + while (names.hasMoreElements()) { + String name = (String) names.nextElement(); + String value = props.getProperty(name); + factory.setAttribute(name, value); + } + } + } + + return factory; + } + + + /** + * Convenience method to return a named logger, without the application + * having to care about factories. + * + * @param clazz Class from which a log name will be derived + * + * @exception LogConfigurationException if a suitableLog
+ * instance cannot be returned
+ */
+ public static Log getLog(Class clazz)
+ throws LogConfigurationException {
+
+ return (getFactory().getInstance(clazz));
+
+ }
+
+
+ /**
+ * Convenience method to return a named logger, without the application
+ * having to care about factories.
+ *
+ * @param name Logical name of the Log instance to be
+ * returned (the meaning of this name is only known to the underlying
+ * logging implementation that is being wrapped)
+ *
+ * @exception LogConfigurationException if a suitable Log
+ * instance cannot be returned
+ */
+ public static Log getLog(String name)
+ throws LogConfigurationException {
+
+ return (getFactory().getInstance(name));
+
+ }
+
+
+ /**
+ * Release any internal references to previously created {@link LogFactory}
+ * instances that have been associated with the specified class loader
+ * (if any), after calling the instance method release() on
+ * each of them.
+ *
+ * @param classLoader ClassLoader for which to release the LogFactory
+ */
+ public static void release(ClassLoader classLoader) {
+
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic("Releasing factory for classloader " + objectId(classLoader));
+ }
+ synchronized (factories) {
+ if (classLoader == null) {
+ if (nullClassLoaderFactory != null) {
+ nullClassLoaderFactory.release();
+ nullClassLoaderFactory = null;
+ }
+ } else {
+ LogFactory factory = (LogFactory) factories.get(classLoader);
+ if (factory != null) {
+ factory.release();
+ factories.remove(classLoader);
+ }
+ }
+ }
+
+ }
+
+
+ /**
+ * Release any internal references to previously created {@link LogFactory}
+ * instances, after calling the instance method release() on
+ * each of them. This is useful in environments like servlet containers,
+ * which implement application reloading by throwing away a ClassLoader.
+ * Dangling references to objects in that class loader would prevent
+ * garbage collection.
+ */
+ public static void releaseAll() {
+
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic("Releasing factory for all classloaders.");
+ }
+ synchronized (factories) {
+ Enumeration elements = factories.elements();
+ while (elements.hasMoreElements()) {
+ LogFactory element = (LogFactory) elements.nextElement();
+ element.release();
+ }
+ factories.clear();
+
+ if (nullClassLoaderFactory != null) {
+ nullClassLoaderFactory.release();
+ nullClassLoaderFactory = null;
+ }
+ }
+
+ }
+
+
+ // ------------------------------------------------------ Protected Methods
+
+ /**
+ * Safely get access to the classloader for the specified class.
+ * + * Theoretically, calling getClassLoader can throw a security exception, + * and so should be done under an AccessController in order to provide + * maximum flexibility. However in practice people don't appear to use + * security policies that forbid getClassLoader calls. So for the moment + * all code is written to call this method rather than Class.getClassLoader, + * so that we could put AccessController stuff in this method without any + * disruption later if we need to. + *
+ * Even when using an AccessController, however, this method can still + * throw SecurityException. Commons-logging basically relies on the + * ability to access classloaders, ie a policy that forbids all + * classloader access will also prevent commons-logging from working: + * currently this method will throw an exception preventing the entire app + * from starting up. Maybe it would be good to detect this situation and + * just disable all commons-logging? Not high priority though - as stated + * above, security policies that prevent classloader access aren't common. + *
+ * Note that returning an object fetched via an AccessController would + * technically be a security flaw anyway; untrusted code that has access + * to a trusted JCL library could use it to fetch the classloader for + * a class even when forbidden to do so directly. + * + * @since 1.1 + */ + protected static ClassLoader getClassLoader(Class clazz) { + try { + return clazz.getClassLoader(); + } catch(SecurityException ex) { + if (isDiagnosticsEnabled()) { + logDiagnostic( + "Unable to get classloader for class '" + clazz + + "' due to security restrictions - " + ex.getMessage()); + } + throw ex; + } + } + + /** + * Returns the current context classloader. + *
+ * In versions prior to 1.1, this method did not use an AccessController. + * In version 1.1, an AccessController wrapper was incorrectly added to + * this method, causing a minor security flaw. + *
+ * In version 1.1.1 this change was reverted; this method no longer uses + * an AccessController. User code wishing to obtain the context classloader + * must invoke this method via AccessController.doPrivileged if it needs + * support for that. + * + * @return the context classloader associated with the current thread, + * or null if security doesn't allow it. + * + * @throws LogConfigurationException if there was some weird error while + * attempting to get the context classloader. + * + * @throws SecurityException if the current java security policy doesn't + * allow this class to access the context classloader. + */ + protected static ClassLoader getContextClassLoader() + throws LogConfigurationException { + + return directGetContextClassLoader(); + } + + /** + * Calls LogFactory.directGetContextClassLoader under the control of an + * AccessController class. This means that java code running under a + * security manager that forbids access to ClassLoaders will still work + * if this class is given appropriate privileges, even when the caller + * doesn't have such privileges. Without using an AccessController, the + * the entire call stack must have the privilege before the call is + * allowed. + * + * @return the context classloader associated with the current thread, + * or null if security doesn't allow it. + * + * @throws LogConfigurationException if there was some weird error while + * attempting to get the context classloader. + * + * @throws SecurityException if the current java security policy doesn't + * allow this class to access the context classloader. + */ + private static ClassLoader getContextClassLoaderInternal() + throws LogConfigurationException { + return (ClassLoader)AccessController.doPrivileged( + new PrivilegedAction() { + public Object run() { + return directGetContextClassLoader(); + } + }); + } + + /** + * Return the thread context class loader if available; otherwise return + * null. + *
+ * Most/all code should call getContextClassLoaderInternal rather than + * calling this method directly. + *
+ * The thread context class loader is available for JDK 1.2 + * or later, if certain security conditions are met. + *
+ * Note that no internal logging is done within this method because
+ * this method is called every time LogFactory.getLogger() is called,
+ * and we don't want too much output generated here.
+ *
+ * @exception LogConfigurationException if a suitable class loader
+ * cannot be identified.
+ *
+ * @exception SecurityException if the java security policy forbids
+ * access to the context classloader from one of the classes in the
+ * current call stack.
+ * @since 1.1
+ */
+ protected static ClassLoader directGetContextClassLoader()
+ throws LogConfigurationException
+ {
+ ClassLoader classLoader = null;
+
+ try {
+ // Are we running on a JDK 1.2 or later system?
+ Method method = Thread.class.getMethod("getContextClassLoader",
+ (Class[]) null);
+
+ // Get the thread context class loader (if there is one)
+ try {
+ classLoader = (ClassLoader)method.invoke(Thread.currentThread(),
+ (Object[]) null);
+ } catch (IllegalAccessException e) {
+ throw new LogConfigurationException
+ ("Unexpected IllegalAccessException", e);
+ } catch (InvocationTargetException e) {
+ /**
+ * InvocationTargetException is thrown by 'invoke' when
+ * the method being invoked (getContextClassLoader) throws
+ * an exception.
+ *
+ * getContextClassLoader() throws SecurityException when
+ * the context class loader isn't an ancestor of the
+ * calling class's class loader, or if security
+ * permissions are restricted.
+ *
+ * In the first case (not related), we want to ignore and
+ * keep going. We cannot help but also ignore the second
+ * with the logic below, but other calls elsewhere (to
+ * obtain a class loader) will trigger this exception where
+ * we can make a distinction.
+ */
+ if (e.getTargetException() instanceof SecurityException) {
+ ; // ignore
+ } else {
+ // Capture 'e.getTargetException()' exception for details
+ // alternate: log 'e.getTargetException()', and pass back 'e'.
+ throw new LogConfigurationException
+ ("Unexpected InvocationTargetException", e.getTargetException());
+ }
+ }
+ } catch (NoSuchMethodException e) {
+ // Assume we are running on JDK 1.1
+ classLoader = getClassLoader(LogFactory.class);
+
+ // We deliberately don't log a message here to outputStream;
+ // this message would be output for every call to LogFactory.getLog()
+ // when running on JDK1.1
+ //
+ // if (outputStream != null) {
+ // outputStream.println(
+ // "Method Thread.getContextClassLoader does not exist;"
+ // + " assuming this is JDK 1.1, and that the context"
+ // + " classloader is the same as the class that loaded"
+ // + " the concrete LogFactory class.");
+ // }
+
+ }
+
+ // Return the selected class loader
+ return classLoader;
+ }
+
+ /**
+ * Check cached factories (keyed by contextClassLoader)
+ *
+ * @param contextClassLoader is the context classloader associated
+ * with the current thread. This allows separate LogFactory objects
+ * per component within a container, provided each component has
+ * a distinct context classloader set. This parameter may be null
+ * in JDK1.1, and in embedded systems where jcl-using code is
+ * placed in the bootclasspath.
+ *
+ * @return the factory associated with the specified classloader if
+ * one has previously been created, or null if this is the first time
+ * we have seen this particular classloader.
+ */
+ private static LogFactory getCachedFactory(ClassLoader contextClassLoader)
+ {
+ LogFactory factory = null;
+
+ if (contextClassLoader == null) {
+ // We have to handle this specially, as factories is a Hashtable
+ // and those don't accept null as a key value.
+ //
+ // nb: nullClassLoaderFactory might be null. That's ok.
+ factory = nullClassLoaderFactory;
+ } else {
+ factory = (LogFactory) factories.get(contextClassLoader);
+ }
+
+ return factory;
+ }
+
+ /**
+ * Remember this factory, so later calls to LogFactory.getCachedFactory
+ * can return the previously created object (together with all its
+ * cached Log objects).
+ *
+ * @param classLoader should be the current context classloader. Note that
+ * this can be null under some circumstances; this is ok.
+ *
+ * @param factory should be the factory to cache. This should never be null.
+ */
+ private static void cacheFactory(ClassLoader classLoader, LogFactory factory)
+ {
+ // Ideally we would assert(factory != null) here. However reporting
+ // errors from within a logging implementation is a little tricky!
+
+ if (factory != null) {
+ if (classLoader == null) {
+ nullClassLoaderFactory = factory;
+ } else {
+ factories.put(classLoader, factory);
+ }
+ }
+ }
+
+ /**
+ * Return a new instance of the specified LogFactory
+ * implementation class, loaded by the specified class loader.
+ * If that fails, try the class loader used to load this
+ * (abstract) LogFactory.
+ *
+ *
+ * The problem is the same one that can occur when loading a concrete Log + * subclass via a context classloader. + *
+ * The problem occurs when code running in the context classloader calls + * class X which was loaded via a parent classloader, and class X then calls + * LogFactory.getFactory (either directly or via LogFactory.getLog). Because + * class X was loaded via the parent, it binds to LogFactory loaded via + * the parent. When the code in this method finds some LogFactoryYYYY + * class in the child (context) classloader, and there also happens to be a + * LogFactory class defined in the child classloader, then LogFactoryYYYY + * will be bound to LogFactory@childloader. It cannot be cast to + * LogFactory@parentloader, ie this method cannot return the object as + * the desired type. Note that it doesn't matter if the LogFactory class + * in the child classloader is identical to the LogFactory class in the + * parent classloader, they are not compatible. + *
+ * The solution taken here is to simply print out an error message when + * this occurs then throw an exception. The deployer of the application + * must ensure they remove all occurrences of the LogFactory class from + * the child classloader in order to resolve the issue. Note that they + * do not have to move the custom LogFactory subclass; that is ok as + * long as the only LogFactory class it can find to bind to is in the + * parent classloader. + *
+ * @param factoryClass Fully qualified name of the LogFactory
+ * implementation class
+ * @param classLoader ClassLoader from which to load this class
+ * @param contextClassLoader is the context that this new factory will
+ * manage logging for.
+ *
+ * @exception LogConfigurationException if a suitable instance
+ * cannot be created
+ * @since 1.1
+ */
+ protected static LogFactory newFactory(final String factoryClass,
+ final ClassLoader classLoader,
+ final ClassLoader contextClassLoader)
+ throws LogConfigurationException
+ {
+ // Note that any unchecked exceptions thrown by the createFactory
+ // method will propagate out of this method; in particular a
+ // ClassCastException can be thrown.
+ Object result = AccessController.doPrivileged(
+ new PrivilegedAction() {
+ public Object run() {
+ return createFactory(factoryClass, classLoader);
+ }
+ });
+
+ if (result instanceof LogConfigurationException) {
+ LogConfigurationException ex = (LogConfigurationException) result;
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic(
+ "An error occurred while loading the factory class:"
+ + ex.getMessage());
+ }
+ throw ex;
+ }
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic(
+ "Created object " + objectId(result)
+ + " to manage classloader " + objectId(contextClassLoader));
+ }
+ return (LogFactory)result;
+ }
+
+ /**
+ * Method provided for backwards compatibility; see newFactory version that
+ * takes 3 parameters.
+ *
+ * This method would only ever be called in some rather odd situation.
+ * Note that this method is static, so overriding in a subclass doesn't
+ * have any effect unless this method is called from a method in that
+ * subclass. However this method only makes sense to use from the
+ * getFactory method, and as that is almost always invoked via
+ * LogFactory.getFactory, any custom definition in a subclass would be
+ * pointless. Only a class with a custom getFactory method, then invoked
+ * directly via CustomFactoryImpl.getFactory or similar would ever call
+ * this. Anyway, it's here just in case, though the "managed class loader"
+ * value output to the diagnostics will not report the correct value.
+ */
+ protected static LogFactory newFactory(final String factoryClass,
+ final ClassLoader classLoader) {
+ return newFactory(factoryClass, classLoader, null);
+ }
+
+ /**
+ * Implements the operations described in the javadoc for newFactory.
+ *
+ * @param factoryClass
+ *
+ * @param classLoader used to load the specified factory class. This is
+ * expected to be either the TCCL or the classloader which loaded this
+ * class. Note that the classloader which loaded this class might be
+ * "null" (ie the bootloader) for embedded systems.
+ *
+ * @return either a LogFactory object or a LogConfigurationException object.
+ * @since 1.1
+ */
+ protected static Object createFactory(String factoryClass, ClassLoader classLoader) {
+
+ // This will be used to diagnose bad configurations
+ // and allow a useful message to be sent to the user
+ Class logFactoryClass = null;
+ try {
+ if (classLoader != null) {
+ try {
+ // First the given class loader param (thread class loader)
+
+ // Warning: must typecast here & allow exception
+ // to be generated/caught & recast properly.
+ logFactoryClass = classLoader.loadClass(factoryClass);
+ if (LogFactory.class.isAssignableFrom(logFactoryClass)) {
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic(
+ "Loaded class " + logFactoryClass.getName()
+ + " from classloader " + objectId(classLoader));
+ }
+ } else {
+ //
+ // This indicates a problem with the ClassLoader tree.
+ // An incompatible ClassLoader was used to load the
+ // implementation.
+ // As the same classes
+ // must be available in multiple class loaders,
+ // it is very likely that multiple JCL jars are present.
+ // The most likely fix for this
+ // problem is to remove the extra JCL jars from the
+ // ClassLoader hierarchy.
+ //
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic(
+ "Factory class " + logFactoryClass.getName()
+ + " loaded from classloader " + objectId(logFactoryClass.getClassLoader())
+ + " does not extend '" + LogFactory.class.getName()
+ + "' as loaded by this classloader.");
+ logHierarchy("[BAD CL TREE] ", classLoader);
+ }
+ }
+
+ return (LogFactory) logFactoryClass.newInstance();
+
+ } catch (ClassNotFoundException ex) {
+ if (classLoader == thisClassLoader) {
+ // Nothing more to try, onwards.
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic(
+ "Unable to locate any class called '" + factoryClass
+ + "' via classloader " + objectId(classLoader));
+ }
+ throw ex;
+ }
+ // ignore exception, continue
+ } catch (NoClassDefFoundError e) {
+ if (classLoader == thisClassLoader) {
+ // Nothing more to try, onwards.
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic(
+ "Class '" + factoryClass + "' cannot be loaded"
+ + " via classloader " + objectId(classLoader)
+ + " - it depends on some other class that cannot"
+ + " be found.");
+ }
+ throw e;
+ }
+ // ignore exception, continue
+ } catch(ClassCastException e) {
+ if (classLoader == thisClassLoader) {
+ // There's no point in falling through to the code below that
+ // tries again with thisClassLoader, because we've just tried
+ // loading with that loader (not the TCCL). Just throw an
+ // appropriate exception here.
+
+ final boolean implementsLogFactory = implementsLogFactory(logFactoryClass);
+
+ //
+ // Construct a good message: users may not actual expect that a custom implementation
+ // has been specified. Several well known containers use this mechanism to adapt JCL
+ // to their native logging system.
+ //
+ String msg =
+ "The application has specified that a custom LogFactory implementation should be used but " +
+ "Class '" + factoryClass + "' cannot be converted to '"
+ + LogFactory.class.getName() + "'. ";
+ if (implementsLogFactory) {
+ msg = msg + "The conflict is caused by the presence of multiple LogFactory classes in incompatible classloaders. " +
+ "Background can be found in http://commons.apache.org/logging/tech.html. " +
+ "If you have not explicitly specified a custom LogFactory then it is likely that " +
+ "the container has set one without your knowledge. " +
+ "In this case, consider using the commons-logging-adapters.jar file or " +
+ "specifying the standard LogFactory from the command line. ";
+ } else {
+ msg = msg + "Please check the custom implementation. ";
+ }
+ msg = msg + "Help can be found @http://commons.apache.org/logging/troubleshooting.html.";
+
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic(msg);
+ }
+
+ ClassCastException ex = new ClassCastException(msg);
+ throw ex;
+ }
+
+ // Ignore exception, continue. Presumably the classloader was the
+ // TCCL; the code below will try to load the class via thisClassLoader.
+ // This will handle the case where the original calling class is in
+ // a shared classpath but the TCCL has a copy of LogFactory and the
+ // specified LogFactory implementation; we will fall back to using the
+ // LogFactory implementation from the same classloader as this class.
+ //
+ // Issue: this doesn't handle the reverse case, where this LogFactory
+ // is in the webapp, and the specified LogFactory implementation is
+ // in a shared classpath. In that case:
+ // (a) the class really does implement LogFactory (bad log msg above)
+ // (b) the fallback code will result in exactly the same problem.
+ }
+ }
+
+ /* At this point, either classLoader == null, OR
+ * classLoader was unable to load factoryClass.
+ *
+ * In either case, we call Class.forName, which is equivalent
+ * to LogFactory.class.getClassLoader().load(name), ie we ignore
+ * the classloader parameter the caller passed, and fall back
+ * to trying the classloader associated with this class. See the
+ * javadoc for the newFactory method for more info on the
+ * consequences of this.
+ *
+ * Notes:
+ * * LogFactory.class.getClassLoader() may return 'null'
+ * if LogFactory is loaded by the bootstrap classloader.
+ */
+ // Warning: must typecast here & allow exception
+ // to be generated/caught & recast properly.
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic(
+ "Unable to load factory class via classloader "
+ + objectId(classLoader)
+ + " - trying the classloader associated with this LogFactory.");
+ }
+ logFactoryClass = Class.forName(factoryClass);
+ return (LogFactory) logFactoryClass.newInstance();
+ } catch (Exception e) {
+ // Check to see if we've got a bad configuration
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic("Unable to create LogFactory instance.");
+ }
+ if (logFactoryClass != null
+ && !LogFactory.class.isAssignableFrom(logFactoryClass)) {
+
+ return new LogConfigurationException(
+ "The chosen LogFactory implementation does not extend LogFactory."
+ + " Please check your configuration.",
+ e);
+ }
+ return new LogConfigurationException(e);
+ }
+ }
+
+ /**
+ * Determines whether the given class actually implements LogFactory.
+ * Diagnostic information is also logged.
+ *
+ * Usage: to diagnose whether a classloader conflict is the cause
+ * of incompatibility. The test used is whether the class is assignable from
+ * the LogFactory class loaded by the class's classloader.
+ * @param logFactoryClass Class which may implement LogFactory
+ * @return true if the logFactoryClass does extend
+ * LogFactory when that class is loaded via the same
+ * classloader that loaded the logFactoryClass.
+ */
+ private static boolean implementsLogFactory(Class logFactoryClass) {
+ boolean implementsLogFactory = false;
+ if (logFactoryClass != null) {
+ try {
+ ClassLoader logFactoryClassLoader = logFactoryClass.getClassLoader();
+ if (logFactoryClassLoader == null) {
+ logDiagnostic("[CUSTOM LOG FACTORY] was loaded by the boot classloader");
+ } else {
+ logHierarchy("[CUSTOM LOG FACTORY] ", logFactoryClassLoader);
+ Class factoryFromCustomLoader
+ = Class.forName("org.apache.commons.logging.LogFactory", false, logFactoryClassLoader);
+ implementsLogFactory = factoryFromCustomLoader.isAssignableFrom(logFactoryClass);
+ if (implementsLogFactory) {
+ logDiagnostic("[CUSTOM LOG FACTORY] " + logFactoryClass.getName()
+ + " implements LogFactory but was loaded by an incompatible classloader.");
+ } else {
+ logDiagnostic("[CUSTOM LOG FACTORY] " + logFactoryClass.getName()
+ + " does not implement LogFactory.");
+ }
+ }
+ } catch (SecurityException e) {
+ //
+ // The application is running within a hostile security environment.
+ // This will make it very hard to diagnose issues with JCL.
+ // Consider running less securely whilst debugging this issue.
+ //
+ logDiagnostic("[CUSTOM LOG FACTORY] SecurityException thrown whilst trying to determine whether " +
+ "the compatibility was caused by a classloader conflict: "
+ + e.getMessage());
+ } catch (LinkageError e) {
+ //
+ // This should be an unusual circumstance.
+ // LinkageError's usually indicate that a dependent class has incompatibly changed.
+ // Another possibility may be an exception thrown by an initializer.
+ // Time for a clean rebuild?
+ //
+ logDiagnostic("[CUSTOM LOG FACTORY] LinkageError thrown whilst trying to determine whether " +
+ "the compatibility was caused by a classloader conflict: "
+ + e.getMessage());
+ } catch (ClassNotFoundException e) {
+ //
+ // LogFactory cannot be loaded by the classloader which loaded the custom factory implementation.
+ // The custom implementation is not viable until this is corrected.
+ // Ensure that the JCL jar and the custom class are available from the same classloader.
+ // Running with diagnostics on should give information about the classloaders used
+ // to load the custom factory.
+ //
+ logDiagnostic("[CUSTOM LOG FACTORY] LogFactory class cannot be loaded by classloader which loaded the " +
+ "custom LogFactory implementation. Is the custom factory in the right classloader?");
+ }
+ }
+ return implementsLogFactory;
+ }
+
+ /**
+ * Applets may run in an environment where accessing resources of a loader is
+ * a secure operation, but where the commons-logging library has explicitly
+ * been granted permission for that operation. In this case, we need to
+ * run the operation using an AccessController.
+ */
+ private static InputStream getResourceAsStream(final ClassLoader loader,
+ final String name)
+ {
+ return (InputStream)AccessController.doPrivileged(
+ new PrivilegedAction() {
+ public Object run() {
+ if (loader != null) {
+ return loader.getResourceAsStream(name);
+ } else {
+ return ClassLoader.getSystemResourceAsStream(name);
+ }
+ }
+ });
+ }
+
+ /**
+ * Given a filename, return an enumeration of URLs pointing to
+ * all the occurrences of that filename in the classpath.
+ *
+ * This is just like ClassLoader.getResources except that the + * operation is done under an AccessController so that this method will + * succeed when this jarfile is privileged but the caller is not. + * This method must therefore remain private to avoid security issues. + *
+ * If no instances are found, an Enumeration is returned whose + * hasMoreElements method returns false (ie an "empty" enumeration). + * If resources could not be listed for some reason, null is returned. + */ + private static Enumeration getResources(final ClassLoader loader, + final String name) + { + PrivilegedAction action = + new PrivilegedAction() { + public Object run() { + try { + if (loader != null) { + return loader.getResources(name); + } else { + return ClassLoader.getSystemResources(name); + } + } catch(IOException e) { + if (isDiagnosticsEnabled()) { + logDiagnostic( + "Exception while trying to find configuration file " + + name + ":" + e.getMessage()); + } + return null; + } catch(NoSuchMethodError e) { + // we must be running on a 1.1 JVM which doesn't support + // ClassLoader.getSystemResources; just return null in + // this case. + return null; + } + } + }; + Object result = AccessController.doPrivileged(action); + return (Enumeration) result; + } + + /** + * Given a URL that refers to a .properties file, load that file. + * This is done under an AccessController so that this method will + * succeed when this jarfile is privileged but the caller is not. + * This method must therefore remain private to avoid security issues. + *
+ * Null is returned if the URL cannot be opened. + */ + private static Properties getProperties(final URL url) { + PrivilegedAction action = + new PrivilegedAction() { + public Object run() { + try { + InputStream stream = url.openStream(); + if (stream != null) { + Properties props = new Properties(); + props.load(stream); + stream.close(); + return props; + } + } catch(IOException e) { + if (isDiagnosticsEnabled()) { + logDiagnostic("Unable to read URL " + url); + } + } + + return null; + } + }; + return (Properties) AccessController.doPrivileged(action); + } + + /** + * Locate a user-provided configuration file. + *
+ * The classpath of the specified classLoader (usually the context classloader) + * is searched for properties files of the specified name. If none is found, + * null is returned. If more than one is found, then the file with the greatest + * value for its PRIORITY property is returned. If multiple files have the + * same PRIORITY value then the first in the classpath is returned. + *
+ * This differs from the 1.0.x releases; those always use the first one found. + * However as the priority is a new field, this change is backwards compatible. + *
+ * The purpose of the priority field is to allow a webserver administrator to + * override logging settings in all webapps by placing a commons-logging.properties + * file in a shared classpath location with a priority > 0; this overrides any + * commons-logging.properties files without priorities which are in the + * webapps. Webapps can also use explicit priorities to override a configuration + * file in the shared classpath if needed. + */ + private static final Properties getConfigurationFile( + ClassLoader classLoader, String fileName) { + + Properties props = null; + double priority = 0.0; + URL propsUrl = null; + try { + Enumeration urls = getResources(classLoader, fileName); + + if (urls == null) { + return null; + } + + while (urls.hasMoreElements()) { + URL url = (URL) urls.nextElement(); + + Properties newProps = getProperties(url); + if (newProps != null) { + if (props == null) { + propsUrl = url; + props = newProps; + String priorityStr = props.getProperty(PRIORITY_KEY); + priority = 0.0; + if (priorityStr != null) { + priority = Double.parseDouble(priorityStr); + } + + if (isDiagnosticsEnabled()) { + logDiagnostic( + "[LOOKUP] Properties file found at '" + url + "'" + + " with priority " + priority); + } + } else { + String newPriorityStr = newProps.getProperty(PRIORITY_KEY); + double newPriority = 0.0; + if (newPriorityStr != null) { + newPriority = Double.parseDouble(newPriorityStr); + } + + if (newPriority > priority) { + if (isDiagnosticsEnabled()) { + logDiagnostic( + "[LOOKUP] Properties file at '" + url + "'" + + " with priority " + newPriority + + " overrides file at '" + propsUrl + "'" + + " with priority " + priority); + } + + propsUrl = url; + props = newProps; + priority = newPriority; + } else { + if (isDiagnosticsEnabled()) { + logDiagnostic( + "[LOOKUP] Properties file at '" + url + "'" + + " with priority " + newPriority + + " does not override file at '" + propsUrl + "'" + + " with priority " + priority); + } + } + } + + } + } + } catch (SecurityException e) { + if (isDiagnosticsEnabled()) { + logDiagnostic("SecurityException thrown while trying to find/read config files."); + } + } + + if (isDiagnosticsEnabled()) { + if (props == null) { + logDiagnostic( + "[LOOKUP] No properties file of name '" + fileName + + "' found."); + } else { + logDiagnostic( + "[LOOKUP] Properties file of name '" + fileName + + "' found at '" + propsUrl + '"'); + } + } + + return props; + } + + /** + * Read the specified system property, using an AccessController so that + * the property can be read if JCL has been granted the appropriate + * security rights even if the calling code has not. + *
+ * Take care not to expose the value returned by this method to the + * calling application in any way; otherwise the calling app can use that + * info to access data that should not be available to it. + */ + private static String getSystemProperty(final String key, final String def) + throws SecurityException { + return (String) AccessController.doPrivileged( + new PrivilegedAction() { + public Object run() { + return System.getProperty(key, def); + } + }); + } + + /** + * Determines whether the user wants internal diagnostic output. If so, + * returns an appropriate writer object. Users can enable diagnostic + * output by setting the system property named {@link #DIAGNOSTICS_DEST_PROPERTY} to + * a filename, or the special values STDOUT or STDERR. + */ + private static void initDiagnostics() { + String dest; + try { + dest = getSystemProperty(DIAGNOSTICS_DEST_PROPERTY, null); + if (dest == null) { + return; + } + } catch(SecurityException ex) { + // We must be running in some very secure environment. + // We just have to assume output is not wanted.. + return; + } + + if (dest.equals("STDOUT")) { + diagnosticsStream = System.out; + } else if (dest.equals("STDERR")) { + diagnosticsStream = System.err; + } else { + try { + // open the file in append mode + FileOutputStream fos = new FileOutputStream(dest, true); + diagnosticsStream = new PrintStream(fos); + } catch(IOException ex) { + // We should report this to the user - but how? + return; + } + } + + // In order to avoid confusion where multiple instances of JCL are + // being used via different classloaders within the same app, we + // ensure each logged message has a prefix of form + // [LogFactory from classloader OID] + // + // Note that this prefix should be kept consistent with that + // in LogFactoryImpl. However here we don't need to output info + // about the actual *instance* of LogFactory, as all methods that + // output diagnostics from this class are static. + String classLoaderName; + try { + ClassLoader classLoader = thisClassLoader; + if (thisClassLoader == null) { + classLoaderName = "BOOTLOADER"; + } else { + classLoaderName = objectId(classLoader); + } + } catch(SecurityException e) { + classLoaderName = "UNKNOWN"; + } + diagnosticPrefix = "[LogFactory from " + classLoaderName + "] "; + } + + /** + * Indicates true if the user has enabled internal logging. + *
+ * By the way, sorry for the incorrect grammar, but calling this method + * areDiagnosticsEnabled just isn't java beans style. + * + * @return true if calls to logDiagnostic will have any effect. + * @since 1.1 + */ + protected static boolean isDiagnosticsEnabled() { + return diagnosticsStream != null; + } + + /** + * Write the specified message to the internal logging destination. + *
+ * Note that this method is private; concrete subclasses of this class + * should not call it because the diagnosticPrefix string this + * method puts in front of all its messages is LogFactory@...., + * while subclasses should put SomeSubClass@... + *
+ * Subclasses should instead compute their own prefix, then call + * logRawDiagnostic. Note that calling isDiagnosticsEnabled is + * fine for subclasses. + *
+ * Note that it is safe to call this method before initDiagnostics + * is called; any output will just be ignored (as isDiagnosticsEnabled + * will return false). + * + * @param msg is the diagnostic message to be output. + */ + private static final void logDiagnostic(String msg) { + if (diagnosticsStream != null) { + diagnosticsStream.print(diagnosticPrefix); + diagnosticsStream.println(msg); + diagnosticsStream.flush(); + } + } + + /** + * Write the specified message to the internal logging destination. + * + * @param msg is the diagnostic message to be output. + * @since 1.1 + */ + protected static final void logRawDiagnostic(String msg) { + if (diagnosticsStream != null) { + diagnosticsStream.println(msg); + diagnosticsStream.flush(); + } + } + + /** + * Generate useful diagnostics regarding the classloader tree for + * the specified class. + *
+ * As an example, if the specified class was loaded via a webapp's + * classloader, then you may get the following output: + *
+ * Class com.acme.Foo was loaded via classloader 11111 + * ClassLoader tree: 11111 -> 22222 (SYSTEM) -> 33333 -> BOOT + *+ *
+ * This method returns immediately if isDiagnosticsEnabled() + * returns false. + * + * @param clazz is the class whose classloader + tree are to be + * output. + */ + private static void logClassLoaderEnvironment(Class clazz) { + if (!isDiagnosticsEnabled()) { + return; + } + + try { + // Deliberately use System.getProperty here instead of getSystemProperty; if + // the overall security policy for the calling application forbids access to + // these variables then we do not want to output them to the diagnostic stream. + logDiagnostic("[ENV] Extension directories (java.ext.dir): " + System.getProperty("java.ext.dir")); + logDiagnostic("[ENV] Application classpath (java.class.path): " + System.getProperty("java.class.path")); + } catch(SecurityException ex) { + logDiagnostic("[ENV] Security setting prevent interrogation of system classpaths."); + } + + String className = clazz.getName(); + ClassLoader classLoader; + + try { + classLoader = getClassLoader(clazz); + } catch(SecurityException ex) { + // not much useful diagnostics we can print here! + logDiagnostic( + "[ENV] Security forbids determining the classloader for " + className); + return; + } + + logDiagnostic( + "[ENV] Class " + className + " was loaded via classloader " + + objectId(classLoader)); + logHierarchy("[ENV] Ancestry of classloader which loaded " + className + " is ", classLoader); + } + + /** + * Logs diagnostic messages about the given classloader + * and it's hierarchy. The prefix is prepended to the message + * and is intended to make it easier to understand the logs. + * @param prefix + * @param classLoader + */ + private static void logHierarchy(String prefix, ClassLoader classLoader) { + if (!isDiagnosticsEnabled()) { + return; + } + ClassLoader systemClassLoader; + if (classLoader != null) { + final String classLoaderString = classLoader.toString(); + logDiagnostic(prefix + objectId(classLoader) + " == '" + classLoaderString + "'"); + } + + try { + systemClassLoader = ClassLoader.getSystemClassLoader(); + } catch(SecurityException ex) { + logDiagnostic( + prefix + "Security forbids determining the system classloader."); + return; + } + if (classLoader != null) { + StringBuffer buf = new StringBuffer(prefix + "ClassLoader tree:"); + for(;;) { + buf.append(objectId(classLoader)); + if (classLoader == systemClassLoader) { + buf.append(" (SYSTEM) "); + } + + try { + classLoader = classLoader.getParent(); + } catch(SecurityException ex) { + buf.append(" --> SECRET"); + break; + } + + buf.append(" --> "); + if (classLoader == null) { + buf.append("BOOT"); + break; + } + } + logDiagnostic(buf.toString()); + } + } + + /** + * Returns a string that uniquely identifies the specified object, including + * its class. + *
+ * The returned string is of form "classname@hashcode", ie is the same as + * the return value of the Object.toString() method, but works even when + * the specified object's class has overidden the toString method. + * + * @param o may be null. + * @return a string of form classname@hashcode, or "null" if param o is null. + * @since 1.1 + */ + public static String objectId(Object o) { + if (o == null) { + return "null"; + } else { + return o.getClass().getName() + "@" + System.identityHashCode(o); + } + } + + // ---------------------------------------------------------------------- + // Static initialiser block to perform initialisation at class load time. + // + // We can't do this in the class constructor, as there are many + // static methods on this class that can be called before any + // LogFactory instances are created, and they depend upon this + // stuff having been set up. + // + // Note that this block must come after any variable declarations used + // by any methods called from this block, as we want any static initialiser + // associated with the variable to run first. If static initialisers for + // variables run after this code, then (a) their value might be needed + // by methods called from here, and (b) they might *override* any value + // computed here! + // + // So the wisest thing to do is just to place this code at the very end + // of the class file. + // ---------------------------------------------------------------------- + + static { + // note: it's safe to call methods before initDiagnostics (though + // diagnostic output gets discarded). + thisClassLoader = getClassLoader(LogFactory.class); + initDiagnostics(); + logClassLoaderEnvironment(LogFactory.class); + factories = createFactoryStore(); + if (isDiagnosticsEnabled()) { + logDiagnostic("BOOTSTRAP COMPLETED"); + } + } +} diff --git a/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/LogSource.java b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/LogSource.java new file mode 100644 index 0000000..50b3e4b --- /dev/null +++ b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/LogSource.java @@ -0,0 +1,262 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.logging; + + +import java.lang.reflect.Constructor; +import java.util.Hashtable; + +import org.apache.commons.logging.impl.NoOpLog; + + +/** + *
Factory for creating {@link Log} instances. Applications should call
+ * the makeNewLogInstance() method to instantiate new instances
+ * of the configured {@link Log} implementation class.
By default, calling getInstance() will use the following
+ * algorithm:
org.apache.commons.logging.impl.Log4JLogger.org.apache.commons.logging.impl.Jdk14Logger.org.apache.commons.logging.impl.NoOpLog.You can change the default behavior in one of two ways:
+ *org.apache.commons.logging.log to the name of the
+ * org.apache.commons.logging.Log implementation class
+ * you want to use.LogSource.setLogImplementation().Log instance by class name */
+ static public Log getInstance(String name) {
+ Log log = (Log) (logs.get(name));
+ if (null == log) {
+ log = makeNewLogInstance(name);
+ logs.put(name, log);
+ }
+ return log;
+ }
+
+
+ /** Get a Log instance by class */
+ static public Log getInstance(Class clazz) {
+ return getInstance(clazz.getName());
+ }
+
+
+ /**
+ * Create a new {@link Log} implementation, based
+ * on the given name.
+ * + * The specific {@link Log} implementation returned + * is determined by the value of the + * org.apache.commons.logging.log property. + * The value of org.apache.commons.logging.log may be set to + * the fully specified name of a class that implements + * the {@link Log} interface. This class must also + * have a public constructor that takes a single + * {@link String} argument (containing the name + * of the {@link Log} to be constructed. + *
+ * When org.apache.commons.logging.log is not set, + * or when no corresponding class can be found, + * this method will return a Log4JLogger + * if the log4j Logger class is + * available in the {@link LogSource}'s classpath, or a + * Jdk14Logger if we are on a JDK 1.4 or later system, or + * NoOpLog if neither of the above conditions is true. + * + * @param name the log name (or category) + */ + static public Log makeNewLogInstance(String name) { + + Log log = null; + try { + Object[] args = new Object[1]; + args[0] = name; + log = (Log) (logImplctor.newInstance(args)); + } catch (Throwable t) { + log = null; + } + if (null == log) { + log = new NoOpLog(name); + } + return log; + + } + + + /** + * Returns a {@link String} array containing the names of + * all logs known to me. + */ + static public String[] getLogNames() { + return (String[]) (logs.keySet().toArray(new String[logs.size()])); + } + + +} diff --git a/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/AvalonLogger.java b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/AvalonLogger.java new file mode 100644 index 0000000..2500172 --- /dev/null +++ b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/AvalonLogger.java @@ -0,0 +1,292 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.logging.impl; + +import org.apache.avalon.framework.logger.Logger; +import org.apache.commons.logging.Log; + +/** + *
Implementation of commons-logging Log interface that delegates all + * logging calls to the Avalon logging abstraction: the Logger interface. + *
+ *+ * There are two ways in which this class can be used: + *
+ *AvalonLogger
+ * instances created through the LogFactory mechanisms will output
+ * to child loggers of this Logger.
+ *
+ * Note: AvalonLogger does not implement Serializable
+ * because the constructors available for it make this impossible to achieve in all
+ * circumstances; there is no way to "reconnect" to an underlying Logger object on
+ * deserialization if one was just passed in to the constructor of the original
+ * object. This class was marked Serializable in the 1.0.4 release of
+ * commons-logging, but this never actually worked (a NullPointerException would
+ * be thrown as soon as the deserialized object was used), so removing this marker
+ * is not considered to be an incompatible change.
+ *
AvalonLogger that outputs to the given
+ * Logger instance.
+ * @param logger the avalon logger implementation to delegate to
+ */
+ public AvalonLogger(Logger logger) {
+ this.logger = logger;
+ }
+
+ /**
+ * Constructs an AvalonLogger that will log to a child
+ * of the Logger set by calling {@link #setDefaultLogger}.
+ * @param name the name of the avalon logger implementation to delegate to
+ */
+ public AvalonLogger(String name) {
+ if (defaultLogger == null)
+ throw new NullPointerException("default logger has to be specified if this constructor is used!");
+ this.logger = defaultLogger.getChildLogger(name);
+ }
+
+ /**
+ * Gets the Avalon logger implementation used to perform logging.
+ * @return avalon logger implementation
+ */
+ public Logger getLogger() {
+ return logger;
+ }
+
+ /**
+ * Sets the ancesteral Avalon logger from which the delegating loggers
+ * will descend.
+ * @param logger the default avalon logger,
+ * in case there is no logger instance supplied in constructor
+ */
+ public static void setDefaultLogger(Logger logger) {
+ defaultLogger = logger;
+ }
+
+ /**
+ * Logs a message with
+ * org.apache.avalon.framework.logger.Logger.debug.
+ *
+ * @param message to log
+ * @param t log this cause
+ * @see org.apache.commons.logging.Log#debug(Object, Throwable)
+ */
+ public void debug(Object message, Throwable t) {
+ if (getLogger().isDebugEnabled()) getLogger().debug(String.valueOf(message), t);
+ }
+
+ /**
+ * Logs a message with
+ * org.apache.avalon.framework.logger.Logger.debug.
+ *
+ * @param message to log.
+ * @see org.apache.commons.logging.Log#debug(Object)
+ */
+ public void debug(Object message) {
+ if (getLogger().isDebugEnabled()) getLogger().debug(String.valueOf(message));
+ }
+
+ /**
+ * Logs a message with
+ * org.apache.avalon.framework.logger.Logger.error.
+ *
+ * @param message to log
+ * @param t log this cause
+ * @see org.apache.commons.logging.Log#error(Object, Throwable)
+ */
+ public void error(Object message, Throwable t) {
+ if (getLogger().isErrorEnabled()) getLogger().error(String.valueOf(message), t);
+ }
+
+ /**
+ * Logs a message with
+ * org.apache.avalon.framework.logger.Logger.error.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#error(Object)
+ */
+ public void error(Object message) {
+ if (getLogger().isErrorEnabled()) getLogger().error(String.valueOf(message));
+ }
+
+ /**
+ * Logs a message with
+ * org.apache.avalon.framework.logger.Logger.fatalError.
+ *
+ * @param message to log.
+ * @param t log this cause.
+ * @see org.apache.commons.logging.Log#fatal(Object, Throwable)
+ */
+ public void fatal(Object message, Throwable t) {
+ if (getLogger().isFatalErrorEnabled()) getLogger().fatalError(String.valueOf(message), t);
+ }
+
+ /**
+ * Logs a message with
+ * org.apache.avalon.framework.logger.Logger.fatalError.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#fatal(Object)
+ */
+ public void fatal(Object message) {
+ if (getLogger().isFatalErrorEnabled()) getLogger().fatalError(String.valueOf(message));
+ }
+
+ /**
+ * Logs a message with
+ * org.apache.avalon.framework.logger.Logger.info.
+ *
+ * @param message to log
+ * @param t log this cause
+ * @see org.apache.commons.logging.Log#info(Object, Throwable)
+ */
+ public void info(Object message, Throwable t) {
+ if (getLogger().isInfoEnabled()) getLogger().info(String.valueOf(message), t);
+ }
+
+ /**
+ * Logs a message with
+ * org.apache.avalon.framework.logger.Logger.info.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#info(Object)
+ */
+ public void info(Object message) {
+ if (getLogger().isInfoEnabled()) getLogger().info(String.valueOf(message));
+ }
+
+ /**
+ * Is logging to
+ * org.apache.avalon.framework.logger.Logger.debug enabled?
+ * @see org.apache.commons.logging.Log#isDebugEnabled()
+ */
+ public boolean isDebugEnabled() {
+ return getLogger().isDebugEnabled();
+ }
+
+ /**
+ * Is logging to
+ * org.apache.avalon.framework.logger.Logger.error enabled?
+ * @see org.apache.commons.logging.Log#isErrorEnabled()
+ */
+ public boolean isErrorEnabled() {
+ return getLogger().isErrorEnabled();
+ }
+
+ /**
+ * Is logging to
+ * org.apache.avalon.framework.logger.Logger.fatalError enabled?
+ * @see org.apache.commons.logging.Log#isFatalEnabled()
+ */
+ public boolean isFatalEnabled() {
+ return getLogger().isFatalErrorEnabled();
+ }
+
+ /**
+ * Is logging to
+ * org.apache.avalon.framework.logger.Logger.info enabled?
+ * @see org.apache.commons.logging.Log#isInfoEnabled()
+ */
+ public boolean isInfoEnabled() {
+ return getLogger().isInfoEnabled();
+ }
+
+ /**
+ * Is logging to
+ * org.apache.avalon.framework.logger.Logger.debug enabled?
+ * @see org.apache.commons.logging.Log#isTraceEnabled()
+ */
+ public boolean isTraceEnabled() {
+ return getLogger().isDebugEnabled();
+ }
+
+ /**
+ * Is logging to
+ * org.apache.avalon.framework.logger.Logger.warn enabled?
+ * @see org.apache.commons.logging.Log#isWarnEnabled()
+ */
+ public boolean isWarnEnabled() {
+ return getLogger().isWarnEnabled();
+ }
+
+ /**
+ * Logs a message with
+ * org.apache.avalon.framework.logger.Logger.debug.
+ *
+ * @param message to log.
+ * @param t log this cause.
+ * @see org.apache.commons.logging.Log#trace(Object, Throwable)
+ */
+ public void trace(Object message, Throwable t) {
+ if (getLogger().isDebugEnabled()) getLogger().debug(String.valueOf(message), t);
+ }
+
+ /**
+ * Logs a message with
+ * org.apache.avalon.framework.logger.Logger.debug.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#trace(Object)
+ */
+ public void trace(Object message) {
+ if (getLogger().isDebugEnabled()) getLogger().debug(String.valueOf(message));
+ }
+
+ /**
+ * Logs a message with
+ * org.apache.avalon.framework.logger.Logger.warn.
+ *
+ * @param message to log
+ * @param t log this cause
+ * @see org.apache.commons.logging.Log#warn(Object, Throwable)
+ */
+ public void warn(Object message, Throwable t) {
+ if (getLogger().isWarnEnabled()) getLogger().warn(String.valueOf(message), t);
+ }
+
+ /**
+ * Logs a message with
+ * org.apache.avalon.framework.logger.Logger.warn.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#warn(Object)
+ */
+ public void warn(Object message) {
+ if (getLogger().isWarnEnabled()) getLogger().warn(String.valueOf(message));
+ }
+
+}
diff --git a/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/Jdk13LumberjackLogger.java b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/Jdk13LumberjackLogger.java
new file mode 100644
index 0000000..fb17d26
--- /dev/null
+++ b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/Jdk13LumberjackLogger.java
@@ -0,0 +1,335 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.commons.logging.impl;
+
+
+import java.io.Serializable;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.logging.LogRecord;
+import java.util.StringTokenizer;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.apache.commons.logging.Log;
+
+
+/**
+ * Implementation of the org.apache.commons.logging.Log
+ * interface that wraps the standard JDK logging mechanisms that are
+ * available in SourceForge's Lumberjack for JDKs prior to 1.4.
Gets the class and method by looking at the stack trace for the + * first entry that is not this class.
+ */ + private void getClassAndMethod() { + try { + Throwable throwable = new Throwable(); + throwable.fillInStackTrace(); + StringWriter stringWriter = new StringWriter(); + PrintWriter printWriter = new PrintWriter( stringWriter ); + throwable.printStackTrace( printWriter ); + String traceString = stringWriter.getBuffer().toString(); + StringTokenizer tokenizer = + new StringTokenizer( traceString, "\n" ); + tokenizer.nextToken(); + String line = tokenizer.nextToken(); + while ( line.indexOf( this.getClass().getName() ) == -1 ) { + line = tokenizer.nextToken(); + } + while ( line.indexOf( this.getClass().getName() ) >= 0 ) { + line = tokenizer.nextToken(); + } + int start = line.indexOf( "at " ) + 3; + int end = line.indexOf( '(' ); + String temp = line.substring( start, end ); + int lastPeriod = temp.lastIndexOf( '.' ); + sourceClassName = temp.substring( 0, lastPeriod ); + sourceMethodName = temp.substring( lastPeriod + 1 ); + } catch ( Exception ex ) { + // ignore - leave class and methodname unknown + } + classAndMethodFound = true; + } + + /** + * Logs a message withjava.util.logging.Level.FINE.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#debug(Object)
+ */
+ public void debug(Object message) {
+ log(Level.FINE, String.valueOf(message), null);
+ }
+
+
+ /**
+ * Logs a message with java.util.logging.Level.FINE.
+ *
+ * @param message to log
+ * @param exception log this cause
+ * @see org.apache.commons.logging.Log#debug(Object, Throwable)
+ */
+ public void debug(Object message, Throwable exception) {
+ log(Level.FINE, String.valueOf(message), exception);
+ }
+
+
+ /**
+ * Logs a message with java.util.logging.Level.SEVERE.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#error(Object)
+ */
+ public void error(Object message) {
+ log(Level.SEVERE, String.valueOf(message), null);
+ }
+
+
+ /**
+ * Logs a message with java.util.logging.Level.SEVERE.
+ *
+ * @param message to log
+ * @param exception log this cause
+ * @see org.apache.commons.logging.Log#error(Object, Throwable)
+ */
+ public void error(Object message, Throwable exception) {
+ log(Level.SEVERE, String.valueOf(message), exception);
+ }
+
+
+ /**
+ * Logs a message with java.util.logging.Level.SEVERE.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#fatal(Object)
+ */
+ public void fatal(Object message) {
+ log(Level.SEVERE, String.valueOf(message), null);
+ }
+
+
+ /**
+ * Logs a message with java.util.logging.Level.SEVERE.
+ *
+ * @param message to log
+ * @param exception log this cause
+ * @see org.apache.commons.logging.Log#fatal(Object, Throwable)
+ */
+ public void fatal(Object message, Throwable exception) {
+ log(Level.SEVERE, String.valueOf(message), exception);
+ }
+
+
+ /**
+ * Return the native Logger instance we are using.
+ */
+ public Logger getLogger() {
+ if (logger == null) {
+ logger = Logger.getLogger(name);
+ }
+ return (logger);
+ }
+
+
+ /**
+ * Logs a message with java.util.logging.Level.INFO.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#info(Object)
+ */
+ public void info(Object message) {
+ log(Level.INFO, String.valueOf(message), null);
+ }
+
+
+ /**
+ * Logs a message with java.util.logging.Level.INFO.
+ *
+ * @param message to log
+ * @param exception log this cause
+ * @see org.apache.commons.logging.Log#info(Object, Throwable)
+ */
+ public void info(Object message, Throwable exception) {
+ log(Level.INFO, String.valueOf(message), exception);
+ }
+
+
+ /**
+ * Is debug logging currently enabled?
+ */
+ public boolean isDebugEnabled() {
+ return (getLogger().isLoggable(Level.FINE));
+ }
+
+
+ /**
+ * Is error logging currently enabled?
+ */
+ public boolean isErrorEnabled() {
+ return (getLogger().isLoggable(Level.SEVERE));
+ }
+
+
+ /**
+ * Is fatal logging currently enabled?
+ */
+ public boolean isFatalEnabled() {
+ return (getLogger().isLoggable(Level.SEVERE));
+ }
+
+
+ /**
+ * Is info logging currently enabled?
+ */
+ public boolean isInfoEnabled() {
+ return (getLogger().isLoggable(Level.INFO));
+ }
+
+
+ /**
+ * Is trace logging currently enabled?
+ */
+ public boolean isTraceEnabled() {
+ return (getLogger().isLoggable(Level.FINEST));
+ }
+
+
+ /**
+ * Is warn logging currently enabled?
+ */
+ public boolean isWarnEnabled() {
+ return (getLogger().isLoggable(Level.WARNING));
+ }
+
+
+ /**
+ * Logs a message with java.util.logging.Level.FINEST.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#trace(Object)
+ */
+ public void trace(Object message) {
+ log(Level.FINEST, String.valueOf(message), null);
+ }
+
+
+ /**
+ * Logs a message with java.util.logging.Level.FINEST.
+ *
+ * @param message to log
+ * @param exception log this cause
+ * @see org.apache.commons.logging.Log#trace(Object, Throwable)
+ */
+ public void trace(Object message, Throwable exception) {
+ log(Level.FINEST, String.valueOf(message), exception);
+ }
+
+
+ /**
+ * Logs a message with java.util.logging.Level.WARNING.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#warn(Object)
+ */
+ public void warn(Object message) {
+ log(Level.WARNING, String.valueOf(message), null);
+ }
+
+
+ /**
+ * Logs a message with java.util.logging.Level.WARNING.
+ *
+ * @param message to log
+ * @param exception log this cause
+ * @see org.apache.commons.logging.Log#warn(Object, Throwable)
+ */
+ public void warn(Object message, Throwable exception) {
+ log(Level.WARNING, String.valueOf(message), exception);
+ }
+
+
+}
diff --git a/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/Jdk14Logger.java b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/Jdk14Logger.java
new file mode 100644
index 0000000..9fafefd
--- /dev/null
+++ b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/Jdk14Logger.java
@@ -0,0 +1,304 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.commons.logging.impl;
+
+
+import java.io.Serializable;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.commons.logging.Log;
+
+
+/**
+ * Implementation of the org.apache.commons.logging.Log
+ * interface that wraps the standard JDK logging mechanisms that were
+ * introduced in the Merlin release (JDK 1.4).
java.util.logging.Level.FINE.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#debug(Object)
+ */
+ public void debug(Object message) {
+ log(Level.FINE, String.valueOf(message), null);
+ }
+
+
+ /**
+ * Logs a message with java.util.logging.Level.FINE.
+ *
+ * @param message to log
+ * @param exception log this cause
+ * @see org.apache.commons.logging.Log#debug(Object, Throwable)
+ */
+ public void debug(Object message, Throwable exception) {
+ log(Level.FINE, String.valueOf(message), exception);
+ }
+
+
+ /**
+ * Logs a message with java.util.logging.Level.SEVERE.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#error(Object)
+ */
+ public void error(Object message) {
+ log(Level.SEVERE, String.valueOf(message), null);
+ }
+
+
+ /**
+ * Logs a message with java.util.logging.Level.SEVERE.
+ *
+ * @param message to log
+ * @param exception log this cause
+ * @see org.apache.commons.logging.Log#error(Object, Throwable)
+ */
+ public void error(Object message, Throwable exception) {
+ log(Level.SEVERE, String.valueOf(message), exception);
+ }
+
+
+ /**
+ * Logs a message with java.util.logging.Level.SEVERE.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#fatal(Object)
+ */
+ public void fatal(Object message) {
+ log(Level.SEVERE, String.valueOf(message), null);
+ }
+
+
+ /**
+ * Logs a message with java.util.logging.Level.SEVERE.
+ *
+ * @param message to log
+ * @param exception log this cause
+ * @see org.apache.commons.logging.Log#fatal(Object, Throwable)
+ */
+ public void fatal(Object message, Throwable exception) {
+ log(Level.SEVERE, String.valueOf(message), exception);
+ }
+
+
+ /**
+ * Return the native Logger instance we are using.
+ */
+ public Logger getLogger() {
+ if (logger == null) {
+ logger = Logger.getLogger(name);
+ }
+ return (logger);
+ }
+
+
+ /**
+ * Logs a message with java.util.logging.Level.INFO.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#info(Object)
+ */
+ public void info(Object message) {
+ log(Level.INFO, String.valueOf(message), null);
+ }
+
+
+ /**
+ * Logs a message with java.util.logging.Level.INFO.
+ *
+ * @param message to log
+ * @param exception log this cause
+ * @see org.apache.commons.logging.Log#info(Object, Throwable)
+ */
+ public void info(Object message, Throwable exception) {
+ log(Level.INFO, String.valueOf(message), exception);
+ }
+
+
+ /**
+ * Is debug logging currently enabled?
+ */
+ public boolean isDebugEnabled() {
+ return (getLogger().isLoggable(Level.FINE));
+ }
+
+
+ /**
+ * Is error logging currently enabled?
+ */
+ public boolean isErrorEnabled() {
+ return (getLogger().isLoggable(Level.SEVERE));
+ }
+
+
+ /**
+ * Is fatal logging currently enabled?
+ */
+ public boolean isFatalEnabled() {
+ return (getLogger().isLoggable(Level.SEVERE));
+ }
+
+
+ /**
+ * Is info logging currently enabled?
+ */
+ public boolean isInfoEnabled() {
+ return (getLogger().isLoggable(Level.INFO));
+ }
+
+
+ /**
+ * Is trace logging currently enabled?
+ */
+ public boolean isTraceEnabled() {
+ return (getLogger().isLoggable(Level.FINEST));
+ }
+
+
+ /**
+ * Is warn logging currently enabled?
+ */
+ public boolean isWarnEnabled() {
+ return (getLogger().isLoggable(Level.WARNING));
+ }
+
+
+ /**
+ * Logs a message with java.util.logging.Level.FINEST.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#trace(Object)
+ */
+ public void trace(Object message) {
+ log(Level.FINEST, String.valueOf(message), null);
+ }
+
+
+ /**
+ * Logs a message with java.util.logging.Level.FINEST.
+ *
+ * @param message to log
+ * @param exception log this cause
+ * @see org.apache.commons.logging.Log#trace(Object, Throwable)
+ */
+ public void trace(Object message, Throwable exception) {
+ log(Level.FINEST, String.valueOf(message), exception);
+ }
+
+
+ /**
+ * Logs a message with java.util.logging.Level.WARNING.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#warn(Object)
+ */
+ public void warn(Object message) {
+ log(Level.WARNING, String.valueOf(message), null);
+ }
+
+
+ /**
+ * Logs a message with java.util.logging.Level.WARNING.
+ *
+ * @param message to log
+ * @param exception log this cause
+ * @see org.apache.commons.logging.Log#warn(Object, Throwable)
+ */
+ public void warn(Object message, Throwable exception) {
+ log(Level.WARNING, String.valueOf(message), exception);
+ }
+
+
+}
diff --git a/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/Log4JLogger.java b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/Log4JLogger.java
new file mode 100644
index 0000000..68877b9
--- /dev/null
+++ b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/Log4JLogger.java
@@ -0,0 +1,342 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.commons.logging.impl;
+
+import java.io.Serializable;
+import org.apache.commons.logging.Log;
+import org.apache.log4j.Logger;
+import org.apache.log4j.Priority;
+import org.apache.log4j.Level;
+
+/**
+ * Implementation of {@link Log} that maps directly to a
+ * Logger for log4J version 1.2.
+ * + * Initial configuration of the corresponding Logger instances should be done + * in the usual manner, as outlined in the Log4J documentation. + *
+ * The reason this logger is distinct from the 1.3 logger is that in version 1.2 + * of Log4J: + *
org.apache.log4j.Priority.TRACE.
+ * When using a log4j version that does not support the TRACE
+ * level, the message will be logged at the DEBUG level.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#trace(Object)
+ */
+ public void trace(Object message) {
+ getLogger().log(FQCN, traceLevel, message, null );
+ }
+
+
+ /**
+ * Logs a message with org.apache.log4j.Priority.TRACE.
+ * When using a log4j version that does not support the TRACE
+ * level, the message will be logged at the DEBUG level.
+ *
+ * @param message to log
+ * @param t log this cause
+ * @see org.apache.commons.logging.Log#trace(Object, Throwable)
+ */
+ public void trace(Object message, Throwable t) {
+ getLogger().log(FQCN, traceLevel, message, t );
+ }
+
+
+ /**
+ * Logs a message with org.apache.log4j.Priority.DEBUG.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#debug(Object)
+ */
+ public void debug(Object message) {
+ getLogger().log(FQCN, Priority.DEBUG, message, null );
+ }
+
+ /**
+ * Logs a message with org.apache.log4j.Priority.DEBUG.
+ *
+ * @param message to log
+ * @param t log this cause
+ * @see org.apache.commons.logging.Log#debug(Object, Throwable)
+ */
+ public void debug(Object message, Throwable t) {
+ getLogger().log(FQCN, Priority.DEBUG, message, t );
+ }
+
+
+ /**
+ * Logs a message with org.apache.log4j.Priority.INFO.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#info(Object)
+ */
+ public void info(Object message) {
+ getLogger().log(FQCN, Priority.INFO, message, null );
+ }
+
+
+ /**
+ * Logs a message with org.apache.log4j.Priority.INFO.
+ *
+ * @param message to log
+ * @param t log this cause
+ * @see org.apache.commons.logging.Log#info(Object, Throwable)
+ */
+ public void info(Object message, Throwable t) {
+ getLogger().log(FQCN, Priority.INFO, message, t );
+ }
+
+
+ /**
+ * Logs a message with org.apache.log4j.Priority.WARN.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#warn(Object)
+ */
+ public void warn(Object message) {
+ getLogger().log(FQCN, Priority.WARN, message, null );
+ }
+
+
+ /**
+ * Logs a message with org.apache.log4j.Priority.WARN.
+ *
+ * @param message to log
+ * @param t log this cause
+ * @see org.apache.commons.logging.Log#warn(Object, Throwable)
+ */
+ public void warn(Object message, Throwable t) {
+ getLogger().log(FQCN, Priority.WARN, message, t );
+ }
+
+
+ /**
+ * Logs a message with org.apache.log4j.Priority.ERROR.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#error(Object)
+ */
+ public void error(Object message) {
+ getLogger().log(FQCN, Priority.ERROR, message, null );
+ }
+
+
+ /**
+ * Logs a message with org.apache.log4j.Priority.ERROR.
+ *
+ * @param message to log
+ * @param t log this cause
+ * @see org.apache.commons.logging.Log#error(Object, Throwable)
+ */
+ public void error(Object message, Throwable t) {
+ getLogger().log(FQCN, Priority.ERROR, message, t );
+ }
+
+
+ /**
+ * Logs a message with org.apache.log4j.Priority.FATAL.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#fatal(Object)
+ */
+ public void fatal(Object message) {
+ getLogger().log(FQCN, Priority.FATAL, message, null );
+ }
+
+
+ /**
+ * Logs a message with org.apache.log4j.Priority.FATAL.
+ *
+ * @param message to log
+ * @param t log this cause
+ * @see org.apache.commons.logging.Log#fatal(Object, Throwable)
+ */
+ public void fatal(Object message, Throwable t) {
+ getLogger().log(FQCN, Priority.FATAL, message, t );
+ }
+
+
+ /**
+ * Return the native Logger instance we are using.
+ */
+ public Logger getLogger() {
+ if (logger == null) {
+ logger = Logger.getLogger(name);
+ }
+ return (this.logger);
+ }
+
+
+ /**
+ * Check whether the Log4j Logger used is enabled for DEBUG priority.
+ */
+ public boolean isDebugEnabled() {
+ return getLogger().isDebugEnabled();
+ }
+
+
+ /**
+ * Check whether the Log4j Logger used is enabled for ERROR priority.
+ */
+ public boolean isErrorEnabled() {
+ return getLogger().isEnabledFor(Priority.ERROR);
+ }
+
+
+ /**
+ * Check whether the Log4j Logger used is enabled for FATAL priority.
+ */
+ public boolean isFatalEnabled() {
+ return getLogger().isEnabledFor(Priority.FATAL);
+ }
+
+
+ /**
+ * Check whether the Log4j Logger used is enabled for INFO priority.
+ */
+ public boolean isInfoEnabled() {
+ return getLogger().isInfoEnabled();
+ }
+
+
+ /**
+ * Check whether the Log4j Logger used is enabled for TRACE priority.
+ * When using a log4j version that does not support the TRACE level, this call
+ * will report whether DEBUG is enabled or not.
+ */
+ public boolean isTraceEnabled() {
+ return getLogger().isEnabledFor(traceLevel);
+ }
+
+ /**
+ * Check whether the Log4j Logger used is enabled for WARN priority.
+ */
+ public boolean isWarnEnabled() {
+ return getLogger().isEnabledFor(Priority.WARN);
+ }
+}
diff --git a/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/LogFactoryImpl.java b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/LogFactoryImpl.java
new file mode 100644
index 0000000..97a9ac0
--- /dev/null
+++ b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/LogFactoryImpl.java
@@ -0,0 +1,1500 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.logging.impl;
+
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogConfigurationException;
+import org.apache.commons.logging.LogFactory;
+
+
+/**
+ * Concrete subclass of {@link LogFactory} that implements the + * following algorithm to dynamically select a logging implementation + * class to instantiate a wrapper for.
+ *org.apache.commons.logging.Log to identify the
+ * requested implementation class.org.apache.commons.logging.Log system property
+ * to identify the requested implementation class.org.apache.commons.logging.impl.Log4JLogger.org.apache.commons.logging.impl.Jdk14Logger.org.apache.commons.logging.impl.SimpleLog.If the selected {@link Log} implementation class has a
+ * setLogFactory() method that accepts a {@link LogFactory}
+ * parameter, this method will be called on each newly created instance
+ * to identify the associated factory. This makes factory configuration
+ * attributes available to the Log instance, if it so desires.
This factory will remember previously created Log instances
+ * for the same name, and will return them on repeated requests to the
+ * getInstance() method.
org.apache.commons.logging.Log) of the system
+ * property identifying our {@link Log} implementation class.
+ */
+ public static final String LOG_PROPERTY =
+ "org.apache.commons.logging.Log";
+
+
+ /**
+ * The deprecated system property used for backwards compatibility with
+ * old versions of JCL.
+ */
+ protected static final String LOG_PROPERTY_OLD =
+ "org.apache.commons.logging.log";
+
+ /**
+ * The name (org.apache.commons.logging.Log.allowFlawedContext)
+ * of the system property which can be set true/false to
+ * determine system behaviour when a bad context-classloader is encountered.
+ * When set to false, a LogConfigurationException is thrown if
+ * LogFactoryImpl is loaded via a child classloader of the TCCL (this
+ * should never happen in sane systems).
+ *
+ * Default behaviour: true (tolerates bad context classloaders)
+ *
+ * See also method setAttribute.
+ */
+ public static final String ALLOW_FLAWED_CONTEXT_PROPERTY =
+ "org.apache.commons.logging.Log.allowFlawedContext";
+
+ /**
+ * The name (org.apache.commons.logging.Log.allowFlawedDiscovery)
+ * of the system property which can be set true/false to
+ * determine system behaviour when a bad logging adapter class is
+ * encountered during logging discovery. When set to false, an
+ * exception will be thrown and the app will fail to start. When set
+ * to true, discovery will continue (though the user might end up
+ * with a different logging implementation than they expected).
+ *
+ * Default behaviour: true (tolerates bad logging adapters)
+ *
+ * See also method setAttribute.
+ */
+ public static final String ALLOW_FLAWED_DISCOVERY_PROPERTY =
+ "org.apache.commons.logging.Log.allowFlawedDiscovery";
+
+ /**
+ * The name (org.apache.commons.logging.Log.allowFlawedHierarchy)
+ * of the system property which can be set true/false to
+ * determine system behaviour when a logging adapter class is
+ * encountered which has bound to the wrong Log class implementation.
+ * When set to false, an exception will be thrown and the app will fail
+ * to start. When set to true, discovery will continue (though the user
+ * might end up with a different logging implementation than they expected).
+ *
+ * Default behaviour: true (tolerates bad Log class hierarchy)
+ *
+ * See also method setAttribute.
+ */
+ public static final String ALLOW_FLAWED_HIERARCHY_PROPERTY =
+ "org.apache.commons.logging.Log.allowFlawedHierarchy";
+
+
+ /**
+ * The names of classes that will be tried (in order) as logging
+ * adapters. Each class is expected to implement the Log interface,
+ * and to throw NoClassDefFound or ExceptionInInitializerError when
+ * loaded if the underlying logging library is not available. Any
+ * other error indicates that the underlying logging library is available
+ * but broken/unusable for some reason.
+ */
+ private static final String[] classesToDiscover = {
+ LOGGING_IMPL_LOG4J_LOGGER,
+ "org.apache.commons.logging.impl.Jdk14Logger",
+ "org.apache.commons.logging.impl.Jdk13LumberjackLogger",
+ "org.apache.commons.logging.impl.SimpleLog"
+ };
+
+
+ // ----------------------------------------------------- Instance Variables
+
+ /**
+ * Determines whether logging classes should be loaded using the thread-context
+ * classloader, or via the classloader that loaded this LogFactoryImpl class.
+ */
+ private boolean useTCCL = true;
+
+ /**
+ * The string prefixed to every message output by the logDiagnostic method.
+ */
+ private String diagnosticPrefix;
+
+
+ /**
+ * Configuration attributes.
+ */
+ protected Hashtable attributes = new Hashtable();
+
+
+ /**
+ * The {@link org.apache.commons.logging.Log} instances that have
+ * already been created, keyed by logger name.
+ */
+ protected Hashtable instances = new Hashtable();
+
+
+ /**
+ * Name of the class implementing the Log interface.
+ */
+ private String logClassName;
+
+
+ /**
+ * The one-argument constructor of the
+ * {@link org.apache.commons.logging.Log}
+ * implementation class that will be used to create new instances.
+ * This value is initialized by getLogConstructor(),
+ * and then returned repeatedly.
+ */
+ protected Constructor logConstructor = null;
+
+
+ /**
+ * The signature of the Constructor to be used.
+ */
+ protected Class logConstructorSignature[] =
+ { java.lang.String.class };
+
+
+ /**
+ * The one-argument setLogFactory method of the selected
+ * {@link org.apache.commons.logging.Log} method, if it exists.
+ */
+ protected Method logMethod = null;
+
+
+ /**
+ * The signature of the setLogFactory method to be used.
+ */
+ protected Class logMethodSignature[] =
+ { LogFactory.class };
+
+ /**
+ * See getBaseClassLoader and initConfiguration.
+ */
+ private boolean allowFlawedContext;
+
+ /**
+ * See handleFlawedDiscovery and initConfiguration.
+ */
+ private boolean allowFlawedDiscovery;
+
+ /**
+ * See handleFlawedHierarchy and initConfiguration.
+ */
+ private boolean allowFlawedHierarchy;
+
+ // --------------------------------------------------------- Public Methods
+
+
+ /**
+ * Return the configuration attribute with the specified name (if any),
+ * or null if there is no such attribute.
+ *
+ * @param name Name of the attribute to return
+ */
+ public Object getAttribute(String name) {
+
+ return (attributes.get(name));
+
+ }
+
+
+ /**
+ * Return an array containing the names of all currently defined
+ * configuration attributes. If there are no such attributes, a zero
+ * length array is returned.
+ */
+ public String[] getAttributeNames() {
+
+ Vector names = new Vector();
+ Enumeration keys = attributes.keys();
+ while (keys.hasMoreElements()) {
+ names.addElement((String) keys.nextElement());
+ }
+ String results[] = new String[names.size()];
+ for (int i = 0; i < results.length; i++) {
+ results[i] = (String) names.elementAt(i);
+ }
+ return (results);
+
+ }
+
+
+ /**
+ * Convenience method to derive a name from the specified class and
+ * call getInstance(String) with it.
+ *
+ * @param clazz Class for which a suitable Log name will be derived
+ *
+ * @exception LogConfigurationException if a suitable Log
+ * instance cannot be returned
+ */
+ public Log getInstance(Class clazz) throws LogConfigurationException {
+
+ return (getInstance(clazz.getName()));
+
+ }
+
+
+ /**
+ * Construct (if necessary) and return a Log instance,
+ * using the factory's current set of configuration attributes.
NOTE - Depending upon the implementation of
+ * the LogFactory you are using, the Log
+ * instance you are returned may or may not be local to the current
+ * application, and may or may not be returned again on a subsequent
+ * call with the same name argument.
Log instance to be
+ * returned (the meaning of this name is only known to the underlying
+ * logging implementation that is being wrapped)
+ *
+ * @exception LogConfigurationException if a suitable Log
+ * instance cannot be returned
+ */
+ public Log getInstance(String name) throws LogConfigurationException {
+
+ Log instance = (Log) instances.get(name);
+ if (instance == null) {
+ instance = newInstance(name);
+ instances.put(name, instance);
+ }
+ return (instance);
+
+ }
+
+
+ /**
+ * Release any internal references to previously created
+ * {@link org.apache.commons.logging.Log}
+ * instances returned by this factory. This is useful in environments
+ * like servlet containers, which implement application reloading by
+ * throwing away a ClassLoader. Dangling references to objects in that
+ * class loader would prevent garbage collection.
+ */
+ public void release() {
+
+ logDiagnostic("Releasing all known loggers");
+ instances.clear();
+ }
+
+
+ /**
+ * Remove any configuration attribute associated with the specified name.
+ * If there is no such attribute, no action is taken.
+ *
+ * @param name Name of the attribute to remove
+ */
+ public void removeAttribute(String name) {
+
+ attributes.remove(name);
+
+ }
+
+
+ /**
+ * Set the configuration attribute with the specified name. Calling
+ * this with a null value is equivalent to calling
+ * removeAttribute(name).
+ * + * This method can be used to set logging configuration programmatically + * rather than via system properties. It can also be used in code running + * within a container (such as a webapp) to configure behaviour on a + * per-component level instead of globally as system properties would do. + * To use this method instead of a system property, call + *
+ * LogFactory.getFactory().setAttribute(...) + *+ * This must be done before the first Log object is created; configuration + * changes after that point will be ignored. + *
+ * This method is also called automatically if LogFactory detects a
+ * commons-logging.properties file; every entry in that file is set
+ * automatically as an attribute here.
+ *
+ * @param name Name of the attribute to set
+ * @param value Value of the attribute to set, or null
+ * to remove any setting for this attribute
+ */
+ public void setAttribute(String name, Object value) {
+
+ if (logConstructor != null) {
+ logDiagnostic("setAttribute: call too late; configuration already performed.");
+ }
+
+ if (value == null) {
+ attributes.remove(name);
+ } else {
+ attributes.put(name, value);
+ }
+
+ if (name.equals(TCCL_KEY)) {
+ useTCCL = Boolean.valueOf(value.toString()).booleanValue();
+ }
+
+ }
+
+
+ // ------------------------------------------------------
+ // Static Methods
+ //
+ // These methods only defined as workarounds for a java 1.2 bug;
+ // theoretically none of these are needed.
+ // ------------------------------------------------------
+
+ /**
+ * Gets the context classloader.
+ * This method is a workaround for a java 1.2 compiler bug.
+ * @since 1.1
+ */
+ protected static ClassLoader getContextClassLoader() throws LogConfigurationException {
+ return LogFactory.getContextClassLoader();
+ }
+
+
+ /**
+ * Workaround for bug in Java1.2; in theory this method is not needed.
+ * See LogFactory.isDiagnosticsEnabled.
+ */
+ protected static boolean isDiagnosticsEnabled() {
+ return LogFactory.isDiagnosticsEnabled();
+ }
+
+
+ /**
+ * Workaround for bug in Java1.2; in theory this method is not needed.
+ * See LogFactory.getClassLoader.
+ * @since 1.1
+ */
+ protected static ClassLoader getClassLoader(Class clazz) {
+ return LogFactory.getClassLoader(clazz);
+ }
+
+
+ // ------------------------------------------------------ Protected Methods
+
+ /**
+ * Calculate and cache a string that uniquely identifies this instance,
+ * including which classloader the object was loaded from.
+ *
+ * This string will later be prefixed to each "internal logging" message + * emitted, so that users can clearly see any unexpected behaviour. + *
+ * Note that this method does not detect whether internal logging is + * enabled or not, nor where to output stuff if it is; that is all + * handled by the parent LogFactory class. This method just computes + * its own unique prefix for log messages. + */ + private void initDiagnostics() { + // It would be nice to include an identifier of the context classloader + // that this LogFactoryImpl object is responsible for. However that + // isn't possible as that information isn't available. It is possible + // to figure this out by looking at the logging from LogFactory to + // see the context & impl ids from when this object was instantiated, + // in order to link the impl id output as this object's prefix back to + // the context it is intended to manage. + // Note that this prefix should be kept consistent with that + // in LogFactory. + Class clazz = this.getClass(); + ClassLoader classLoader = getClassLoader(clazz); + String classLoaderName; + try { + if (classLoader == null) { + classLoaderName = "BOOTLOADER"; + } else { + classLoaderName = objectId(classLoader); + } + } catch(SecurityException e) { + classLoaderName = "UNKNOWN"; + } + diagnosticPrefix = "[LogFactoryImpl@" + System.identityHashCode(this) + " from " + classLoaderName + "] "; + } + + + /** + * Output a diagnostic message to a user-specified destination (if the + * user has enabled diagnostic logging). + * + * @param msg diagnostic message + * @since 1.1 + */ + protected void logDiagnostic(String msg) { + if (isDiagnosticsEnabled()) { + logRawDiagnostic(diagnosticPrefix + msg); + } + } + + /** + * Return the fully qualified Java classname of the {@link Log} + * implementation we will be using. + * + * @deprecated Never invoked by this class; subclasses should not assume + * it will be. + */ + protected String getLogClassName() { + + if (logClassName == null) { + discoverLogImplementation(getClass().getName()); + } + + return logClassName; + } + + + /** + *
Return the Constructor that can be called to instantiate
+ * new {@link org.apache.commons.logging.Log} instances.
IMPLEMENTATION NOTE - Race conditions caused by
+ * calling this method from more than one thread are ignored, because
+ * the same Constructor instance will ultimately be derived
+ * in all circumstances.
Return true if JDK 1.4 or later logging
+ * is available. Also checks that the Throwable class
+ * supports getStackTrace(), which is required by
+ * Jdk14Logger.
+ * Take care not to expose the value returned by this method to the + * calling application in any way; otherwise the calling app can use that + * info to access data that should not be available to it. + */ + private static String getSystemProperty(final String key, final String def) + throws SecurityException { + return (String) AccessController.doPrivileged( + new PrivilegedAction() { + public Object run() { + return System.getProperty(key, def); + } + }); + } + + /** + * Fetch the parent classloader of a specified classloader. + *
+ * If a SecurityException occurs, null is returned. + *
+ * Note that this method is non-static merely so logDiagnostic is available. + */ + private ClassLoader getParentClassLoader(final ClassLoader cl) { + try { + return (ClassLoader)AccessController.doPrivileged( + new PrivilegedAction() { + public Object run() { + return cl.getParent(); + } + }); + } catch(SecurityException ex) { + logDiagnostic("[SECURITY] Unable to obtain parent classloader"); + return null; + } + + } + + /** + * Utility method to check whether a particular logging library is + * present and available for use. Note that this does not + * affect the future behaviour of this class. + */ + private boolean isLogLibraryAvailable(String name, String classname) { + if (isDiagnosticsEnabled()) { + logDiagnostic("Checking for '" + name + "'."); + } + try { + Log log = createLogFromClass( + classname, + this.getClass().getName(), // dummy category + false); + + if (log == null) { + if (isDiagnosticsEnabled()) { + logDiagnostic("Did not find '" + name + "'."); + } + return false; + } else { + if (isDiagnosticsEnabled()) { + logDiagnostic("Found '" + name + "'."); + } + return true; + } + } catch(LogConfigurationException e) { + if (isDiagnosticsEnabled()) { + logDiagnostic("Logging system '" + name + "' is available but not useable."); + } + return false; + } + } + + /** + * Attempt to find an attribute (see method setAttribute) or a + * system property with the provided name and return its value. + *
+ * The attributes associated with this object are checked before
+ * system properties in case someone has explicitly called setAttribute,
+ * or a configuration property has been set in a commons-logging.properties
+ * file.
+ *
+ * @return the value associated with the property, or null.
+ */
+ private String getConfigurationValue(String property) {
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic("[ENV] Trying to get configuration for item " + property);
+ }
+
+ Object valueObj = getAttribute(property);
+ if (valueObj != null) {
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic("[ENV] Found LogFactory attribute [" + valueObj + "] for " + property);
+ }
+ return valueObj.toString();
+ }
+
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic("[ENV] No LogFactory attribute found for " + property);
+ }
+
+ try {
+ // warning: minor security hole here, in that we potentially read a system
+ // property that the caller cannot, then output it in readable form as a
+ // diagnostic message. However it's only ever JCL-specific properties
+ // involved here, so the harm is truly trivial.
+ String value = getSystemProperty(property, null);
+ if (value != null) {
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic("[ENV] Found system property [" + value + "] for " + property);
+ }
+ return value;
+ }
+
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic("[ENV] No system property found for property " + property);
+ }
+ } catch (SecurityException e) {
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic("[ENV] Security prevented reading system property " + property);
+ }
+ }
+
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic("[ENV] No configuration defined for item " + property);
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the setting for the user-configurable behaviour specified by key.
+ * If nothing has explicitly been set, then return dflt.
+ */
+ private boolean getBooleanConfiguration(String key, boolean dflt) {
+ String val = getConfigurationValue(key);
+ if (val == null)
+ return dflt;
+ return Boolean.valueOf(val).booleanValue();
+ }
+
+ /**
+ * Initialize a number of variables that control the behaviour of this
+ * class and that can be tweaked by the user. This is done when the first
+ * logger is created, not in the constructor of this class, because we
+ * need to give the user a chance to call method setAttribute in order to
+ * configure this object.
+ */
+ private void initConfiguration() {
+ allowFlawedContext = getBooleanConfiguration(ALLOW_FLAWED_CONTEXT_PROPERTY, true);
+ allowFlawedDiscovery = getBooleanConfiguration(ALLOW_FLAWED_DISCOVERY_PROPERTY, true);
+ allowFlawedHierarchy = getBooleanConfiguration(ALLOW_FLAWED_HIERARCHY_PROPERTY, true);
+ }
+
+
+ /**
+ * Attempts to create a Log instance for the given category name.
+ * Follows the discovery process described in the class javadoc.
+ *
+ * @param logCategory the name of the log category
+ *
+ * @throws LogConfigurationException if an error in discovery occurs,
+ * or if no adapter at all can be instantiated
+ */
+ private Log discoverLogImplementation(String logCategory)
+ throws LogConfigurationException
+ {
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic("Discovering a Log implementation...");
+ }
+
+ initConfiguration();
+
+ Log result = null;
+
+ // See if the user specified the Log implementation to use
+ String specifiedLogClassName = findUserSpecifiedLogClassName();
+
+ if (specifiedLogClassName != null) {
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic("Attempting to load user-specified log class '" +
+ specifiedLogClassName + "'...");
+ }
+
+ result = createLogFromClass(specifiedLogClassName,
+ logCategory,
+ true);
+ if (result == null) {
+ StringBuffer messageBuffer = new StringBuffer("User-specified log class '");
+ messageBuffer.append(specifiedLogClassName);
+ messageBuffer.append("' cannot be found or is not useable.");
+
+ // Mistyping or misspelling names is a common fault.
+ // Construct a good error message, if we can
+ if (specifiedLogClassName != null) {
+ informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_LOG4J_LOGGER);
+ informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_JDK14_LOGGER);
+ informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_LUMBERJACK_LOGGER);
+ informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_SIMPLE_LOGGER);
+ }
+ throw new LogConfigurationException(messageBuffer.toString());
+ }
+
+ return result;
+ }
+
+ // No user specified log; try to discover what's on the classpath
+ //
+ // Note that we deliberately loop here over classesToDiscover and
+ // expect method createLogFromClass to loop over the possible source
+ // classloaders. The effect is:
+ // for each discoverable log adapter
+ // for each possible classloader
+ // see if it works
+ //
+ // It appears reasonable at first glance to do the opposite:
+ // for each possible classloader
+ // for each discoverable log adapter
+ // see if it works
+ //
+ // The latter certainly has advantages for user-installable logging
+ // libraries such as log4j; in a webapp for example this code should
+ // first check whether the user has provided any of the possible
+ // logging libraries before looking in the parent classloader.
+ // Unfortunately, however, Jdk14Logger will always work in jvm>=1.4,
+ // and SimpleLog will always work in any JVM. So the loop would never
+ // ever look for logging libraries in the parent classpath. Yet many
+ // users would expect that putting log4j there would cause it to be
+ // detected (and this is the historical JCL behaviour). So we go with
+ // the first approach. A user that has bundled a specific logging lib
+ // in a webapp should use a commons-logging.properties file or a
+ // service file in META-INF to force use of that logging lib anyway,
+ // rather than relying on discovery.
+
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic(
+ "No user-specified Log implementation; performing discovery" +
+ " using the standard supported logging implementations...");
+ }
+ for(int i=0; (i
+ * This method usually returns the context classloader. However if it
+ * is discovered that the classloader which loaded this class is a child
+ * of the context classloader and the allowFlawedContext option
+ * has been set then the classloader which loaded this class is returned
+ * instead.
+ *
+ * The only time when the classloader which loaded this class is a
+ * descendant (rather than the same as or an ancestor of the context
+ * classloader) is when an app has created custom classloaders but
+ * failed to correctly set the context classloader. This is a bug in
+ * the calling application; however we provide the option for JCL to
+ * simply generate a warning rather than fail outright.
+ *
+ */
+ private ClassLoader getBaseClassLoader() throws LogConfigurationException {
+ ClassLoader thisClassLoader = getClassLoader(LogFactoryImpl.class);
+
+ if (useTCCL == false) {
+ return thisClassLoader;
+ }
+
+ ClassLoader contextClassLoader = getContextClassLoaderInternal();
+
+ ClassLoader baseClassLoader = getLowestClassLoader(
+ contextClassLoader, thisClassLoader);
+
+ if (baseClassLoader == null) {
+ // The two classloaders are not part of a parent child relationship.
+ // In some classloading setups (e.g. JBoss with its
+ // UnifiedLoaderRepository) this can still work, so if user hasn't
+ // forbidden it, just return the contextClassLoader.
+ if (allowFlawedContext) {
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic(
+ "[WARNING] the context classloader is not part of a"
+ + " parent-child relationship with the classloader that"
+ + " loaded LogFactoryImpl.");
+ }
+ // If contextClassLoader were null, getLowestClassLoader() would
+ // have returned thisClassLoader. The fact we are here means
+ // contextClassLoader is not null, so we can just return it.
+ return contextClassLoader;
+ }
+ else {
+ throw new LogConfigurationException(
+ "Bad classloader hierarchy; LogFactoryImpl was loaded via"
+ + " a classloader that is not related to the current context"
+ + " classloader.");
+ }
+ }
+
+ if (baseClassLoader != contextClassLoader) {
+ // We really should just use the contextClassLoader as the starting
+ // point for scanning for log adapter classes. However it is expected
+ // that there are a number of broken systems out there which create
+ // custom classloaders but fail to set the context classloader so
+ // we handle those flawed systems anyway.
+ if (allowFlawedContext) {
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic(
+ "Warning: the context classloader is an ancestor of the"
+ + " classloader that loaded LogFactoryImpl; it should be"
+ + " the same or a descendant. The application using"
+ + " commons-logging should ensure the context classloader"
+ + " is used correctly.");
+ }
+ } else {
+ throw new LogConfigurationException(
+ "Bad classloader hierarchy; LogFactoryImpl was loaded via"
+ + " a classloader that is not related to the current context"
+ + " classloader.");
+ }
+ }
+
+ return baseClassLoader;
+ }
+
+ /**
+ * Given two related classloaders, return the one which is a child of
+ * the other.
+ *
+ * @param c1 is a classloader (including the null classloader)
+ * @param c2 is a classloader (including the null classloader)
+ *
+ * @return c1 if it has c2 as an ancestor, c2 if it has c1 as an ancestor,
+ * and null if neither is an ancestor of the other.
+ */
+ private ClassLoader getLowestClassLoader(ClassLoader c1, ClassLoader c2) {
+ // TODO: use AccessController when dealing with classloaders here
+
+ if (c1 == null)
+ return c2;
+
+ if (c2 == null)
+ return c1;
+
+ ClassLoader current;
+
+ // scan c1's ancestors to find c2
+ current = c1;
+ while (current != null) {
+ if (current == c2)
+ return c1;
+ current = current.getParent();
+ }
+
+ // scan c2's ancestors to find c1
+ current = c2;
+ while (current != null) {
+ if (current == c1)
+ return c2;
+ current = current.getParent();
+ }
+
+ return null;
+ }
+
+ /**
+ * Generates an internal diagnostic logging of the discovery failure and
+ * then throws a
+ * There are two possible reasons why we successfully loaded the
+ * specified log adapter class then failed to cast it to a Log object:
+ *
+ * Here we try to figure out which case has occurred so we can give the
+ * user some reasonable feedback.
+ *
+ * @param badClassLoader is the classloader we loaded the problem class from,
+ * ie it is equivalent to badClass.getClassLoader().
+ *
+ * @param badClass is a Class object with the desired name, but which
+ * does not implement Log correctly.
+ *
+ * @throws LogConfigurationException when the situation
+ * should not be recovered from.
+ */
+ private void handleFlawedHierarchy(ClassLoader badClassLoader, Class badClass)
+ throws LogConfigurationException {
+
+ boolean implementsLog = false;
+ String logInterfaceName = Log.class.getName();
+ Class interfaces[] = badClass.getInterfaces();
+ for (int i = 0; i < interfaces.length; i++) {
+ if (logInterfaceName.equals(interfaces[i].getName())) {
+ implementsLog = true;
+ break;
+ }
+ }
+
+ if (implementsLog) {
+ // the class does implement an interface called Log, but
+ // it is in the wrong classloader
+ if (isDiagnosticsEnabled()) {
+ try {
+ ClassLoader logInterfaceClassLoader = getClassLoader(Log.class);
+ logDiagnostic(
+ "Class '" + badClass.getName()
+ + "' was found in classloader "
+ + objectId(badClassLoader)
+ + ". It is bound to a Log interface which is not"
+ + " the one loaded from classloader "
+ + objectId(logInterfaceClassLoader));
+ } catch (Throwable t) {
+ logDiagnostic(
+ "Error while trying to output diagnostics about"
+ + " bad class '" + badClass + "'");
+ }
+ }
+
+ if (!allowFlawedHierarchy) {
+ StringBuffer msg = new StringBuffer();
+ msg.append("Terminating logging for this context ");
+ msg.append("due to bad log hierarchy. ");
+ msg.append("You have more than one version of '");
+ msg.append(Log.class.getName());
+ msg.append("' visible.");
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic(msg.toString());
+ }
+ throw new LogConfigurationException(msg.toString());
+ }
+
+ if (isDiagnosticsEnabled()) {
+ StringBuffer msg = new StringBuffer();
+ msg.append("Warning: bad log hierarchy. ");
+ msg.append("You have more than one version of '");
+ msg.append(Log.class.getName());
+ msg.append("' visible.");
+ logDiagnostic(msg.toString());
+ }
+ } else {
+ // this is just a bad adapter class
+ if (!allowFlawedDiscovery) {
+ StringBuffer msg = new StringBuffer();
+ msg.append("Terminating logging for this context. ");
+ msg.append("Log class '");
+ msg.append(badClass.getName());
+ msg.append("' does not implement the Log interface.");
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic(msg.toString());
+ }
+
+ throw new LogConfigurationException(msg.toString());
+ }
+
+ if (isDiagnosticsEnabled()) {
+ StringBuffer msg = new StringBuffer();
+ msg.append("[WARNING] Log class '");
+ msg.append(badClass.getName());
+ msg.append("' does not implement the Log interface.");
+ logDiagnostic(msg.toString());
+ }
+ }
+ }
+}
diff --git a/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/LogKitLogger.java b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/LogKitLogger.java
new file mode 100644
index 0000000..2587e81
--- /dev/null
+++ b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/LogKitLogger.java
@@ -0,0 +1,294 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.commons.logging.impl;
+
+import java.io.Serializable;
+import org.apache.log.Logger;
+import org.apache.log.Hierarchy;
+import org.apache.commons.logging.Log;
+
+/**
+ * Implementation of Return the underlying Logger we are using. Trivial implementation of Log that throws away all messages. No
+ * configurable system properties are supported.
+ * In general, the WeakHashtable support added in commons-logging release 1.1
+ * ensures that logging classes do not hold references that prevent an
+ * undeployed webapp's memory from being garbage-collected even when multiple
+ * copies of commons-logging are deployed via multiple classloaders (a
+ * situation that earlier versions had problems with). However there are
+ * some rare cases where the WeakHashtable approach does not work; in these
+ * situations specifying this class as a listener for the web application will
+ * ensure that all references held by commons-logging are fully released.
+ *
+ * To use this class, configure the webapp deployment descriptor to call
+ * this class on webapp undeploy; the contextDestroyed method will tell
+ * every accessable LogFactory class that the entry in its map for the
+ * current webapp's context classloader should be cleared.
+ *
+ * @since 1.1
+ */
+
+public class ServletContextCleaner implements ServletContextListener {
+
+ private Class[] RELEASE_SIGNATURE = {ClassLoader.class};
+
+ /**
+ * Invoked when a webapp is undeployed, this tells the LogFactory
+ * class to release any logging information related to the current
+ * contextClassloader.
+ */
+ public void contextDestroyed(ServletContextEvent sce) {
+ ClassLoader tccl = Thread.currentThread().getContextClassLoader();
+
+ Object[] params = new Object[1];
+ params[0] = tccl;
+
+ // Walk up the tree of classloaders, finding all the available
+ // LogFactory classes and releasing any objects associated with
+ // the tccl (ie the webapp).
+ //
+ // When there is only one LogFactory in the classpath, and it
+ // is within the webapp being undeployed then there is no problem;
+ // garbage collection works fine.
+ //
+ // When there are multiple LogFactory classes in the classpath but
+ // parent-first classloading is used everywhere, this loop is really
+ // short. The first instance of LogFactory found will
+ // be the highest in the classpath, and then no more will be found.
+ // This is ok, as with this setup this will be the only LogFactory
+ // holding any data associated with the tccl being released.
+ //
+ // When there are multiple LogFactory classes in the classpath and
+ // child-first classloading is used in any classloader, then multiple
+ // LogFactory instances may hold info about this TCCL; whenever the
+ // webapp makes a call into a class loaded via an ancestor classloader
+ // and that class calls LogFactory the tccl gets registered in
+ // the LogFactory instance that is visible from the ancestor
+ // classloader. However the concrete logging library it points
+ // to is expected to have been loaded via the TCCL, so the
+ // underlying logging lib is only initialised/configured once.
+ // These references from ancestor LogFactory classes down to
+ // TCCL classloaders are held via weak references and so should
+ // be released but there are circumstances where they may not.
+ // Walking up the classloader ancestry ladder releasing
+ // the current tccl at each level tree, though, will definitely
+ // clear any problem references.
+ ClassLoader loader = tccl;
+ while (loader != null) {
+ // Load via the current loader. Note that if the class is not accessable
+ // via this loader, but is accessable via some ancestor then that class
+ // will be returned.
+ try {
+ Class logFactoryClass = loader.loadClass("org.apache.commons.logging.LogFactory");
+ Method releaseMethod = logFactoryClass.getMethod("release", RELEASE_SIGNATURE);
+ releaseMethod.invoke(null, params);
+ loader = logFactoryClass.getClassLoader().getParent();
+ } catch(ClassNotFoundException ex) {
+ // Neither the current classloader nor any of its ancestors could find
+ // the LogFactory class, so we can stop now.
+ loader = null;
+ } catch(NoSuchMethodException ex) {
+ // This is not expected; every version of JCL has this method
+ System.err.println("LogFactory instance found which does not support release method!");
+ loader = null;
+ } catch(IllegalAccessException ex) {
+ // This is not expected; every ancestor class should be accessable
+ System.err.println("LogFactory instance found which is not accessable!");
+ loader = null;
+ } catch(InvocationTargetException ex) {
+ // This is not expected
+ System.err.println("LogFactory instance release method failed!");
+ loader = null;
+ }
+ }
+
+ // Just to be sure, invoke release on the LogFactory that is visible from
+ // this ServletContextCleaner class too. This should already have been caught
+ // by the above loop but just in case...
+ LogFactory.release(tccl);
+ }
+
+ /**
+ * Invoked when a webapp is deployed. Nothing needs to be done here.
+ */
+ public void contextInitialized(ServletContextEvent sce) {
+ // do nothing
+ }
+}
diff --git a/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/SimpleLog.java b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/SimpleLog.java
new file mode 100644
index 0000000..d966722
--- /dev/null
+++ b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/SimpleLog.java
@@ -0,0 +1,721 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.commons.logging.impl;
+
+import java.io.InputStream;
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogConfigurationException;
+
+/**
+ * Simple implementation of Log that sends all enabled log messages,
+ * for all defined loggers, to System.err. The following system properties
+ * are supported to configure the behavior of this logger: In addition to looking for system properties with the names specified
+ * above, this implementation also checks for a class loader resource named
+ *
+ * Any code that accesses this object should first obtain a lock on it,
+ * ie use synchronized(dateFormatter); this requirement was introduced
+ * in 1.1.1 to fix an existing thread safety bug (SimpleDateFormat.format
+ * is not thread-safe).
+ */
+ static protected DateFormat dateFormatter = null;
+
+ // ---------------------------------------------------- Log Level Constants
+
+
+ /** "Trace" level logging. */
+ public static final int LOG_LEVEL_TRACE = 1;
+ /** "Debug" level logging. */
+ public static final int LOG_LEVEL_DEBUG = 2;
+ /** "Info" level logging. */
+ public static final int LOG_LEVEL_INFO = 3;
+ /** "Warn" level logging. */
+ public static final int LOG_LEVEL_WARN = 4;
+ /** "Error" level logging. */
+ public static final int LOG_LEVEL_ERROR = 5;
+ /** "Fatal" level logging. */
+ public static final int LOG_LEVEL_FATAL = 6;
+
+ /** Enable all logging levels */
+ public static final int LOG_LEVEL_ALL = (LOG_LEVEL_TRACE - 1);
+
+ /** Enable no logging levels */
+ public static final int LOG_LEVEL_OFF = (LOG_LEVEL_FATAL + 1);
+
+ // ------------------------------------------------------------ Initializer
+
+ private static String getStringProperty(String name) {
+ String prop = null;
+ try {
+ prop = System.getProperty(name);
+ } catch (SecurityException e) {
+ ; // Ignore
+ }
+ return (prop == null) ? simpleLogProps.getProperty(name) : prop;
+ }
+
+ private static String getStringProperty(String name, String dephault) {
+ String prop = getStringProperty(name);
+ return (prop == null) ? dephault : prop;
+ }
+
+ private static boolean getBooleanProperty(String name, boolean dephault) {
+ String prop = getStringProperty(name);
+ return (prop == null) ? dephault : "true".equalsIgnoreCase(prop);
+ }
+
+ // Initialize class attributes.
+ // Load properties file, if found.
+ // Override with system properties.
+ static {
+ // Add props from the resource simplelog.properties
+ InputStream in = getResourceAsStream("simplelog.properties");
+ if(null != in) {
+ try {
+ simpleLogProps.load(in);
+ in.close();
+ } catch(java.io.IOException e) {
+ // ignored
+ }
+ }
+
+ showLogName = getBooleanProperty( systemPrefix + "showlogname", showLogName);
+ showShortName = getBooleanProperty( systemPrefix + "showShortLogname", showShortName);
+ showDateTime = getBooleanProperty( systemPrefix + "showdatetime", showDateTime);
+
+ if(showDateTime) {
+ dateTimeFormat = getStringProperty(systemPrefix + "dateTimeFormat",
+ dateTimeFormat);
+ try {
+ dateFormatter = new SimpleDateFormat(dateTimeFormat);
+ } catch(IllegalArgumentException e) {
+ // If the format pattern is invalid - use the default format
+ dateTimeFormat = DEFAULT_DATE_TIME_FORMAT;
+ dateFormatter = new SimpleDateFormat(dateTimeFormat);
+ }
+ }
+ }
+
+ // ------------------------------------------------------------- Attributes
+
+ /** The name of this simple log instance */
+ protected String logName = null;
+ /** The current log level */
+ protected int currentLogLevel;
+ /** The short name of this simple log instance */
+ private String shortLogName = null;
+
+
+ // ------------------------------------------------------------ Constructor
+
+ /**
+ * Construct a simple log with given name.
+ *
+ * @param name log name
+ */
+ public SimpleLog(String name) {
+
+ logName = name;
+
+ // Set initial log level
+ // Used to be: set default log level to ERROR
+ // IMHO it should be lower, but at least info ( costin ).
+ setLevel(SimpleLog.LOG_LEVEL_INFO);
+
+ // Set log level from properties
+ String lvl = getStringProperty(systemPrefix + "log." + logName);
+ int i = String.valueOf(name).lastIndexOf(".");
+ while(null == lvl && i > -1) {
+ name = name.substring(0,i);
+ lvl = getStringProperty(systemPrefix + "log." + name);
+ i = String.valueOf(name).lastIndexOf(".");
+ }
+
+ if(null == lvl) {
+ lvl = getStringProperty(systemPrefix + "defaultlog");
+ }
+
+ if("all".equalsIgnoreCase(lvl)) {
+ setLevel(SimpleLog.LOG_LEVEL_ALL);
+ } else if("trace".equalsIgnoreCase(lvl)) {
+ setLevel(SimpleLog.LOG_LEVEL_TRACE);
+ } else if("debug".equalsIgnoreCase(lvl)) {
+ setLevel(SimpleLog.LOG_LEVEL_DEBUG);
+ } else if("info".equalsIgnoreCase(lvl)) {
+ setLevel(SimpleLog.LOG_LEVEL_INFO);
+ } else if("warn".equalsIgnoreCase(lvl)) {
+ setLevel(SimpleLog.LOG_LEVEL_WARN);
+ } else if("error".equalsIgnoreCase(lvl)) {
+ setLevel(SimpleLog.LOG_LEVEL_ERROR);
+ } else if("fatal".equalsIgnoreCase(lvl)) {
+ setLevel(SimpleLog.LOG_LEVEL_FATAL);
+ } else if("off".equalsIgnoreCase(lvl)) {
+ setLevel(SimpleLog.LOG_LEVEL_OFF);
+ }
+
+ }
+
+
+ // -------------------------------------------------------- Properties
+
+ /**
+ * Set logging level. Get logging level. Do the actual logging.
+ * This method assembles the message
+ * and then calls Write the content of the message accumulated in the specified
+ * Are debug messages currently enabled? This allows expensive operations such as Are error messages currently enabled? This allows expensive operations such as Are fatal messages currently enabled? This allows expensive operations such as Are info messages currently enabled? This allows expensive operations such as Are trace messages currently enabled? This allows expensive operations such as Are warn messages currently enabled? This allows expensive operations such as Implementation of This class follows the symantics of Note:
+ * This is not intended to be a general purpose hash table replacement.
+ * This implementation is also tuned towards a particular purpose: for use as a replacement
+ * for
+ * Usage: typical use case is as a drop-in replacement
+ * for the The reason all this is necessary is due to a issue which
+ * arises during hot deploy in a J2EE-like containers.
+ * Each component running in the container owns one or more classloaders; when
+ * the component loads a LogFactory instance via the component classloader
+ * a reference to it gets stored in the static LogFactory.factories member,
+ * keyed by the component's classloader so different components don't
+ * stomp on each other. When the component is later unloaded, the container
+ * sets the component's classloader to null with the intent that all the
+ * component's classes get garbage-collected. However there's still a
+ * reference to the component's classloader from a key in the "global"
+ *
+ * Limitations:
+ * There is still one (unusual) scenario in which a component will not
+ * be correctly unloaded without an explicit release. Though weak references
+ * are used for its keys, it is necessary to use strong references for its values.
+ * If the abstract class
+ * Such a situation occurs when the commons-logging.jar is
+ * loaded by a parent classloader (e.g. a server level classloader in a
+ * servlet container) and a custom To avoid this scenario, ensure
+ * that any custom LogFactory subclass is loaded by the same classloader as
+ * the base Concrete implementations of commons-logging wrapper APIs. Simple wrapper API around multiple logging APIs. This package provides an API for logging in server-based applications that
+can be used around a variety of different logging implementations, including
+prebuilt support for the following: For those impatient to just get on with it, the following example
+illustrates the typical declaration and use of a logger that is named (by
+convention) after the calling class:
+
+ Unless you configure things differently, all log output will be written
+to System.err. Therefore, you really will want to review the remainder of
+this page in order to understand how to configure logging for your
+application. From an application perspective, the first requirement is to retrieve an
+object reference to the If a Once an implementation class name is selected, the corresponding class is
+loaded from the current Thread context class loader (if there is one), or
+from the class loader that loaded the The Logging Package APIs include a default See the SimpleLog JavaDocs for detailed
+configuration information for this default implementation. The basic principle is that the user is totally responsible for the
+configuration of the underlying logging system.
+Commons-logging should not change the existing configuration. Each individual Log implementation may
+support its own configuration properties. These will be documented in the
+class descriptions for the corresponding implementation class. Finally, some Use of the Logging Package APIs, from the perspective of an application
+component, consists of the following steps: For convenience, into a single method call: For example, you might use the following technique to initialize and
+use a Log instance in an application component:
+ * It is really up to the developer as to whether they want to use the Dispatch
+ * interface or the ActiveXComponent interface.
+ *
+ * This class simulates com.ms.activeX.ActiveXComponent only in the sense that
+ * it is used for creating Dispatch objects
+ */
+public class ActiveXComponent extends Dispatch {
+
+ /**
+ * Normally used to create a new connection to a microsoft application. The
+ * passed in parameter is the name of the program as registered in the
+ * registry. It can also be the object name.
+ *
+ * This constructor causes a new Windows object of the requested type to be
+ * created. The windows CoCreate() function gets called to create the
+ * underlying windows object.
+ *
+ *
+ * Factory that returns a Dispatch object wrapped around the result of a
+ * CoCreate() call. This differs from the standard constructor in that it
+ * throws no exceptions and returns null on failure.
+ *
+ * This will fail for any prog id with a ":" in it.
+ *
+ * @param pRequestedProgramId
+ * @return Dispatch pointer to the COM object or null if couldn't create
+ */
+ public static ActiveXComponent createNewInstance(String pRequestedProgramId) {
+ ActiveXComponent mCreatedDispatch = null;
+ try {
+ mCreatedDispatch = new ActiveXComponent();
+ mCreatedDispatch.coCreateInstance(pRequestedProgramId);
+ } catch (Exception e) {
+ mCreatedDispatch = null;
+ if (JacobObject.isDebugEnabled()) {
+ JacobObject.debug("Unable to co-create instance of "
+ + pRequestedProgramId);
+ }
+ }
+ return mCreatedDispatch;
+ }
+
+ /**
+ * Most code should use the standard ActiveXComponent(String) constructor
+ * and not this factory method. This method exists for applications that
+ * need special behavior. Experimental in release 1.9.2.
+ *
+ * Factory that returns a Dispatch wrapped around the result of a
+ * getActiveObject() call. This differs from the standard constructor in
+ * that it throws no exceptions and returns null on failure.
+ *
+ * This will fail for any prog id with a ":" in it
+ *
+ * @param pRequestedProgramId
+ * @return Dispatch pointer to a COM object or null if wasn't already
+ * running
+ */
+ public static ActiveXComponent connectToActiveInstance(
+ String pRequestedProgramId) {
+ ActiveXComponent mCreatedDispatch = null;
+ try {
+ mCreatedDispatch = new ActiveXComponent();
+ mCreatedDispatch.getActiveInstance(pRequestedProgramId);
+ } catch (Exception e) {
+ mCreatedDispatch = null;
+ if (JacobObject.isDebugEnabled()) {
+ JacobObject.debug("Unable to attach to running instance of "
+ + pRequestedProgramId);
+ }
+ }
+ return mCreatedDispatch;
+ }
+
+ /**
+ * @see com.jacob.com.Dispatch#finalize()
+ */
+ @Override
+ protected void finalize() {
+ super.finalize();
+ }
+
+ /*
+ * ============================================================
+ *
+ * start of instance based calls to the COM layer
+ * ===========================================================
+ */
+
+ /**
+ * retrieves a property and returns it as a Variant
+ *
+ * @param propertyName
+ * @return variant value of property
+ */
+ public Variant getProperty(String propertyName) {
+ return Dispatch.get(this, propertyName);
+ }
+
+ /**
+ * retrieves a property and returns it as an ActiveX component
+ *
+ * @param propertyName
+ * @return Dispatch representing the object under the property name
+ */
+ public ActiveXComponent getPropertyAsComponent(String propertyName) {
+ return new ActiveXComponent(Dispatch.get(this, propertyName)
+ .toDispatch());
+
+ }
+
+ /**
+ * retrieves a property and returns it as a Boolean
+ *
+ * @param propertyName
+ * property we are looking up
+ * @return boolean value of property
+ */
+ public boolean getPropertyAsBoolean(String propertyName) {
+ return Dispatch.get(this, propertyName).getBoolean();
+ }
+
+ /**
+ * retrieves a property and returns it as a byte
+ *
+ * @param propertyName
+ * property we are looking up
+ * @return byte value of property
+ */
+ public byte getPropertyAsByte(String propertyName) {
+ return Dispatch.get(this, propertyName).getByte();
+ }
+
+ /**
+ * retrieves a property and returns it as a String
+ *
+ * @param propertyName
+ * @return String value of property
+ */
+ public String getPropertyAsString(String propertyName) {
+ return Dispatch.get(this, propertyName).getString();
+
+ }
+
+ /**
+ * retrieves a property and returns it as a int
+ *
+ * @param propertyName
+ * @return the property value as an int
+ */
+ public int getPropertyAsInt(String propertyName) {
+ return Dispatch.get(this, propertyName).getInt();
+ }
+
+ /**
+ * sets a property on this object
+ *
+ * @param propertyName
+ * property name
+ * @param arg
+ * variant value to be set
+ */
+ public void setProperty(String propertyName, Variant arg) {
+ Dispatch.put(this, propertyName, arg);
+ }
+
+ /**
+ * sets a property on this object
+ *
+ * @param propertyName
+ * property name
+ * @param arg
+ * variant value to be set
+ */
+ public void setProperty(String propertyName, Dispatch arg) {
+ Dispatch.put(this, propertyName, arg);
+ }
+
+ /**
+ * sets a property to be the value of the string
+ *
+ * @param propertyName
+ * @param propertyValue
+ */
+ public void setProperty(String propertyName, String propertyValue) {
+ this.setProperty(propertyName, new Variant(propertyValue));
+ }
+
+ /**
+ * sets a property as a boolean value
+ *
+ * @param propertyName
+ * @param propValue
+ * the boolean value we want the prop set to
+ */
+ public void setProperty(String propertyName, boolean propValue) {
+ this.setProperty(propertyName, new Variant(propValue));
+ }
+
+ /**
+ * sets a property as a boolean value
+ *
+ * @param propertyName
+ * @param propValue
+ * the boolean value we want the prop set to
+ */
+ public void setProperty(String propertyName, byte propValue) {
+ this.setProperty(propertyName, new Variant(propValue));
+ }
+
+ /**
+ * sets the property as an int value
+ *
+ * @param propertyName
+ * @param propValue
+ * the int value we want the prop to be set to.
+ */
+ public void setProperty(String propertyName, int propValue) {
+ this.setProperty(propertyName, new Variant(propValue));
+ }
+
+ /*-------------------------------------------------------
+ * Listener logging helpers
+ *-------------------------------------------------------
+ */
+
+ /**
+ * This boolean determines if callback events should be logged
+ */
+ public static boolean shouldLogEvents = false;
+
+ /**
+ * used by the doc and application listeners to get intelligent logging
+ *
+ * @param description
+ * event description
+ * @param args
+ * args passed in (variants)
+ *
+ */
+ public void logCallbackEvent(String description, Variant[] args) {
+ String argString = "";
+ if (args != null && ActiveXComponent.shouldLogEvents) {
+ if (args.length > 0) {
+ argString += " args: ";
+ }
+ for (int i = 0; i < args.length; i++) {
+ short argType = args[i].getvt();
+ argString += ",[" + i + "]";
+ // break out the byref bits if they are on this
+ if ((argType & Variant.VariantByref) == Variant.VariantByref) {
+ // show the type and the fact that its byref
+ argString += "("
+ + (args[i].getvt() & ~Variant.VariantByref) + "/"
+ + Variant.VariantByref + ")";
+ } else {
+ // show the type
+ argString += "(" + argType + ")";
+ }
+ argString += "=";
+ if (argType == Variant.VariantDispatch) {
+ Dispatch foo = (args[i].getDispatch());
+ argString += foo;
+ } else if ((argType & Variant.VariantBoolean) == Variant.VariantBoolean) {
+ // do the boolean thing
+ if ((argType & Variant.VariantByref) == Variant.VariantByref) {
+ // boolean by ref
+ argString += args[i].getBooleanRef();
+ } else {
+ // boolean by value
+ argString += args[i].getBoolean();
+ }
+ } else if ((argType & Variant.VariantString) == Variant.VariantString) {
+ // do the string thing
+ if ((argType & Variant.VariantByref) == Variant.VariantByref) {
+ // string by ref
+ argString += args[i].getStringRef();
+ } else {
+ // string by value
+ argString += args[i].getString();
+ }
+ } else {
+ argString += args[i].toString();
+ }
+ }
+ System.out.println(description + argString);
+ }
+ }
+
+ /*
+ * ==============================================================
+ *
+ * covers for dispatch call methods
+ * =============================================================
+ */
+
+ /**
+ * makes a dispatch call for the passed in action and no parameter
+ *
+ * @param callAction
+ * @return ActiveXComponent representing the results of the call
+ */
+ public ActiveXComponent invokeGetComponent(String callAction) {
+ return new ActiveXComponent(invoke(callAction).toDispatch());
+ }
+
+ /**
+ * makes a dispatch call for the passed in action and single parameter
+ *
+ * @param callAction
+ * @param parameters
+ * @return ActiveXComponent representing the results of the call
+ */
+ public ActiveXComponent invokeGetComponent(String callAction,
+ Variant... parameters) {
+ return new ActiveXComponent(invoke(callAction, parameters).toDispatch());
+ }
+
+ /**
+ * invokes a single parameter call on this dispatch that returns no value
+ *
+ * @param actionCommand
+ * @param parameter
+ * @return a Variant but that may be null for some calls
+ */
+ public Variant invoke(String actionCommand, String parameter) {
+ return Dispatch.call(this, actionCommand, parameter);
+ }
+
+ /**
+ * makes a dispatch call to the passed in action with a single boolean
+ * parameter
+ *
+ * @param actionCommand
+ * @param parameter
+ * @return Variant result
+ */
+ public Variant invoke(String actionCommand, boolean parameter) {
+ return Dispatch.call(this, actionCommand, new Variant(parameter));
+ }
+
+ /**
+ * makes a dispatch call to the passed in action with a single int parameter
+ *
+ * @param actionCommand
+ * @param parameter
+ * @return Variant result of the invoke (Dispatch.call)
+ */
+ public Variant invoke(String actionCommand, int parameter) {
+ return Dispatch.call(this, actionCommand, new Variant(parameter));
+ }
+
+ /**
+ * makes a dispatch call to the passed in action with a string and integer
+ * parameter (this was put in for some application)
+ *
+ * @param actionCommand
+ * @param parameter1
+ * @param parameter2
+ * @return Variant result
+ */
+ public Variant invoke(String actionCommand, String parameter1,
+ int parameter2) {
+ return Dispatch.call(this, actionCommand, parameter1, new Variant(
+ parameter2));
+ }
+
+ /**
+ * makes a dispatch call to the passed in action with two integer parameters
+ * (this was put in for some application)
+ *
+ * @param actionCommand
+ * @param parameter1
+ * @param parameter2
+ * @return a Variant but that may be null for some calls
+ */
+ public Variant invoke(String actionCommand, int parameter1, int parameter2) {
+ return Dispatch.call(this, actionCommand, new Variant(parameter1),
+ new Variant(parameter2));
+ }
+
+ /**
+ * makes a dispatch call for the passed in action and no parameter
+ *
+ * @param callAction
+ * @return a Variant but that may be null for some calls
+ */
+ public Variant invoke(String callAction) {
+ return Dispatch.call(this, callAction);
+ }
+
+ /**
+ * This is really a cover for call(String,Variant[]) that should be
+ * eliminated call with a variable number of args mainly used for quit.
+ *
+ * @param name
+ * @param args
+ * @return Variant returned by the invoke (Dispatch.callN)
+ */
+ public Variant invoke(String name, Variant... args) {
+ return Dispatch.callN(this, name, args);
+ }
+
+}
\ No newline at end of file
diff --git a/vendor/jacob/1.15-M4/java/com/jacob/activeX/ActiveXDispatchEvents.java b/vendor/jacob/1.15-M4/java/com/jacob/activeX/ActiveXDispatchEvents.java
new file mode 100644
index 0000000..16bb649
--- /dev/null
+++ b/vendor/jacob/1.15-M4/java/com/jacob/activeX/ActiveXDispatchEvents.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1999-2004 Sourceforge JACOB Project.
+ * All rights reserved. Originator: Dan Adler (http://danadler.com).
+ * Get more information about JACOB at http://sourceforge.net/projects/jacob-project
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package com.jacob.activeX;
+
+import com.jacob.com.Dispatch;
+import com.jacob.com.DispatchEvents;
+import com.jacob.com.InvocationProxy;
+
+/**
+ * RELEASE 1.12 EXPERIMENTAL.
+ *
+ * Use this exactly like the DispatchEvents class. This class plugs in an
+ * ActiveXInvocationProxy instead of an InvocationProxy. It is the
+ * ActiveXInvocationProxy that implements the reflection calls and invoke the
+ * found java event callbacks. See ActiveXInvocationProxy for details.
+ *
+ *
+ */
+public class ActiveXDispatchEvents extends DispatchEvents {
+
+ /**
+ * This is the most commonly used constructor.
+ *
+ * Creates the event callback linkage between the the MS program represented
+ * by the Dispatch object and the Java object that will receive the
+ * callback.
+ *
+ * @param sourceOfEvent
+ * Dispatch object who's MS app will generate callbacks
+ * @param eventSink
+ * Java object that wants to receive the events
+ */
+ public ActiveXDispatchEvents(Dispatch sourceOfEvent, Object eventSink) {
+ super(sourceOfEvent, eventSink, null);
+ }
+
+ /**
+ * None of the samples use this constructor.
+ *
+ * Creates the event callback linkage between the the MS program represented
+ * by the Dispatch object and the Java object that will receive the
+ * callback.
+ *
+ * @param sourceOfEvent
+ * Dispatch object who's MS app will generate callbacks
+ * @param eventSink
+ * Java object that wants to receive the events
+ * @param progId
+ * ???
+ */
+ public ActiveXDispatchEvents(Dispatch sourceOfEvent, Object eventSink,
+ String progId) {
+ super(sourceOfEvent, eventSink, progId, null);
+ }
+
+ /**
+ * Creates the event callback linkage between the the MS program represented
+ * by the Dispatch object and the Java object that will receive the
+ * callback.
+ *
+ *
+ * This class that lets event handlers receive events with all java objects as
+ * parameters. The standard Jacob event methods all accept an array of Variant
+ * objects. When using this class, you can set up your event methods as regular
+ * java methods with the correct number of parameters of the correct java type.
+ * This does NOT work for any event that wishes to accept a call back and modify
+ * the calling parameters to tell windows what to do. An example is when an
+ * event lets the receiver cancel the action by setting a boolean flag to false.
+ * The java objects cannot be modified and their values will not be passed back
+ * into the originating Variants even if they could be modified.
+ *
+ * This class acts as a proxy between the windows event callback mechanism and
+ * the Java classes that are looking for events. It assumes that all of the Java
+ * classes that are looking for events implement methods with the same names as
+ * the windows events and that the implemented methods native java objects of
+ * the type and order that match the windows documentation. The methods can
+ * return void or a Variant that will be returned to the calling layer. All
+ * Event methods that will be recognized by InvocationProxyAllEvents have the
+ * signature
+ *
+ *
+ * In the future, this should convert to and from BigDecimal or Double
+ */
+public class Currency {
+ Long embeddedValue = null;
+
+ /**
+ * constructor that takes a long already in COM representation
+ *
+ * @param newValue
+ */
+ public Currency(long newValue) {
+ embeddedValue = new Long(newValue);
+ }
+
+ /**
+ * constructor that takes a String already in COM representation
+ *
+ * @param newValue
+ */
+ public Currency(String newValue) {
+ embeddedValue = new Long(newValue);
+ }
+
+ /**
+ *
+ * @return the currency as a primitive long
+ */
+ public long longValue() {
+ return embeddedValue.longValue();
+ }
+
+ /**
+ * getter to the inner storage so that cmpareTo can work
+ *
+ * @return the embedded long value
+ */
+ protected Long getLongValue() {
+ return embeddedValue;
+ }
+
+ /**
+ * compares the values of two currencies
+ *
+ * @param anotherCurrency
+ * @return the usual compareTo results
+ */
+ public int compareTo(Currency anotherCurrency) {
+ return embeddedValue.compareTo(anotherCurrency.getLongValue());
+ }
+
+ /**
+ * standard comparison
+ *
+ * @param o
+ * must be Currency or Long
+ * @return the usual compareTo results
+ */
+ public int compareTo(Object o) {
+ if (o instanceof Currency) {
+ return compareTo((Currency) o);
+ } else if (o instanceof Long) {
+ return embeddedValue.compareTo((Long) o);
+ } else
+ throw new IllegalArgumentException(
+ "Can only compare to Long and Currency not "
+ + o.getClass().getName());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean equals(Object o) {
+ if (o == null) {
+ return false;
+ } else if (compareTo(o) == 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/vendor/jacob/1.15-M4/java/com/jacob/com/DateUtilities.java b/vendor/jacob/1.15-M4/java/com/jacob/com/DateUtilities.java
new file mode 100644
index 0000000..195ba33
--- /dev/null
+++ b/vendor/jacob/1.15-M4/java/com/jacob/com/DateUtilities.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 1999-2004 Sourceforge JACOB Project.
+ * All rights reserved. Originator: Dan Adler (http://danadler.com).
+ * Get more information about JACOB at http://sourceforge.net/projects/jacob-project
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package com.jacob.com;
+
+import java.util.Calendar;
+import java.util.Date;
+
+/**
+ * java / windows date conversion utilities
+ *
+ * @author joe
+ *
+ */
+public class DateUtilities {
+
+ /**
+ * converts a windows time to a Java Date Object
+ *
+ * @param comTime
+ * @return Date object representing the windows time as specified in comTime
+ */
+ static public Date convertWindowsTimeToDate(double comTime) {
+ return new Date(convertWindowsTimeToMilliseconds(comTime));
+ }
+
+ /**
+ * Convert a COM time from functions Date(), Time(), Now() to a Java time
+ * (milliseconds). Visual Basic time values are based to 30.12.1899, Java
+ * time values are based to 1.1.1970 (= 0 milliseconds). The difference is
+ * added to the Visual Basic value to get the corresponding Java value. The
+ * Visual Basic double value reads:
+ * You're going to live here a lot
+ */
+public class Dispatch extends JacobObject {
+
+ /**
+ * Used to set the locale in a call. The user locale is another option
+ */
+ public static final int LOCALE_SYSTEM_DEFAULT = 2048;
+ /** used by callN() and callSubN() */
+ public static final int Method = 1;
+ /** used by callN() and callSubN() */
+ public static final int Get = 2;
+ /** used by put() */
+ public static final int Put = 4;
+ /** not used, probably intended for putRef() */
+ public static final int PutRef = 8;
+ /**
+ * One of legal values for GetDispId. Not used in this layer and probably
+ * not needed.
+ */
+ public static final int fdexNameCaseSensitive = 1;
+
+ /**
+ * This is public because Dispatch.cpp knows its name and accesses it
+ * directly to get the dispatch id. You really can't rename it or make it
+ * private
+ */
+ public int m_pDispatch;
+
+ /** program Id passed in by ActiveX components in their constructor */
+ private String programId = null;
+
+ private static int NOT_ATTACHED = 0;
+
+ /**
+ * Dummy empty array used one doesn't have to be created on every invocation
+ */
+ private final static Object[] NO_OBJECT_ARGS = new Object[0];
+ /**
+ * Dummy empty array used one doesn't have to be created on every invocation
+ */
+ private final static Variant[] NO_VARIANT_ARGS = new Variant[0];
+ /**
+ * Dummy empty array used one doesn't have to be created on every invocation
+ */
+ private final static int[] NO_INT_ARGS = new int[0];
+
+ /**
+ * zero argument constructor that sets the dispatch pointer to 0 This is the
+ * only way to create a Dispatch without a value in the pointer field.
+ */
+ public Dispatch() {
+ m_pDispatch = NOT_ATTACHED;
+ }
+
+ /**
+ * This constructor calls createInstance with progid. This is the
+ * constructor used by the ActiveXComponent or by programs that don't like
+ * the activeX interface but wish to create new connections to windows
+ * programs.
+ *
+ * This constructor always creates a new windows/program object because it
+ * is based on the CoCreate() windows function.
+ *
+ *
+ * @param requestedProgramId
+ * @throws IllegalArgumentException
+ * if null is passed in as the program id
+ *
+ */
+ public Dispatch(String requestedProgramId) {
+ programId = requestedProgramId;
+ if (programId != null && !"".equals(programId)) {
+ createInstanceNative(requestedProgramId);
+ } else {
+ throw new IllegalArgumentException(
+ "Dispatch(String) does not accept null or an empty string as a parameter");
+ }
+ }
+
+ /**
+ * native call createInstance only used by the constructor with the same
+ * parm type. This probably should be private. It is the wrapper for the
+ * Windows CoCreate() call
+ *
+ * This ends up calling CoCreate down in the JNI layer
+ *
+ * The behavior is different if a ":" character exists in the progId. In
+ * that case CoGetObject and CreateInstance (someone needs to describe this
+ * better)
+ *
+ * @param progid
+ */
+ private native void createInstanceNative(String progid);
+
+ /**
+ * native call getActiveInstance only used by the constructor with the same
+ * parm type. This probably should be private. It is the wrapper for the
+ * Windows GetActiveObject() call
+ *
+ * This ends up calling GetActiveObject down in the JNI layer
+ *
+ * This does not have the special behavior for program ids with ":" in them
+ * that createInstance has.
+ *
+ * @param progid
+ */
+ private native void getActiveInstanceNative(String progid);
+
+ /**
+ * Wrapper around the native method
+ *
+ * @param pProgramIdentifier
+ * name of the program you wish to connect to
+ */
+ protected void getActiveInstance(String pProgramIdentifier) {
+ if (pProgramIdentifier == null || "".equals(pProgramIdentifier)) {
+ throw new IllegalArgumentException("program id is required");
+ }
+ this.programId = pProgramIdentifier;
+ getActiveInstanceNative(pProgramIdentifier);
+ }
+
+ /**
+ * native call coCreateInstance only used by the constructor with the same
+ * parm type. This probably should be private. It is the wrapper for the
+ * Windows CoCreate() call
+ *
+ * This ends up calling CoCreate down in the JNI layer
+ *
+ * This does not have the special behavior for program ids with ":" in them
+ * that createInstance has.
+ *
+ * @param progid
+ */
+ private native void coCreateInstanceNative(String progid);
+
+ /**
+ * Wrapper around the native method
+ *
+ * @param pProgramIdentifier
+ */
+ protected void coCreateInstance(String pProgramIdentifier) {
+ if (pProgramIdentifier == null || "".equals(pProgramIdentifier)) {
+ throw new IllegalArgumentException("program id is required");
+ }
+ this.programId = pProgramIdentifier;
+ coCreateInstanceNative(pProgramIdentifier);
+ }
+
+ /**
+ * Return a different interface by IID string.
+ *
+ * Once you have a Dispatch object, you can navigate to the other interfaces
+ * of a COM object by calling QueryInterafce. The argument is an IID string
+ * in the format: "{9BF24410-B2E0-11D4-A695-00104BFF3241}". You typically
+ * get this string from the idl file (it's called uuid in there). Any
+ * interface you try to use must be derived from IDispatch. T The atl
+ * example uses this.
+ *
+ * The Dispatch instance resulting from this query is instanciated in the
+ * JNI code.
+ *
+ * @param iid
+ * @return Dispatch a disptach that matches ??
+ */
+ public native Dispatch QueryInterface(String iid);
+
+ /**
+ * Constructor that only gets called from JNI QueryInterface calls JNI code
+ * that looks up the object for the key passed in. The JNI CODE then creates
+ * a new dispatch object using this constructor
+ *
+ * @param pDisp
+ */
+ protected Dispatch(int pDisp) {
+ m_pDispatch = pDisp;
+ }
+
+ /**
+ * Constructor to be used by subclass that want to swap themselves in for
+ * the default Dispatch class. Usually you will have a class like
+ * WordDocument that is a subclass of Dispatch and it will have a
+ * constructor public WordDocument(Dispatch). That constructor should just
+ * call this constructor as super(Dispatch)
+ *
+ * @param dispatchToBeDisplaced
+ */
+ public Dispatch(Dispatch dispatchToBeDisplaced) {
+ // TAKE OVER THE IDispatch POINTER
+ this.m_pDispatch = dispatchToBeDisplaced.m_pDispatch;
+ // NULL OUT THE INPUT POINTER
+ dispatchToBeDisplaced.m_pDispatch = NOT_ATTACHED;
+ }
+
+ /**
+ * returns the program id if an activeX component created this otherwise it
+ * returns null. This was added to aid in debugging
+ *
+ * @return the program id an activeX component was created against
+ */
+ public String getProgramId() {
+ return programId;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#finalize()
+ */
+ @Override
+ protected void finalize() {
+ safeRelease();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.jacob.com.JacobObject#safeRelease()
+ */
+ @Override
+ public void safeRelease() {
+ super.safeRelease();
+ if (isAttached()) {
+ release();
+ m_pDispatch = NOT_ATTACHED;
+ } else {
+ // looks like a double release
+ if (isDebugEnabled()) {
+ debug(this.getClass().getName() + ":" + this.hashCode()
+ + " double release");
+ }
+ }
+ }
+
+ /**
+ *
+ * @return true if there is an underlying windows dispatch object
+ */
+ protected boolean isAttached() {
+ if (m_pDispatch == NOT_ATTACHED) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * @param theOneInQuestion
+ * dispatch being tested
+ * @throws IllegalStateException
+ * if this dispatch isn't hooked up
+ * @throws IllegalArgumentException
+ * if null the dispatch under test is null
+ */
+ private static void throwIfUnattachedDispatch(Dispatch theOneInQuestion) {
+ if (theOneInQuestion == null) {
+ throw new IllegalArgumentException(
+ "Can't pass in null Dispatch object");
+ } else if (theOneInQuestion.isAttached()) {
+ return;
+ } else {
+ throw new IllegalStateException(
+ "Dispatch not hooked to windows memory");
+ }
+ }
+
+ /**
+ * now private so only this object can access was: call this to explicitly
+ * release the com object before gc
+ *
+ */
+ private native void release();
+
+ /**
+ * not implemented yet
+ *
+ * @param dispatchTarget
+ * @param name
+ * @param val
+ * @throws com.jacob.com.NotImplementedException
+ */
+ public static void put_Casesensitive(Dispatch dispatchTarget, String name,
+ Object val) {
+ throw new NotImplementedException("not implemented yet");
+ }
+
+ /*
+ * ============================================================ start of the
+ * invokev section
+ * ===========================================================
+ */
+ // eliminate _Guid arg
+ /**
+ * @param dispatchTarget
+ * @param name
+ * @param dispID
+ * @param lcid
+ * @param wFlags
+ * @param vArg
+ * @param uArgErr
+ */
+ public static void invokeSubv(Dispatch dispatchTarget, String name,
+ int dispID, int lcid, int wFlags, Variant[] vArg, int[] uArgErr) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ invokev(dispatchTarget, name, dispID, lcid, wFlags, vArg, uArgErr);
+ }
+
+ /**
+ * @param dispatchTarget
+ * @param name
+ * @param wFlags
+ * @param vArg
+ * @param uArgErr
+ */
+ public static void invokeSubv(Dispatch dispatchTarget, String name,
+ int wFlags, Variant[] vArg, int[] uArgErr) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ invokev(dispatchTarget, name, 0, Dispatch.LOCALE_SYSTEM_DEFAULT,
+ wFlags, vArg, uArgErr);
+ }
+
+ /**
+ * @param dispatchTarget
+ * @param dispID
+ * @param wFlags
+ * @param vArg
+ * @param uArgErr
+ */
+ public static void invokeSubv(Dispatch dispatchTarget, int dispID,
+ int wFlags, Variant[] vArg, int[] uArgErr) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ invokev(dispatchTarget, null, dispID, Dispatch.LOCALE_SYSTEM_DEFAULT,
+ wFlags, vArg, uArgErr);
+ }
+
+ /**
+ * not implemented yet
+ *
+ * @param dispatchTarget
+ * @param name
+ * @param values
+ * @return never returns anything because
+ * @throws com.jacob.com.NotImplementedException
+ */
+ public static Variant callN_CaseSensitive(Dispatch dispatchTarget,
+ String name, Object[] values) {
+ throw new NotImplementedException("not implemented yet");
+ }
+
+ /**
+ * @param dispatchTarget
+ * @param name
+ * @param args
+ * an array of argument objects
+ */
+ public static void callSubN(Dispatch dispatchTarget, String name,
+ Object... args) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ invokeSubv(dispatchTarget, name, Dispatch.Method | Dispatch.Get,
+ VariantUtilities.objectsToVariants(args), new int[args.length]);
+ }
+
+ /**
+ * @param dispatchTarget
+ * @param dispID
+ * @param args
+ * an array of argument objects
+ */
+ public static void callSubN(Dispatch dispatchTarget, int dispID,
+ Object... args) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ invokeSubv(dispatchTarget, dispID, Dispatch.Method | Dispatch.Get,
+ VariantUtilities.objectsToVariants(args), new int[args.length]);
+ }
+
+ /*
+ * ============================================================ start of the
+ * getIdsOfNames section
+ * ===========================================================
+ */
+ /**
+ * @param dispatchTarget
+ * @param name
+ * @return int id for the passed in name
+ */
+ public static int getIDOfName(Dispatch dispatchTarget, String name) {
+ int ids[] = getIDsOfNames(dispatchTarget,
+ Dispatch.LOCALE_SYSTEM_DEFAULT, new String[] { name });
+ return ids[0];
+ }
+
+ /**
+ * @param dispatchTarget
+ * @param lcid
+ * @param names
+ * @return int[] in id array for passed in names
+ */
+ // eliminated _Guid argument
+ public static native int[] getIDsOfNames(Dispatch dispatchTarget, int lcid,
+ String[] names);
+
+ /**
+ * @param dispatchTarget
+ * @param names
+ * @return int[] int id array for passed in names
+ */
+ // eliminated _Guid argument
+ public static int[] getIDsOfNames(Dispatch dispatchTarget, String[] names) {
+ return getIDsOfNames(dispatchTarget, Dispatch.LOCALE_SYSTEM_DEFAULT,
+ names);
+ }
+
+ /*
+ * ============================================================ start of the
+ * invokev section
+ * ===========================================================
+ */
+ /**
+ * @param dispatchTarget
+ * @param name
+ * @param args
+ * @return Variant returned by call
+ */
+ public static Variant callN(Dispatch dispatchTarget, String name,
+ Object... args) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ return invokev(dispatchTarget, name, Dispatch.Method | Dispatch.Get,
+ VariantUtilities.objectsToVariants(args), new int[args.length]);
+ }
+
+ /**
+ * @param dispatchTarget
+ * @param dispID
+ * @param args
+ * @return Variant returned by call
+ */
+ public static Variant callN(Dispatch dispatchTarget, int dispID,
+ Object... args) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ return invokev(dispatchTarget, dispID, Dispatch.Method | Dispatch.Get,
+ VariantUtilities.objectsToVariants(args), new int[args.length]);
+ }
+
+ /**
+ * @param dispatchTarget
+ * @param name
+ * @param dispID
+ * @param lcid
+ * @param wFlags
+ * @param oArg
+ * @param uArgErr
+ * @return Variant returned by invoke
+ */
+ public static Variant invoke(Dispatch dispatchTarget, String name,
+ int dispID, int lcid, int wFlags, Object[] oArg, int[] uArgErr) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ return invokev(dispatchTarget, name, dispID, lcid, wFlags,
+ VariantUtilities.objectsToVariants(oArg), uArgErr);
+ }
+
+ /**
+ * @param dispatchTarget
+ * @param name
+ * @param wFlags
+ * @param oArg
+ * @param uArgErr
+ * @return Variant returned by invoke
+ */
+ public static Variant invoke(Dispatch dispatchTarget, String name,
+ int wFlags, Object[] oArg, int[] uArgErr) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ return invokev(dispatchTarget, name, wFlags, VariantUtilities
+ .objectsToVariants(oArg), uArgErr);
+ }
+
+ /**
+ * @param dispatchTarget
+ * @param dispID
+ * @param wFlags
+ * @param oArg
+ * @param uArgErr
+ * @return Variant returned by invoke
+ */
+ public static Variant invoke(Dispatch dispatchTarget, int dispID,
+ int wFlags, Object[] oArg, int[] uArgErr) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ return invokev(dispatchTarget, dispID, wFlags, VariantUtilities
+ .objectsToVariants(oArg), uArgErr);
+ }
+
+ /*
+ * ============================================================ start of the
+ * callN section ===========================================================
+ */
+
+ /**
+ * @param dispatchTarget
+ * @param name
+ * @return Variant returned by underlying callN
+ */
+ public static Variant call(Dispatch dispatchTarget, String name) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ return callN(dispatchTarget, name, NO_VARIANT_ARGS);
+ }
+
+ /**
+ * @param dispatchTarget
+ * @param name
+ * @param attributes
+ * @return Variant returned by underlying callN
+ */
+ public static Variant call(Dispatch dispatchTarget, String name,
+ Object... attributes) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ return callN(dispatchTarget, name, attributes);
+ }
+
+ /**
+ * @param dispatchTarget
+ * @param dispid
+ * @return Variant returned by underlying callN
+ */
+ public static Variant call(Dispatch dispatchTarget, int dispid) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ return callN(dispatchTarget, dispid, NO_VARIANT_ARGS);
+ }
+
+ /**
+ * @param dispatchTarget
+ * @param dispid
+ * @param attributes
+ * var arg list of attributes that will be passed to the
+ * underlying function
+ * @return Variant returned by underlying callN
+ */
+ public static Variant call(Dispatch dispatchTarget, int dispid,
+ Object... attributes) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ return callN(dispatchTarget, dispid, attributes);
+ }
+
+ /*
+ * ============================================================ start of the
+ * invoke section
+ * ===========================================================
+ */
+ /**
+ * @param dispatchTarget
+ * @param name
+ * @param val
+ */
+ public static void put(Dispatch dispatchTarget, String name, Object val) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ invoke(dispatchTarget, name, Dispatch.Put, new Object[] { val },
+ new int[1]);
+ }
+
+ /**
+ * @param dispatchTarget
+ * @param dispid
+ * @param val
+ */
+ public static void put(Dispatch dispatchTarget, int dispid, Object val) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ invoke(dispatchTarget, dispid, Dispatch.Put, new Object[] { val },
+ new int[1]);
+ }
+
+ /*
+ * ============================================================ start of the
+ * invokev section
+ * ===========================================================
+ */
+ // removed _Guid argument
+ /**
+ * @param dispatchTarget
+ * @param name
+ * @param dispID
+ * @param lcid
+ * @param wFlags
+ * @param vArg
+ * @param uArgErr
+ * @return Variant returned by underlying invokev
+ */
+ public static native Variant invokev(Dispatch dispatchTarget, String name,
+ int dispID, int lcid, int wFlags, Variant[] vArg, int[] uArgErr);
+
+ /**
+ * @param dispatchTarget
+ * @param name
+ * @param wFlags
+ * @param vArg
+ * @param uArgErr
+ * @return Variant returned by underlying invokev
+ */
+ public static Variant invokev(Dispatch dispatchTarget, String name,
+ int wFlags, Variant[] vArg, int[] uArgErr) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ return invokev(dispatchTarget, name, 0, Dispatch.LOCALE_SYSTEM_DEFAULT,
+ wFlags, vArg, uArgErr);
+ }
+
+ /**
+ * @param dispatchTarget
+ * @param name
+ * @param wFlags
+ * @param vArg
+ * @param uArgErr
+ * @param wFlagsEx
+ * @return Variant returned by underlying invokev
+ */
+ public static Variant invokev(Dispatch dispatchTarget, String name,
+ int wFlags, Variant[] vArg, int[] uArgErr, int wFlagsEx) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ // do not implement IDispatchEx for now
+ return invokev(dispatchTarget, name, 0, Dispatch.LOCALE_SYSTEM_DEFAULT,
+ wFlags, vArg, uArgErr);
+ }
+
+ /**
+ * @param dispatchTarget
+ * @param dispID
+ * @param wFlags
+ * @param vArg
+ * @param uArgErr
+ * @return Variant returned by underlying invokev
+ */
+ public static Variant invokev(Dispatch dispatchTarget, int dispID,
+ int wFlags, Variant[] vArg, int[] uArgErr) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ return invokev(dispatchTarget, null, dispID,
+ Dispatch.LOCALE_SYSTEM_DEFAULT, wFlags, vArg, uArgErr);
+ }
+
+ /*
+ * ============================================================ start of the
+ * invokeSubv section
+ * ===========================================================
+ */
+
+ // removed _Guid argument
+ /**
+ * @param dispatchTarget
+ * @param name
+ * @param dispid
+ * @param lcid
+ * @param wFlags
+ * @param oArg
+ * @param uArgErr
+ */
+ public static void invokeSub(Dispatch dispatchTarget, String name,
+ int dispid, int lcid, int wFlags, Object[] oArg, int[] uArgErr) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ invokeSubv(dispatchTarget, name, dispid, lcid, wFlags, VariantUtilities
+ .objectsToVariants(oArg), uArgErr);
+ }
+
+ /*
+ * ============================================================ start of the
+ * invokeSub section
+ * ===========================================================
+ */
+ /**
+ * @param dispatchTarget
+ * @param name
+ * @param wFlags
+ * @param oArg
+ * @param uArgErr
+ */
+ public static void invokeSub(Dispatch dispatchTarget, String name,
+ int wFlags, Object[] oArg, int[] uArgErr) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ invokeSub(dispatchTarget, name, 0, Dispatch.LOCALE_SYSTEM_DEFAULT,
+ wFlags, oArg, uArgErr);
+ }
+
+ /**
+ * @param dispatchTarget
+ * @param dispid
+ * @param wFlags
+ * @param oArg
+ * @param uArgErr
+ */
+ public static void invokeSub(Dispatch dispatchTarget, int dispid,
+ int wFlags, Object[] oArg, int[] uArgErr) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ invokeSub(dispatchTarget, null, dispid, Dispatch.LOCALE_SYSTEM_DEFAULT,
+ wFlags, oArg, uArgErr);
+ }
+
+ /*
+ * ============================================================ start of the
+ * callSubN section
+ * ===========================================================
+ */
+ /**
+ * makes call to native callSubN
+ *
+ * @param dispatchTarget
+ * @param name
+ */
+ public static void callSub(Dispatch dispatchTarget, String name) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ callSubN(dispatchTarget, name, NO_OBJECT_ARGS);
+ }
+
+ /**
+ * makes call to native callSubN
+ *
+ * @param dispatchTarget
+ * @param name
+ * @param attributes
+ * var args list of attributes to be passed to underlying
+ * functions
+ */
+ public static void callSub(Dispatch dispatchTarget, String name,
+ Object... attributes) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ callSubN(dispatchTarget, name, attributes);
+ }
+
+ /**
+ * makes call to native callSubN
+ *
+ * @param dispatchTarget
+ * @param dispid
+ */
+ public static void callSub(Dispatch dispatchTarget, int dispid) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ callSubN(dispatchTarget, dispid, NO_OBJECT_ARGS);
+ }
+
+ /**
+ * makes call to native callSubN
+ *
+ * @param dispatchTarget
+ * @param dispid
+ * @param attributes
+ * var args list of attributes to be passed to underlying
+ * function
+ */
+ public static void callSub(Dispatch dispatchTarget, int dispid,
+ Object... attributes) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ callSubN(dispatchTarget, dispid, attributes);
+ }
+
+ /*
+ * ============================================================ start of the
+ * invokev section
+ * ===========================================================
+ */
+ /**
+ * Cover for call to underlying invokev()
+ *
+ * @param dispatchTarget
+ * @param name
+ * @return Variant returned by the request for retrieval of parameter
+ */
+ public static Variant get(Dispatch dispatchTarget, String name) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ return invokev(dispatchTarget, name, Dispatch.Get, NO_VARIANT_ARGS,
+ NO_INT_ARGS);
+ }
+
+ /**
+ * Cover for call to underlying invokev()
+ *
+ * @param dispatchTarget
+ * @param dispid
+ * @return Variant returned by the request for retrieval of parameter
+ */
+ public static Variant get(Dispatch dispatchTarget, int dispid) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ return invokev(dispatchTarget, dispid, Dispatch.Get, NO_VARIANT_ARGS,
+ NO_INT_ARGS);
+ }
+
+ /*
+ * ============================================================ start of the
+ * invoke section
+ * ===========================================================
+ */
+ /**
+ * cover for underlying call to invoke
+ *
+ * @param dispatchTarget
+ * @param name
+ * @param val
+ */
+ public static void putRef(Dispatch dispatchTarget, String name, Object val) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ invoke(dispatchTarget, name, Dispatch.PutRef, new Object[] { val },
+ new int[1]);
+ }
+
+ /**
+ * cover for underlying call to invoke
+ *
+ * @param dispatchTarget
+ * @param dispid
+ * @param val
+ */
+ public static void putRef(Dispatch dispatchTarget, int dispid, Object val) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ invoke(dispatchTarget, dispid, Dispatch.PutRef, new Object[] { val },
+ new int[1]);
+ }
+
+ /**
+ * not implemented yet
+ *
+ * @param dispatchTarget
+ * @param name
+ * @return Variant never returned
+ * @throws com.jacob.com.NotImplementedException
+ */
+ public static Variant get_CaseSensitive(Dispatch dispatchTarget, String name) {
+ throw new NotImplementedException("not implemented yet");
+ }
+
+ /**
+ * Cover for native method
+ *
+ * @param disp
+ * @param dispid
+ * @param lcid
+ * @return 0 if the dispatch is still active and 1 if it has exited
+ */
+ public static native int hasExited(Dispatch disp, int dispid, int lcid);
+
+ /**
+ * The method is used to poll until it returns 1, indicating that the COM
+ * server in gone.
+ *
+ * Sourceforge feature request 2927058
+ *
+ * @param dispatchTarget
+ * @return 0 if the dispatch is still active and 1 if it has exited
+ */
+ public static int hasExited(Dispatch dispatchTarget) {
+ throwIfUnattachedDispatch(dispatchTarget);
+ return hasExited(dispatchTarget, 0, LOCALE_SYSTEM_DEFAULT);
+ }
+
+}
diff --git a/vendor/jacob/1.15-M4/java/com/jacob/com/DispatchEvents.java b/vendor/jacob/1.15-M4/java/com/jacob/com/DispatchEvents.java
new file mode 100644
index 0000000..a9ca0a1
--- /dev/null
+++ b/vendor/jacob/1.15-M4/java/com/jacob/com/DispatchEvents.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 1999-2004 Sourceforge JACOB Project.
+ * All rights reserved. Originator: Dan Adler (http://danadler.com).
+ * Get more information about JACOB at http://sourceforge.net/projects/jacob-project
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package com.jacob.com;
+
+/**
+ * This class creates the scaffolding for event callbacks. Every instance of tis
+ * acts as a wrapper around some java object that wants callbacks from the
+ * microsoft side. It represents the connection between Java and COM for
+ * callbacks.
+ *
+ * The callback mechanism will take any event that it receives and try and find
+ * a java method with the same name that accepts the Variant... as a parameter.
+ * It will then wrap the call back data in the Variant array and call the java
+ * method of the object that this DispatchEvents object was initialized with.
+ *
+ * Instances of this class are created with "sink object" that will receive the
+ * event messages. The sink object is wrapped in an Invocation handler that
+ * actually receives the messages and then forwards them on to the "sink
+ * object". The constructors recognize when an instance of InvocationProxy is
+ * passed in and do not create a new InvocationProxy as a wrapper. They instead
+ * use the passed in InvocationProxy.
+ *
+ */
+public class DispatchEvents extends JacobObject {
+
+ /**
+ * pointer to an MS data struct. The COM layer knows the name of this
+ * variable and puts the windows memory pointer here.
+ */
+ int m_pConnPtProxy = 0;
+
+ /**
+ * the wrapper for the event sink. This object is the one that will be sent
+ * a message when an event occurs in the MS layer. Normally, the
+ * InvocationProxy will forward the messages to a wrapped object that it
+ * contains.
+ */
+ InvocationProxy mInvocationProxy = null;
+
+ /**
+ * This is the most commonly used constructor.
+ *
+ * Creates the event callback linkage between the the MS program represented
+ * by the Dispatch object and the Java object that will receive the
+ * callback.
+ *
+ * Can be used on any object that implements IProvideClassInfo.
+ *
+ * @param sourceOfEvent
+ * Dispatch object who's MS app will generate callbacks
+ * @param eventSink
+ * Java object that wants to receive the events
+ */
+ public DispatchEvents(Dispatch sourceOfEvent, Object eventSink) {
+ this(sourceOfEvent, eventSink, null);
+ }
+
+ /**
+ * None of the samples use this constructor.
+ *
+ * Creates the event callback linkage between the the MS program represented
+ * by the Dispatch object and the Java object that will receive the
+ * callback.
+ *
+ * Used when the program doesn't implement IProvideClassInfo. It provides a
+ * way to find the TypeLib in the registry based on the programId. The
+ * TypeLib is looked up in the registry on the path
+ * HKEY_LOCAL_MACHINE/SOFTWARE/Classes/CLSID/(CLID drived from
+ * progid)/ProgID/Typelib
+ *
+ * @param sourceOfEvent
+ * Dispatch object who's MS app will generate callbacks
+ * @param eventSink
+ * Java object that wants to receive the events
+ * @param progId
+ * program id in the registry that has a TypeLib subkey. The
+ * progrId is mapped to a CLSID that is they used to look up the
+ * key to the Typelib
+ */
+ public DispatchEvents(Dispatch sourceOfEvent, Object eventSink,
+ String progId) {
+ this(sourceOfEvent, eventSink, progId, null);
+ }
+
+ /**
+ * Creates the event callback linkage between the the MS program represented
+ * by the Dispatch object and the Java object that will receive the
+ * callback.
+ *
+ * This method was added because Excel doesn't implement IProvideClassInfo
+ * and the registry entry for Excel.Application doesn't include a typelib
+ * key.
+ *
+ *
+ *
+ * The void returning signature is the standard legacy signature. The Variant
+ * returning signature was added in 1.10 to support event handlers returning
+ * values.
+ *
+ */
+public abstract class InvocationProxy {
+
+ /**
+ * the object we will try and forward to.
+ */
+ protected Object mTargetObject = null;
+
+ /**
+ * dummy constructor for subclasses that don't actually wrap anything and
+ * just want to override the invoke() method
+ */
+ protected InvocationProxy() {
+ super();
+ }
+
+ /**
+ * The method actually invoked by EventProxy.cpp. The method name is
+ * calculated by the underlying JNI code from the MS windows Callback
+ * function name. The method is assumed to take an array of Variant objects.
+ * The method may return a Variant or be a void. Those are the only two
+ * options that will not blow up.
+ *
+ * Subclasses that override this should make sure mTargetObject is not null
+ * before processing.
+ *
+ * @param methodName
+ * name of method in mTargetObject we will invoke
+ * @param targetParameters
+ * Variant[] that is the single parameter to the method
+ * @return an object that will be returned to the com event caller
+ */
+ public abstract Variant invoke(String methodName,
+ Variant targetParameters[]);
+
+ /**
+ * used by EventProxy.cpp to create variant objects in the right thread
+ *
+ * @return Variant object that will be used by the COM layer
+ */
+ public Variant getVariant() {
+ return new VariantViaEvent();
+ }
+
+ /**
+ * Sets the target for this InvocationProxy.
+ *
+ * @param pTargetObject
+ * @throws IllegalArgumentException
+ * if target is not publicly accessible
+ */
+ public void setTarget(Object pTargetObject) {
+ if (JacobObject.isDebugEnabled()) {
+ JacobObject.debug("InvocationProxy: setting target "
+ + pTargetObject);
+ }
+ if (pTargetObject != null) {
+ // JNI code apparently bypasses this check and could operate against
+ // protected classes. This seems like a security issue...
+ // maybe it was because JNI code isn't in a package?
+ if (!java.lang.reflect.Modifier.isPublic(pTargetObject.getClass()
+ .getModifiers())) {
+ throw new IllegalArgumentException(
+ "InvocationProxy only public classes can receive event notifications");
+ }
+ }
+ mTargetObject = pTargetObject;
+ }
+
+}
diff --git a/vendor/jacob/1.15-M4/java/com/jacob/com/InvocationProxyAllVariants.java b/vendor/jacob/1.15-M4/java/com/jacob/com/InvocationProxyAllVariants.java
new file mode 100644
index 0000000..3a5d846
--- /dev/null
+++ b/vendor/jacob/1.15-M4/java/com/jacob/com/InvocationProxyAllVariants.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 1999-2004 Sourceforge JACOB Project.
+ * All rights reserved. Originator: Dan Adler (http://danadler.com).
+ * Get more information about JACOB at http://sourceforge.net/projects/jacob-project
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package com.jacob.com;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * This class acts as a proxy between the windows event callback mechanism and
+ * the Java classes that are looking for events. It assumes that all of the Java
+ * classes that are looking for events implement methods with the same names as
+ * the windows events and that the implemented methods accept an array of
+ * variant objects. The methods can return void or a Variant that will be
+ * returned to the calling layer. All Event methods that will be recognized by
+ * InvocationProxyAllEvents have the signature
+ *
+ *
+ * All instances of this class and subclasses are automatically managed by the
+ * ROT. This means the ROT cannot be a subclass of JacobObject.
+ *
+ * All COM object created by JACOB extend this class so that we can
+ * automatically release them when the thread is detached from COM - if we leave
+ * it to the finalizer it will call the release from another thread, which may
+ * result in a segmentation violation.
+ */
+public class JacobObject {
+
+ /**
+ * Standard constructor that adds this JacobObject to the memory management
+ * pool.
+ */
+ public JacobObject() {
+ ROT.addObject(this);
+ }
+
+ /**
+ * Finalizers call this method. This method should release any COM data
+ * structures in a way that it can be called multiple times. This can happen
+ * if someone manually calls this and then a finalizer calls it.
+ */
+ public void safeRelease() {
+ // currently does nothing - subclasses may do something
+ if (isDebugEnabled()) {
+ // this used to do a toString() but that is bad for SafeArray
+ debug("SafeRelease: " + this.getClass().getName());
+ }
+ }
+
+ /**
+ * When things go wrong, it is useful to be able to debug the ROT.
+ */
+ private static final boolean DEBUG =
+ // true;
+ "true".equalsIgnoreCase(System.getProperty("com.jacob.debug"));
+
+ protected static boolean isDebugEnabled() {
+ return DEBUG;
+ }
+
+ /**
+ * Loads JacobVersion.Properties and returns the value of version in it
+ *
+ * @deprecated use JacobReleaseInfo.getBuildDate() instead.
+ * @return String value of version in JacobVersion.Properties or "" if none
+ */
+ @Deprecated
+ public static String getBuildDate() {
+ return JacobReleaseInfo.getBuildDate();
+ }
+
+ /**
+ * Loads JacobVersion.Properties and returns the value of version in it
+ *
+ * @deprecated use JacobReleaseInfo.getBuildVersion() instead.
+ * @return String value of version in JacobVersion.Properties or "" if none
+ */
+ @Deprecated
+ public static String getBuildVersion() {
+ return JacobReleaseInfo.getBuildVersion();
+ }
+
+ /**
+ * Very basic debugging function.
+ *
+ * @param istrMessage
+ */
+ protected static void debug(String istrMessage) {
+ if (isDebugEnabled()) {
+ System.out.println(Thread.currentThread().getName() + ": "
+ + istrMessage);
+ }
+ }
+
+ /**
+ * force the jacob DLL to be loaded whenever this class is referenced
+ */
+ static {
+ LibraryLoader.loadJacobLibrary();
+ }
+
+}
\ No newline at end of file
diff --git a/vendor/jacob/1.15-M4/java/com/jacob/com/JacobReleaseInfo.java b/vendor/jacob/1.15-M4/java/com/jacob/com/JacobReleaseInfo.java
new file mode 100644
index 0000000..a41b239
--- /dev/null
+++ b/vendor/jacob/1.15-M4/java/com/jacob/com/JacobReleaseInfo.java
@@ -0,0 +1,96 @@
+package com.jacob.com;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+/**
+ * An interface to the version properties file. This code was removed from
+ * JacobObject because it doesn't belong there.
+ *
+ */
+public class JacobReleaseInfo {
+
+ /**
+ * holds the build version as retrieved from the version properties file
+ * that exists in the JAR. This can be retrieved by calling the static
+ * method getBuildVersion()
+ *
+ * @see #getBuildVersion()
+ */
+ private static String buildVersion = "";
+ /**
+ * holds the build date as retrieved from the version properties file that
+ * exists in the JAR This can be retrieved by calling the static method
+ * getBuildDate()
+ *
+ * @see #getBuildDate()
+ */
+ private static String buildDate = "";
+ /** the name of the jacob version properties file */
+ private static final String PROPERTY_FILE_NAME = "META-INF/JacobVersion.properties";
+
+ /**
+ * Loads version information from PROPERTY_FILE_NAME that was built as part
+ * of this release.
+ *
+ * @throws IllegalStateException
+ * when it can't find the version properties file
+ */
+ private static void loadVersionProperties() {
+ Properties versionProps = new Properties();
+ // can't use system class loader cause won't work in JavaWebStart
+ InputStream stream = JacobReleaseInfo.class.getClassLoader()
+ .getResourceAsStream(PROPERTY_FILE_NAME);
+ // This should never happen. This is an attempt to make something work
+ // for WebSphere. They may be using some kind of Servlet loader that
+ // needs an absolute path based search
+ if (stream == null) {
+ stream = JacobReleaseInfo.class.getClassLoader()
+ .getResourceAsStream("/" + PROPERTY_FILE_NAME);
+ }
+ // A report came in that WebSphere had trouble finding the file
+ // so lets trap it. Plus, it's a good idea anyway.
+ if (stream == null) {
+ throw new IllegalStateException(
+ "Can't find "
+ + PROPERTY_FILE_NAME
+ + " using JacobReleaseInfo.class.getClassLoader().getResourceAsStream()");
+ } else {
+ try {
+ versionProps.load(stream);
+ stream.close();
+ buildVersion = (String) versionProps.get("version");
+ buildDate = (String) versionProps.get("build.date");
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ System.err.println("Warning! Couldn't load props " + ioe);
+ }
+ }
+ }
+
+ /**
+ * loads PROPERT_FILE_NAME and returns the value of version in it
+ *
+ * @return String value of version in PROPERT_FILE_NAME or "" if none
+ */
+ public static String getBuildDate() {
+ if (buildDate.equals("")) {
+ loadVersionProperties();
+ }
+ return buildDate;
+ }
+
+ /**
+ * loads PROPERT_FILE_NAME and returns the value of version in it
+ *
+ * @return String value of version in PROPERT_FILE_NAME or "" if none
+ */
+ public static String getBuildVersion() {
+ if (buildVersion.equals("")) {
+ loadVersionProperties();
+ }
+ return buildVersion;
+ }
+
+}
diff --git a/vendor/jacob/1.15-M4/java/com/jacob/com/LibraryLoader.java b/vendor/jacob/1.15-M4/java/com/jacob/com/LibraryLoader.java
new file mode 100644
index 0000000..4fd2740
--- /dev/null
+++ b/vendor/jacob/1.15-M4/java/com/jacob/com/LibraryLoader.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 1999-2007 Sourceforge JACOB Project.
+ * All rights reserved. Originator: Dan Adler (http://danadler.com).
+ * Get more information about JACOB at http://sourceforge.net/projects/jacob-project
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package com.jacob.com;
+
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.Set;
+
+/**
+ * Utility class to centralize the way in which the jacob JNI library is loaded.
+ *
+ *
+ * This supports defining the path or library name using system properties or a
+ * custom resource file. If desired, jacob can auto-detect the correct version
+ * of the DLL for 32 or 64 bit windows, as long as you have named them
+ * differently.
+ *
+ *
+ * JACOB_DLL_PATH submitted sourceforge ticket 1493647 Added 1.11
+ * The DLL name is "jacob\
+ * The clearObjects method is used to release all the COM objects created by
+ * Jacob in the current thread prior to uninitializing COM for that thread.
+ *
+ * Prior to 1.9, manual garbage collection was the only option in Jacob, but
+ * from 1.9 onward, setting the com.jacob.autogc system property allows the
+ * objects referenced by the ROT to be automatically GCed. Automatic GC may be
+ * preferable in systems with heavy event callbacks.
+ *
+ * Is [ 1116101 ] jacob-msg 0284 relevant???
+ */
+public abstract class ROT {
+ /**
+ * Manual garbage collection was the only option pre 1.9 Can staticly cache
+ * the results because only one value and we don't let it change during a
+ * run
+ */
+ protected static final boolean USE_AUTOMATIC_GARBAGE_COLLECTION = "true"
+ .equalsIgnoreCase(System.getProperty("com.jacob.autogc"));
+
+ /**
+ * If the code is ran from an applet that is called from javascript the Java
+ * Plugin does not give full permissions to the code and thus System
+ * properties cannot be accessed. They can be accessed at class
+ * initialization time.
+ *
+ * The default behavior is to include all classes in the ROT, setting a
+ * boolean here to indicate this prevents a call to System.getProperty as
+ * part of the general call flow.
+ */
+ protected static final Boolean INCLUDE_ALL_CLASSES_IN_ROT = Boolean
+ .valueOf(System.getProperty("com.jacob.includeAllClassesInROT",
+ "true"));
+
+ /**
+ * Suffix added to class name to make up property name that determines if
+ * this object should be stored in the ROT. This 1.13 "feature" makes it
+ * possible to cause VariantViaEvent objects to not be added to the ROT in
+ * event callbacks.
+ *
+ * We don't have a static for the actual property because there is a
+ * different property for each class that may make use of this feature.
+ */
+ protected static String PUT_IN_ROT_SUFFIX = ".PutInROT";
+
+ /**
+ * A hash table where each element is another HashMap that represents a
+ * thread. Each thread HashMap contains the com objects created in that
+ * thread
+ */
+ private static HashMap
+ * This method does not need to be threaded because the only concurrent
+ * modification risk is on the hash map that contains all of the thread
+ * related hash maps. The individual thread related maps are only used on a
+ * per thread basis so there isn't a locking issue.
+ *
+ * In addition, this method cannot be threaded because it calls
+ * ComThread.InitMTA. The ComThread object has some methods that call ROT so
+ * we could end up deadlocked. This method should be safe without the
+ * synchronization because the ROT works on per thread basis and the methods
+ * that add threads and remove thread related entries are all synchronized
+ *
+ *
+ * @param o
+ */
+ protected static void addObject(JacobObject o) {
+ String shouldIncludeClassInROT = "true";
+ // only call System.getProperty if we are not including all classes in
+ // the ROT. This lets us run with standard Jacob behavior in Applets
+ // without the security exception raised by System.getProperty in the
+ // flow
+ if (!ROT.INCLUDE_ALL_CLASSES_IN_ROT) {
+ shouldIncludeClassInROT = System.getProperty(o.getClass().getName()
+ + PUT_IN_ROT_SUFFIX, "true");
+ }
+ if (shouldIncludeClassInROT.equalsIgnoreCase("false")) {
+ if (JacobObject.isDebugEnabled()) {
+ JacobObject.debug("JacobObject: New instance of "
+ + o.getClass().getName() + " not added to ROT");
+ }
+ } else {
+ // first see if we have a table for this thread
+ Map
+ * You create an N-D SafeArray by: SafeArray sa = new
+ * SafeArray(Variant.VariantVariant, new int[] {0,0,0,0}, new int[]
+ * {4,4,4,4}); Where the 1st array is lower bounds and 2nd has the lengths
+ * of each dimension *
+ *
+ * @param vt
+ * @param lbounds
+ * @param celems
+ */
+ public SafeArray(int vt, int lbounds[], int celems[]) {
+ init(vt, lbounds, celems);
+ }
+
+ /**
+ * convert a string to a VT_UI1 array
+ *
+ * @param s
+ * source string
+ */
+ public SafeArray(String s) {
+ char[] ca = s.toCharArray();
+ init(Variant.VariantByte, new int[] { 0 }, new int[] { ca.length });
+ fromCharArray(ca);
+ }
+
+ /**
+ * convert a VT_UI1 array to string
+ *
+ * @return variant byte as a string
+ */
+ public String asString() {
+ if (getvt() != Variant.VariantByte) {
+ return null;
+ }
+ char ja[] = toCharArray();
+ return new String(ja);
+ }
+
+ public native Object clone();
+
+ /**
+ * now private so only this object can access. Was: call this to explicitly
+ * release the com object before gc
+ *
+ */
+ private native void destroy();
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void finalize() {
+ safeRelease();
+ }
+
+ /**
+ * populate the safe array from the passed in array of data
+ *
+ * @param ja
+ */
+ public native void fromBooleanArray(boolean ja[]);
+
+ /**
+ * populate the safe array from the passed in array of data
+ *
+ * @param ja
+ */
+ public native void fromByteArray(byte ja[]);
+
+ /**
+ * populate the safe array from the passed in array of data
+ *
+ * @param ja
+ */
+ public native void fromCharArray(char ja[]);
+
+ /**
+ * populate the safe array from the passed in array of data
+ *
+ * @param ja
+ */
+ public native void fromDoubleArray(double ja[]);
+
+ /**
+ * populate the safe array from the passed in array of data
+ *
+ * @param ja
+ */
+ public native void fromFloatArray(float ja[]);
+
+ /**
+ * populate the safe array from the passed in array of data
+ *
+ * @param ja
+ */
+ public native void fromIntArray(int ja[]);
+
+ /**
+ * populate the safe array from the passed in array of data
+ *
+ * @param ja
+ */
+ public native void fromLongArray(long ja[]);
+
+ /**
+ * populate the safe array from the passed in array of data
+ *
+ * @param ja
+ */
+ public native void fromShortArray(short ja[]);
+
+ /**
+ * populate the safe array from the passed in array of data
+ *
+ * @param ja
+ */
+ public native void fromStringArray(String ja[]);
+
+ /**
+ * populate the safe array from the passed in array of data
+ *
+ * @param ja
+ */
+ public native void fromVariantArray(Variant ja[]);
+
+ /**
+ * boolean access
+ *
+ * @param sa_idx
+ * @return boolean representation
+ */
+ public native boolean getBoolean(int sa_idx);
+
+ /**
+ * get boolean value from N-dimensional array
+ *
+ * @param indices -
+ * length must equal Dimension of SafeArray
+ * @return the value at the specified location
+ */
+ public native boolean getBoolean(int indices[]);
+
+ /**
+ * boolean access
+ *
+ * @param sa_idx1
+ * @param sa_idx2
+ * @return boolean representation
+ */
+ public native boolean getBoolean(int sa_idx1, int sa_idx2);
+
+ /**
+ * boolean access
+ *
+ * @param sa_idx
+ * @param nelems
+ * @param ja
+ * @param ja_start
+ */
+ public native void getBooleans(int sa_idx, int nelems, boolean ja[],
+ int ja_start);
+
+ /**
+ * byte access
+ *
+ * @param sa_idx
+ * @return byte representaton
+ */
+ public native byte getByte(int sa_idx);
+
+ /**
+ * get byte value from N-dimensional array
+ *
+ * @param indices -
+ * length must equal Dimension of SafeArray
+ * @return the value at the specified location
+ */
+ public native byte getByte(int indices[]);
+
+ /**
+ * byte access
+ *
+ * @param sa_idx1
+ * @param sa_idx2
+ * @return byte representation
+ */
+ public native byte getByte(int sa_idx1, int sa_idx2);
+
+ /**
+ * Fills byte array from contents of this array
+ *
+ * @param sa_idx
+ * @param nelems
+ * @param ja
+ * @param ja_start
+ */
+ public native void getBytes(int sa_idx, int nelems, byte ja[], int ja_start);
+
+ /**
+ * char access
+ *
+ * @param sa_idx
+ * @return single character rpeesentation
+ */
+ public native char getChar(int sa_idx);
+
+ /**
+ * get char value from N-dimensional array
+ *
+ * @param indices -
+ * length must equal Dimension of SafeArray
+ * @return the value at the specified location
+ */
+ public native char getChar(int indices[]);
+
+ /**
+ * char access
+ *
+ * @param sa_idx1
+ * @param sa_idx2
+ * @return single character representation
+ */
+ public native char getChar(int sa_idx1, int sa_idx2);
+
+ /**
+ * char access
+ *
+ * @param sa_idx
+ * @param nelems
+ * @param ja
+ * @param ja_start
+ */
+ public native void getChars(int sa_idx, int nelems, char ja[], int ja_start);
+
+ /**
+ * double access
+ *
+ * @param sa_idx
+ * @return double stored in array
+ */
+ public native double getDouble(int sa_idx);
+
+ /**
+ * get double value from N-dimensional array
+ *
+ * @param indices -
+ * length must equal Dimension of SafeArray
+ * @return the value at the specified location
+ */
+ public native double getDouble(int indices[]);
+
+ /**
+ * double access
+ *
+ * @param sa_idx1
+ * @param sa_idx2
+ * @return double stored in array
+ */
+ public native double getDouble(int sa_idx1, int sa_idx2);
+
+ /**
+ * double access
+ *
+ * @param sa_idx
+ * @param nelems
+ * @param ja
+ * @param ja_start
+ */
+ public native void getDoubles(int sa_idx, int nelems, double ja[],
+ int ja_start);
+
+ /**
+ * @return the size of each element?
+ */
+ public native int getElemSize();
+
+ /**
+ * @return The ??features of the array?
+ */
+ public native int getFeatures();
+
+ /**
+ * float access
+ *
+ * @param sa_idx
+ * @return float held in array at location
+ */
+ public native float getFloat(int sa_idx);
+
+ /**
+ * get float value from N-dimensional array
+ *
+ * @param indices -
+ * length must equal Dimension of SafeArray
+ * @return the value at the specified location
+ */
+ public native float getFloat(int indices[]);
+
+ /**
+ * float access
+ *
+ * @param sa_idx1
+ * @param sa_idx2
+ * @return float held in array at location
+ */
+ public native float getFloat(int sa_idx1, int sa_idx2);
+
+ /**
+ * float access
+ *
+ * @param sa_idx
+ * @param nelems
+ * @param ja
+ * @param ja_start
+ */
+ public native void getFloats(int sa_idx, int nelems, float ja[],
+ int ja_start);
+
+ /**
+ * get int from an single dimensional array
+ *
+ * @param sa_idx
+ * array index
+ * @return int stored in array
+ */
+ public native int getInt(int sa_idx);
+
+ /**
+ * get int value from N-dimensional array
+ *
+ * @param indices -
+ * length must equal Dimension of SafeArray
+ * @return the value at the specified location
+ */
+ public native int getInt(int indices[]);
+
+ /**
+ * get int from 2 dimensional array
+ *
+ * @param sa_idx1
+ * array index first dimension
+ * @param sa_idx2
+ * array index of second dimension
+ * @return int stored in array
+ */
+ public native int getInt(int sa_idx1, int sa_idx2);
+
+ /**
+ * retrieves a group of ints from a single dimensional array
+ *
+ * @param sa_idx
+ * the index in the array to start the get
+ * @param nelems
+ * number of elements to retrieve
+ * @param ja
+ * the structure to be filled with the ints
+ * @param ja_start
+ * the start point in the java int array to start filling
+ */
+ public native void getInts(int sa_idx, int nelems, int ja[], int ja_start);
+
+ /**
+ * get int from an single dimensional array
+ *
+ * @param sa_idx
+ * array index
+ * @return long stored in array
+ */
+ public native long getLong(int sa_idx);
+
+ /**
+ * get long value from N-dimensional array
+ *
+ * @param indices -
+ * length must equal Dimension of SafeArray
+ * @return the value at the specified location
+ */
+ public native long getLong(int indices[]);
+
+ /**
+ * get long from 2 dimensional array
+ *
+ * @param sa_idx1
+ * array index first dimension
+ * @param sa_idx2
+ * array index of second dimension
+ * @return long stored in array
+ */
+ public native long getLong(int sa_idx1, int sa_idx2);
+
+ /**
+ * retrieves a group of longs from a single dimensional array
+ *
+ * @param sa_idx
+ * the index in the array to start the get
+ * @param nelems
+ * number of elements to retrieve
+ * @param ja
+ * the structure to be filled with the longs
+ * @param ja_start
+ * the start point in the java longs array to start filling
+ */
+ public native void getLongs(int sa_idx, int nelems, long ja[], int ja_start);
+
+ /**
+ * @return The lower bounds of the array?
+ */
+ public native int getLBound();
+
+ /**
+ * @param dim
+ * the dimension we are checking in a multidimensional array
+ * @return The lower bounds of the array?
+ */
+ public native int getLBound(int dim);
+
+ /**
+ * @return The number of dimensions in this array
+ */
+ public native int getNumDim();
+
+ /**
+ * not implemented.
+ *
+ * @return 0
+ */
+ public int getNumLocks() {
+ return 0;
+ }
+
+ /**
+ * short access
+ *
+ * @param sa_idx
+ * @return short stored in array
+ */
+ public native short getShort(int sa_idx);
+
+ /**
+ * get short value from N-dimensional array
+ *
+ * @param indices -
+ * length must equal Dimension of SafeArray
+ * @return the value at the specified location
+ */
+ public native short getShort(int indices[]);
+
+ /**
+ * short access
+ *
+ * @param sa_idx1
+ * @param sa_idx2
+ * @return short stored in array
+ */
+ public native short getShort(int sa_idx1, int sa_idx2);
+
+ /**
+ * short access
+ *
+ * @param sa_idx
+ * @param nelems
+ * @param ja
+ * @param ja_start
+ */
+ public native void getShorts(int sa_idx, int nelems, short ja[],
+ int ja_start);
+
+ /**
+ * string access
+ *
+ * @param sa_idx
+ * @return String stored in array
+ *
+ */
+ public native String getString(int sa_idx);
+
+ /**
+ * get String value from N-dimensional array
+ *
+ * @param indices -
+ * length must equal Dimension of SafeArray
+ * @return the value at the specified location
+ */
+ public native String getString(int indices[]);
+
+ /**
+ * string access
+ *
+ * @param sa_idx1
+ * @param sa_idx2
+ * @return String stored in array
+ */
+ public native String getString(int sa_idx1, int sa_idx2);
+
+ /**
+ * string access
+ *
+ * @param sa_idx
+ * @param nelems
+ * @param ja
+ * @param ja_start
+ */
+ public native void getStrings(int sa_idx, int nelems, String ja[],
+ int ja_start);
+
+ /**
+ * @return The upper bounds of the array?
+ */
+ public native int getUBound();
+
+ /**
+ * @param dim
+ * the dimension we are checking in a multidimensional array
+ * @return The upper bounds of the array?
+ */
+ public native int getUBound(int dim);
+
+ /**
+ * variant access
+ *
+ * @param sa_idx
+ * @return Variant held in location in the array?
+ */
+ public native Variant getVariant(int sa_idx);
+
+ /**
+ * get Variant value from N-dimensional array
+ *
+ * @param indices -
+ * length must equal Dimension of SafeArray
+ * @return the value at the specified location
+ */
+ public native Variant getVariant(int indices[]);
+
+ /**
+ * variant access
+ *
+ * @param sa_idx1
+ * @param sa_idx2
+ * @return Variant held in a location in the array?
+ */
+ public native Variant getVariant(int sa_idx1, int sa_idx2);
+
+ /**
+ * variant access
+ *
+ * @param sa_idx
+ * @param nelems
+ * @param ja
+ * @param ja_start
+ */
+ public native void getVariants(int sa_idx, int nelems, Variant ja[],
+ int ja_start);
+
+ /**
+ * @return the Variant type
+ */
+ public native int getvt();
+
+ protected native void init(int vt, int lbounds[], int celems[]);
+
+ /**
+ * Does anyone want to document this?
+ *
+ * @param sa
+ */
+ public native void reinit(SafeArray sa);
+
+ /**
+ * Does anyone want to document this?
+ *
+ * @param vt
+ * the variant type?
+ */
+ public native void reinterpretType(int vt);
+
+ /**
+ * {@inheritDoc}
+ */
+ public void safeRelease() {
+ super.safeRelease();
+ if (m_pV != 0) {
+ destroy();
+ m_pV = 0;
+ } else {
+ // looks like a double release
+ if (isDebugEnabled()) {
+ debug(this.getClass().getName() + ":" + this.hashCode()
+ + " double release");
+ }
+ }
+ }
+
+ /**
+ * boolean access
+ *
+ * @param sa_idx
+ * @param c
+ */
+ public native void setBoolean(int sa_idx, boolean c);
+
+ /**
+ * set boolean value in N-dimensional array
+ *
+ * @param indices -
+ * length must equal Dimension of SafeArray
+ * @param c
+ */
+ public native void setBoolean(int indices[], boolean c);
+
+ /**
+ * boolean access
+ *
+ * @param sa_idx1
+ * @param sa_idx2
+ * @param c
+ */
+ public native void setBoolean(int sa_idx1, int sa_idx2, boolean c);
+
+ /**
+ * boolean access
+ *
+ * @param sa_idx
+ * @param nelems
+ * @param ja
+ * @param ja_start
+ */
+ public native void setBooleans(int sa_idx, int nelems, boolean ja[],
+ int ja_start);
+
+ /**
+ * byte access
+ *
+ * @param sa_idx
+ * @param c
+ */
+ public native void setByte(int sa_idx, byte c);
+
+ /**
+ * set byte value in N-dimensional array
+ *
+ * @param indices -
+ * length must equal Dimension of SafeArray
+ * @param c
+ */
+ public native void setByte(int indices[], byte c);
+
+ /**
+ * byte access
+ *
+ * @param sa_idx1
+ * @param sa_idx2
+ * @param c
+ */
+ public native void setByte(int sa_idx1, int sa_idx2, byte c);
+
+ /**
+ * fills array with passed in bytes
+ *
+ * @param sa_idx
+ * @param nelems
+ * @param ja
+ * @param ja_start
+ */
+ public native void setBytes(int sa_idx, int nelems, byte ja[], int ja_start);
+
+ /**
+ * char access
+ *
+ * @param sa_idx
+ * @param c
+ */
+ public native void setChar(int sa_idx, char c);
+
+ /**
+ * set char value in N-dimensional array
+ *
+ * @param indices -
+ * length must equal Dimension of SafeArray
+ * @param c
+ */
+ public native void setChar(int indices[], char c);
+
+ /**
+ * char access
+ *
+ * @param sa_idx1
+ * @param sa_idx2
+ * @param c
+ */
+ public native void setChar(int sa_idx1, int sa_idx2, char c);
+
+ /**
+ * char access
+ *
+ * @param sa_idx
+ * @param nelems
+ * @param ja
+ * @param ja_start
+ */
+ public native void setChars(int sa_idx, int nelems, char ja[], int ja_start);
+
+ /**
+ * double access
+ *
+ * @param sa_idx
+ * @param c
+ */
+ public native void setDouble(int sa_idx, double c);
+
+ /**
+ * set double value in N-dimensional array
+ *
+ * @param indices -
+ * length must equal Dimension of SafeArray
+ * @param c
+ */
+ public native void setDouble(int indices[], double c);
+
+ /**
+ * double access
+ *
+ * @param sa_idx1
+ * @param sa_idx2
+ * @param c
+ */
+ public native void setDouble(int sa_idx1, int sa_idx2, double c);
+
+ /**
+ * double access
+ *
+ * @param sa_idx
+ * @param nelems
+ * @param ja
+ * @param ja_start
+ */
+ public native void setDoubles(int sa_idx, int nelems, double ja[],
+ int ja_start);
+
+ /**
+ * float access
+ *
+ * @param sa_idx
+ * @param c
+ */
+ public native void setFloat(int sa_idx, float c);
+
+ /**
+ * set float value in N-dimensional array
+ *
+ * @param indices -
+ * length must equal Dimension of SafeArray
+ * @param c
+ */
+ public native void setFloat(int indices[], float c);
+
+ /**
+ * float access
+ *
+ * @param sa_idx1
+ * @param sa_idx2
+ * @param c
+ */
+ public native void setFloat(int sa_idx1, int sa_idx2, float c);
+
+ /**
+ * float access
+ *
+ * @param sa_idx
+ * @param nelems
+ * @param ja
+ * @param ja_start
+ */
+ public native void setFloats(int sa_idx, int nelems, float ja[],
+ int ja_start);
+
+ /**
+ * sets the int value of an element in a single dimensional array
+ *
+ * @param sa_idx
+ * index into the array
+ * @param c
+ * the value to be set
+ */
+ public native void setInt(int sa_idx, int c);
+
+ /**
+ * set int value in N-dimensional array
+ *
+ * @param indices -
+ * length must equal Dimension of SafeArray
+ * @param c
+ */
+ public native void setInt(int indices[], int c);
+
+ /**
+ * sets the int value of a 2 dimensional array
+ *
+ * @param sa_idx1
+ * index on the first dimension
+ * @param sa_idx2
+ * index on the second dimension
+ * @param c
+ * the value to be set
+ */
+ public native void setInt(int sa_idx1, int sa_idx2, int c);
+
+ /**
+ * sets a group of ints into a single dimensional array
+ *
+ * @param sa_idx
+ * the index of the start of the array to put into
+ * @param nelems
+ * number of elements to be copied
+ * @param ja
+ * the new int values to be put into the array
+ * @param ja_start
+ * the start index in the array that we are copying into
+ * SafeArray
+ */
+ public native void setInts(int sa_idx, int nelems, int ja[], int ja_start);
+
+ /**
+ * sets the long value of an element in a single dimensional array
+ *
+ * @param sa_idx
+ * index into the array
+ * @param c
+ * the value to be set
+ */
+ public native void setLong(int sa_idx, long c);
+
+ /**
+ * set long value in N-dimensional array
+ *
+ * @param indices -
+ * length must equal Dimension of SafeArray
+ * @param c
+ */
+ public native void setLong(int indices[], long c);
+
+ /**
+ * sets the long value of a 2 dimensional array
+ *
+ * @param sa_idx1
+ * index on the first dimension
+ * @param sa_idx2
+ * index on the second dimension
+ * @param c
+ * the value to be set
+ */
+ public native void setLong(int sa_idx1, int sa_idx2, long c);
+
+ /**
+ * sets a group of longs into a single dimensional array
+ *
+ * @param sa_idx
+ * the index of the start of the array to put into
+ * @param nelems
+ * number of elements to be copied
+ * @param ja
+ * the new long values to be put into the array
+ * @param ja_start
+ * the start index in the array that we are copying into
+ * SafeArray
+ */
+ public native void setLongs(int sa_idx, int nelems, long ja[], int ja_start);
+
+ /**
+ * short access
+ *
+ * @param sa_idx1
+ * @param sa_idx2
+ * @param c
+ */
+ public native void setShort(int sa_idx1, int sa_idx2, short c);
+
+ /**
+ * short access
+ *
+ * @param sa_idx
+ * @param c
+ */
+ public native void setShort(int sa_idx, short c);
+
+ /**
+ * set short value in N-dimensional array
+ *
+ * @param indices -
+ * length must equal Dimension of SafeArray
+ * @param c
+ */
+ public native void setShort(int indices[], short c);
+
+ /**
+ * short access
+ *
+ * @param sa_idx
+ * @param nelems
+ * @param ja
+ * @param ja_start
+ */
+ public native void setShorts(int sa_idx, int nelems, short ja[],
+ int ja_start);
+
+ /**
+ * puts a string into an element in a two dimensional array.
+ *
+ * @param sa_idx1
+ * @param sa_idx2
+ * @param c
+ */
+ public native void setString(int sa_idx1, int sa_idx2, String c);
+
+ /*
+ * ================================================================ The
+ * beginning of N-dimensional array support
+ * ================================================================
+ */
+
+ /**
+ * puts a string into an element in a single dimensional safe array
+ *
+ * @param sa_idx
+ * @param c
+ */
+ public native void setString(int sa_idx, String c);
+
+ /**
+ * set Stringvalue in N-dimensional array
+ *
+ * @param indices -
+ * length must equal Dimension of SafeArray
+ * @param c
+ */
+ public native void setString(int indices[], String c);
+
+ /**
+ * string access
+ *
+ * @param sa_idx
+ * @param nelems
+ * @param ja
+ * @param ja_start
+ */
+ public native void setStrings(int sa_idx, int nelems, String ja[],
+ int ja_start);
+
+ /**
+ * variant access
+ *
+ * @param sa_idx1
+ * @param sa_idx2
+ * @param c
+ */
+ public native void setVariant(int sa_idx1, int sa_idx2, Variant c);
+
+ /**
+ * variant access
+ *
+ * @param sa_idx
+ * @param c
+ */
+ public native void setVariant(int sa_idx, Variant c);
+
+ /**
+ * set Variant value in N-dimensional array
+ *
+ * @param indices -
+ * length must equal Dimension of SafeArray
+ * @param v
+ */
+ public native void setVariant(int indices[], Variant v);
+
+ /**
+ * variant access
+ *
+ * @param sa_idx
+ * @param nelems
+ * @param ja
+ * @param ja_start
+ */
+ public native void setVariants(int sa_idx, int nelems, Variant ja[],
+ int ja_start);
+
+ /**
+ * Retrieves the data from the array cast to a Java data type
+ *
+ * @return boolean[] array of booleans contained in this collection
+ */
+ public native boolean[] toBooleanArray();
+
+ /**
+ * Retrieves the data from the array cast to a Java data type
+ *
+ * @return byte[] byte array contained in this collection
+ */
+ public native byte[] toByteArray();
+
+ /**
+ * Retrieves the data from the array cast to a Java data type
+ *
+ * @return char[] character array contained in this collection
+ */
+ public native char[] toCharArray();
+
+ /**
+ * Retrieves the data from the array cast to a Java data type
+ *
+ * @return double[] double array contained in this collection
+ */
+ public native double[] toDoubleArray();
+
+ /**
+ * Retrieves the data from the array cast to a Java data type
+ *
+ * @return float[] array of float contained in this collection
+ */
+ public native float[] toFloatArray();
+
+ /**
+ * Retrieves the data from the array cast to a Java data type
+ *
+ * @return int[] int array contained in this collection
+ */
+ public native int[] toIntArray();
+
+ /**
+ * Retrieves the data from the array cast to a Java data type
+ *
+ * @return long[] long array contained in this collection
+ */
+ public native long[] toLongArray();
+
+ /**
+ * Retrieves the data from the array cast to a Java data type
+ *
+ * @return short[] short array contained in this collection
+ */
+ public native short[] toShortArray();
+
+ /**
+ * Standard toString() Warning, this creates new Variant objects!
+ *
+ * @return String contents of variant
+ */
+ public String toString() {
+ String s = "";
+ int ndim = getNumDim();
+ if (ndim == 1) {
+ int ldim = getLBound();
+ int udim = getUBound();
+ for (int i = ldim; i <= udim; i++) {
+ Variant v = getVariant(i);
+
+ if (((v.getvt() & Variant.VariantTypeMask) | Variant.VariantArray) == v
+ .getvt()) {
+ return s + "[" + v.toSafeArray().toString() + "]";
+ } else {
+ s += " " + v.toString();
+ }
+ }
+ } else if (ndim == 2) {
+ int ldim1 = getLBound(1);
+ int udim1 = getUBound(1);
+
+ int ldim2 = getLBound(2);
+ int udim2 = getUBound(2);
+
+ for (int i = ldim1; i <= udim1; i++) {
+ for (int j = ldim2; j <= udim2; j++) {
+ Variant v = getVariant(i, j);
+ s += " " + v.toString();
+ }
+ s += "\n";
+ }
+ }
+ return s;
+ }
+
+ /**
+ * Retrieves the data from the array cast to a Java data type
+ *
+ * @return String[] String array contained in this collection
+ */
+ public native String[] toStringArray();
+
+ /**
+ * Retrieves the data from the array cast to a Java data type
+ *
+ * @return Variant[] array of variants contained in this collection
+ */
+ public native Variant[] toVariantArray();
+
+}
\ No newline at end of file
diff --git a/vendor/jacob/1.15-M4/java/com/jacob/com/Variant.java b/vendor/jacob/1.15-M4/java/com/jacob/com/Variant.java
new file mode 100644
index 0000000..91ae210
--- /dev/null
+++ b/vendor/jacob/1.15-M4/java/com/jacob/com/Variant.java
@@ -0,0 +1,2235 @@
+/*
+ * Copyright (c) 1999-2004 Sourceforge JACOB Project.
+ * All rights reserved. Originator: Dan Adler (http://danadler.com).
+ * Get more information about JACOB at http://sourceforge.net/projects/jacob-project
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package com.jacob.com;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Date;
+
+/**
+ * The multi-format data type used for all call backs and most communications
+ * between Java and COM. It provides a single class that can handle all data
+ * types.
+ *
+ * Just loading this class creates 3 variants that get added to the ROT
+ *
+ * PROPVARIANT introduces new types so eventually Variant will need to be
+ * upgraded to support PropVariant types.
+ * http://blogs.msdn.com/benkaras/archive/2006/09/13/749962.aspx
+ *
+ * This object no longer implements Serializable because serialization is broken
+ * (and has been since 2000/xp). The underlying marshalling/unmarshalling code
+ * is broken in the JNI layer.
+ */
+public class Variant extends JacobObject {
+
+ /**
+ * Use this constant for optional parameters
+ */
+ public final static com.jacob.com.Variant DEFAULT;
+
+ /**
+ * Same than {@link #DEFAULT}
+ */
+ public final static com.jacob.com.Variant VT_MISSING;
+
+ /**
+ * Use for true/false variant parameters
+ */
+ public final static com.jacob.com.Variant VT_TRUE = new com.jacob.com.Variant(
+ true);
+
+ /**
+ * Use for true/false variant parameters
+ */
+ public final static com.jacob.com.Variant VT_FALSE = new com.jacob.com.Variant(
+ false);
+
+ /** variant's type is empty : equivalent to VB Nothing and VT_EMPTY */
+ public static final short VariantEmpty = 0;
+
+ /** variant's type is null : equivalent to VB Null and VT_NULL */
+ public static final short VariantNull = 1;
+
+ /** variant's type is short VT_I2 */
+ public static final short VariantShort = 2;
+
+ /** variant's type is int VT_I4, a Long in VC */
+ public static final short VariantInt = 3;
+
+ /** variant's type is float VT_R4 */
+ public static final short VariantFloat = 4;
+
+ /** variant's type is double VT_R8 */
+ public static final short VariantDouble = 5;
+
+ /** variant's type is currency VT_CY */
+ public static final short VariantCurrency = 6;
+
+ /** variant's type is date VT_DATE */
+ public static final short VariantDate = 7;
+
+ /** variant's type is string also known as VT_BSTR */
+ public static final short VariantString = 8;
+
+ /** variant's type is dispatch VT_DISPATCH */
+ public static final short VariantDispatch = 9;
+
+ /** variant's type is error VT_ERROR */
+ public static final short VariantError = 10;
+
+ /** variant's type is boolean VT_BOOL */
+ public static final short VariantBoolean = 11;
+
+ /** variant's type is variant it encapsulate another variant VT_VARIANT */
+ public static final short VariantVariant = 12;
+
+ /** variant's type is object VT_UNKNOWN */
+ public static final short VariantObject = 13;
+
+ /** variant's type is object VT_DECIMAL */
+ public static final short VariantDecimal = 14;
+
+ // VT_I1 = 16
+
+ /** variant's type is byte VT_UI1 */
+ public static final short VariantByte = 17;
+
+ // VT_UI2 = 18
+ // VT_UI4 = 19
+
+ /**
+ * variant's type is 64 bit long integer VT_I8 - not yet implemented in
+ * Jacob because we have to decide what to do with Currency and because its
+ * only supported on XP and later. No win2k, NT or 2003 server.
+ */
+ public static final short VariantLongInt = 20;
+
+ // VT_UI8 = 21
+ // VT_INT = 22
+ // VT_UNIT = 23
+ // VT_VOID = 24
+ // VT_HRESULT = 25
+
+ /**
+ * This value is for reference only and is not to be used by any callers
+ */
+ public static final short VariantPointer = 26;
+
+ // VT_SAFEARRAY = 27
+ // VT_CARRARY = 28
+ // VT_USERDEFINED = 29
+
+ /** what is this? VT_TYPEMASK && VT_BSTR_BLOB 0xfff */
+ public static final short VariantTypeMask = 4095;
+
+ /** variant's type is array VT_ARRAY 0x2000 */
+ public static final short VariantArray = 8192;
+
+ /** variant's type is a reference (to IDispatch?) VT_BYREF 0x4000 */
+ public static final short VariantByref = 16384;
+
+ /*
+ * Do the run time definition of DEFAULT and MISSING. Have to use static
+ * block because of the way the initialization is done via two calls instead
+ * of just a constructor for this type.
+ */
+ static {
+ com.jacob.com.Variant vtMissing = new com.jacob.com.Variant();
+ vtMissing.putVariantNoParam();
+ DEFAULT = vtMissing;
+ VT_MISSING = vtMissing;
+ }
+
+ /**
+ * Pointer to MS struct.
+ */
+ int m_pVariant = 0;
+
+ /**
+ * public constructor, initializes and sets type to VariantEmpty
+ */
+ public Variant() {
+ this(null, false);
+ }
+
+ /**
+ * Constructor that accepts a primitive rather than an object
+ *
+ * @param in
+ */
+ public Variant(boolean in) {
+ this(new Boolean(in));
+ }
+
+ /**
+ * Constructor that accepts a primitive rather than an object
+ *
+ * @param in
+ */
+ public Variant(byte in) {
+ this(new Byte(in));
+ }
+
+ /**
+ * Constructor that accepts a primitive rather than an object
+ *
+ * @param in
+ */
+ public Variant(double in) {
+ this(new Double(in));
+ }
+
+ /**
+ * Constructor that accepts a primitive rather than an object
+ *
+ * @param in
+ */
+ public Variant(float in) {
+ this(new Float(in));
+ }
+
+ /**
+ * Constructor that accepts a primitive rather than an object
+ *
+ * @param in
+ */
+ public Variant(int in) {
+ this(new Integer(in));
+ };
+
+ /**
+ * Constructor that accepts a primitive rather than an object
+ *
+ * @param in
+ */
+ public Variant(long in) {
+ this(new Long(in));
+ }
+
+ /**
+ * Convenience constructor that calls the main one with a byRef value of
+ * false
+ *
+ * @param in
+ * object to be made into variant
+ */
+ public Variant(Object in) {
+ this(in, false);
+ }
+
+ /**
+ * Constructor that accepts the data object and information about whether
+ * this is by reference or not. It calls the JavaVariantConverter to
+ * actually push the data into the newly created Variant.
+ *
+ * @param pValueObject
+ * The value object that will pushed down into windows memory. A
+ * null object sets this to "empty"
+ * @param fByRef
+ */
+ public Variant(Object pValueObject, boolean fByRef) {
+ init();
+ VariantUtilities.populateVariant(this, pValueObject, fByRef);
+ }
+
+ /**
+ * Constructor that accepts a primitive rather than an object
+ *
+ * @param in
+ */
+ public Variant(short in) {
+ this(new Short(in));
+ }
+
+ /**
+ * Cover for native method so we can cover it.
+ *
+ * This cannot convert an object to a byRef. It can convert from byref to
+ * not byref
+ *
+ * @param in
+ * type to convert this variant too
+ * @return Variant returns this same object so folks can change when
+ * replacing calls toXXX() with changeType().getXXX()
+ */
+ public Variant changeType(short in) {
+ changeVariantType(in);
+ return this;
+ }
+
+ /**
+ * Converts variant to the passed in type by converting the underlying
+ * windows variant structure. private so folks use public java method
+ *
+ * @param in
+ * the desired resulting type
+ */
+ private native void changeVariantType(short in);
+
+ /**
+ * this returns null
+ *
+ * @return ?? comment says null?
+ */
+ @Override
+ public native Object clone();
+
+ /**
+ * @deprecated No longer used
+ * @return null !
+ */
+ @Deprecated
+ public native Variant cloneIndirect();
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#finalize()
+ */
+ @Override
+ protected void finalize() {
+ safeRelease();
+ }
+
+ /**
+ *
+ * @return returns the value as a boolean, throws an exception if its not.
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public boolean getBoolean() {
+ if (this.getvt() == VariantBoolean) {
+ return getVariantBoolean();
+ } else {
+ throw new IllegalStateException(
+ "getBoolean() only legal on Variants of type VariantBoolean, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ * public cover for native method
+ *
+ * @return the boolean from a booleanRef
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public boolean getBooleanRef() {
+ if ((this.getvt() & VariantTypeMask) == VariantBoolean
+ && (this.getvt() & VariantByref) == VariantByref) {
+ return getVariantBooleanRef();
+ } else {
+ throw new IllegalStateException(
+ "getBooleanRef() only legal on byRef Variants of type VariantBoolean, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ *
+ * @return returns the value as a boolean, throws an exception if its not.
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public byte getByte() {
+ if (this.getvt() == VariantByte) {
+ return getVariantByte();
+ } else {
+ throw new IllegalStateException(
+ "getByte() only legal on Variants of type VariantByte, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ * public cover for native method
+ *
+ * @return the byte from a booleanRef
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public byte getByteRef() {
+ if ((this.getvt() & VariantTypeMask) == VariantByte
+ && (this.getvt() & VariantByref) == VariantByref) {
+ return getVariantByteRef();
+ } else {
+ throw new IllegalStateException(
+ "getByteRef() only legal on byRef Variants of type VariantByte, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ * MS Currency objects are 64 bit fixed point numbers with 15 digits to the
+ * left and 4 to the right of the decimal place.
+ *
+ * @return returns the currency value as a long, throws exception if not a
+ * currency type..
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public Currency getCurrency() {
+ if (this.getvt() == VariantCurrency) {
+ return new Currency(getVariantCurrency());
+ } else {
+ throw new IllegalStateException(
+ "getCurrency() only legal on Variants of type VariantCurrency, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ * MS Currency objects are 64 bit fixed point numbers with 15 digits to the
+ * left and 4 to the right of the decimal place.
+ *
+ * @return returns the currency value as a long, throws exception if not a
+ * currency type
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public Currency getCurrencyRef() {
+ if ((this.getvt() & VariantTypeMask) == VariantCurrency
+ && (this.getvt() & VariantByref) == VariantByref) {
+ return new Currency(getVariantCurrencyRef());
+ } else {
+ throw new IllegalStateException(
+ "getCurrencyRef() only legal on byRef Variants of type VariantCurrency, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ * @return double return the date (as a double) value held in this variant
+ * (fails on other types?)
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public double getDate() {
+ if (this.getvt() == VariantDate) {
+ return getVariantDate();
+ } else {
+ throw new IllegalStateException(
+ "getDate() only legal on Variants of type VariantDate, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ *
+ * @return returns the date value as a double, throws exception if not a
+ * date type
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public double getDateRef() {
+ if ((this.getvt() & VariantTypeMask) == VariantDate
+ && (this.getvt() & VariantByref) == VariantByref) {
+ return getVariantDateRef();
+ } else {
+ throw new IllegalStateException(
+ "getDateRef() only legal on byRef Variants of type VariantDate, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ * return the BigDecimal value held in this variant (fails on other types)
+ *
+ * @return BigDecimal
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public BigDecimal getDecimal() {
+ if (this.getvt() == VariantDecimal) {
+ return (BigDecimal) (getVariantDec());
+ } else {
+ throw new IllegalStateException(
+ "getDecimal() only legal on Variants of type VariantDecimal, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ * return the BigDecimal value held in this variant (fails on other types)
+ *
+ * @return BigDecimal
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public BigDecimal getDecimalRef() {
+ if ((this.getvt() & VariantTypeMask) == VariantDecimal
+ && (this.getvt() & VariantByref) == VariantByref) {
+ return (BigDecimal) (getVariantDecRef());
+ } else {
+ throw new IllegalStateException(
+ "getDecimalRef() only legal on byRef Variants of type VariantDecimal, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ * cover for {@link #toDispatch()} This method now matches other getXXX()
+ * methods. It throws an IllegalStateException if the object is not of type
+ * VariantDispatch
+ *
+ * @return this object as a dispatch
+ * @throws IllegalStateException
+ * if wrong variant type
+ */
+ public Dispatch getDispatch() {
+ if (this.getvt() == VariantDispatch) {
+ return toDispatch();
+ } else {
+ throw new IllegalStateException(
+ "getDispatch() only legal on Variants of type VariantDispatch, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ * Dispatch and dispatchRef are treated the same This is just a cover for
+ * toDispatch() with a flag check
+ *
+ * @return the results of toDispatch()
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public Dispatch getDispatchRef() {
+ if ((this.getvt() & VariantTypeMask) == VariantDispatch
+ && (this.getvt() & VariantByref) == VariantByref) {
+ return toDispatch();
+ } else {
+ throw new IllegalStateException(
+ "getDispatchRef() only legal on byRef Variants of type VariantDispatch, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ * @return double return the double value held in this variant (fails on
+ * other types?)
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public double getDouble() {
+ if (this.getvt() == VariantDouble) {
+ return getVariantDouble();
+ } else {
+ throw new IllegalStateException(
+ "getDouble() only legal on Variants of type VariantDouble, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ *
+ * @return returns the double value, throws exception if not a Double type
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public double getDoubleRef() {
+ if ((this.getvt() & VariantTypeMask) == VariantDouble
+ && (this.getvt() & VariantByref) == VariantByref) {
+ return getVariantDoubleRef();
+ } else {
+ throw new IllegalStateException(
+ "getDoubleRef() only legal on byRef Variants of type VariantDouble, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ * Pointless method that was put here so that putEmpty() has a get method.
+ * This would have returned null if the value was VT_EMPTY or if it wasn't
+ * so it would have always returned the same value.
+ *
+ * @deprecated method never did anything
+ */
+ @Deprecated
+ public void getEmpty() {
+ }
+
+ /**
+ * @return double return the error value held in this variant (fails on
+ * other types?)
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public int getError() {
+ if (this.getvt() == VariantError) {
+ return getVariantError();
+ } else {
+ throw new IllegalStateException(
+ "getError() only legal on Variants of type VariantError, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ *
+ * @return returns the error value as an int, throws exception if not a
+ * Error type
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public int getErrorRef() {
+ if ((this.getvt() & VariantTypeMask) == VariantError
+ && (this.getvt() & VariantByref) == VariantByref) {
+ return getVariantErrorRef();
+ } else {
+ throw new IllegalStateException(
+ "getErrorRef() only legal on byRef Variants of type VariantError, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ * @return returns the value as a float if the type is of type float
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public float getFloat() {
+ if (this.getvt() == VariantFloat) {
+ return getVariantFloat();
+ } else {
+ throw new IllegalStateException(
+ "getFloat() only legal on Variants of type VariantFloat, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ *
+ * @return returns the float value, throws exception if not a Float type
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public float getFloatRef() {
+ if ((this.getvt() & VariantTypeMask) == VariantFloat
+ && (this.getvt() & VariantByref) == VariantByref) {
+ return getVariantFloatRef();
+ } else {
+ throw new IllegalStateException(
+ "getFloatRef() only legal on byRef Variants of type VariantFloat, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ * return the int value held in this variant if it is an int or a short.
+ * Throws for other types.
+ *
+ * @return int contents of the windows memory
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public int getInt() {
+ if (this.getvt() == VariantInt) {
+ return getVariantInt();
+ } else if (this.getvt() == VariantShort) {
+ return getVariantShort();
+ } else {
+ throw new IllegalStateException(
+ "getInt() only legal on Variants of type VariantInt, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ * get the content of this variant as an int
+ *
+ * @return int
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public int getIntRef() {
+ if ((this.getvt() & VariantTypeMask) == VariantInt
+ && (this.getvt() & VariantByref) == VariantByref) {
+ return getVariantIntRef();
+ } else {
+ throw new IllegalStateException(
+ "getIntRef() only legal on byRef Variants of type VariantInt, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ * returns the windows time contained in this Variant to a Java Date. should
+ * return null if this is not a date Variant SF 959382
+ *
+ * @return java.util.Date returns the date if this is a VariantDate != 0,
+ * null if it is a VariantDate == 0 and throws an
+ * IllegalStateException if this isn't a date.
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public Date getJavaDate() {
+ Date returnDate = null;
+ if (getvt() == VariantDate) {
+ double windowsDate = getDate();
+ if (windowsDate != 0) {
+ returnDate = DateUtilities.convertWindowsTimeToDate(getDate());
+ }
+ } else {
+ throw new IllegalStateException(
+ "getJavaDate() only legal on Variants of type VariantDate, not "
+ + this.getvt());
+ }
+ return returnDate;
+ }
+
+ /**
+ * returns the windows time contained in this Variant to a Java Date should
+ * return null if this is not a date reference Variant SF 959382
+ *
+ * @return java.util.Date
+ */
+ public Date getJavaDateRef() {
+ double windowsDate = getDateRef();
+ if (windowsDate == 0) {
+ return null;
+ } else {
+ return DateUtilities.convertWindowsTimeToDate(windowsDate);
+ }
+ }
+
+ /**
+ * 64 bit Longs only available on x64. 64 bit long support added 1.14
+ *
+ * @return returns the value as a long, throws exception if not a Long
+ * type..
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public long getLong() {
+ if (this.getvt() == VariantLongInt) {
+ return getVariantLong();
+ } else {
+ throw new IllegalStateException(
+ "getLong() only legal on Variants of type VariantLongInt, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ * 64 bit Longs only available on x64. 64 bit long support added 1.14
+ *
+ * @return returns the value as a long, throws exception if not a long type
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public long getLongRef() {
+ if ((this.getvt() & VariantTypeMask) == VariantLongInt
+ && (this.getvt() & VariantByref) == VariantByref) {
+ return getVariantLongRef();
+ } else {
+ throw new IllegalStateException(
+ "getLongRef() only legal on byRef Variants of type VariantLongInt, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ * This method would have returned null if the type was VT_NULL. But because
+ * we return null if the data is not of the right type, this method should
+ * have always returned null
+ *
+ * @deprecated method never did anything
+ */
+ @Deprecated
+ public void getNull() {
+ }
+
+ /**
+ * return the int value held in this variant (fails on other types?)
+ *
+ * @return int
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public short getShort() {
+ if (this.getvt() == VariantShort) {
+ return getVariantShort();
+ } else {
+ throw new IllegalStateException(
+ "getShort() only legal on Variants of type VariantShort, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ * get the content of this variant as an int
+ *
+ * @return int
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public short getShortRef() {
+ if ((this.getvt() & VariantTypeMask) == VariantShort
+ && (this.getvt() & VariantByref) == VariantByref) {
+ return getVariantShortRef();
+ } else {
+ throw new IllegalStateException(
+ "getShortRef() only legal on byRef Variants of type VariantShort, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ *
+ * @return string contents of the variant.
+ * @throws IllegalStateException
+ * if this variant is not of type String
+ */
+ public String getString() {
+ if (getvt() == Variant.VariantString) {
+ return getVariantString();
+ } else {
+ throw new IllegalStateException(
+ "getString() only legal on Variants of type VariantString, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ * gets the content of the variant as a string ref
+ *
+ * @return String retrieved from the COM area.
+ * @throws IllegalStateException
+ * if variant is not of the requested type
+ */
+ public String getStringRef() {
+ if ((this.getvt() & VariantTypeMask) == VariantString
+ && (this.getvt() & VariantByref) == VariantByref) {
+ return getVariantStringRef();
+ } else {
+ throw new IllegalStateException(
+ "getStringRef() only legal on byRef Variants of type VariantString, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ * Used to get the value from a windows type of VT_VARIANT or a jacob
+ * Variant type of VariantVariant. Added 1.12 pre 6 - VT_VARIANT support is
+ * at an alpha level
+ *
+ * @return Object a java Object that represents the content of the enclosed
+ * Variant
+ */
+ public Object getVariant() {
+ if ((this.getvt() & VariantTypeMask) == VariantVariant
+ && (this.getvt() & VariantByref) == VariantByref) {
+ if (JacobObject.isDebugEnabled()) {
+ JacobObject.debug("About to call getVariantVariant()");
+ }
+ Variant enclosedVariant = new Variant();
+ int enclosedVariantMemory = getVariantVariant();
+ enclosedVariant.m_pVariant = enclosedVariantMemory;
+ Object enclosedVariantAsJava = enclosedVariant.toJavaObject();
+ // zero out the reference to the underlying windows memory so that
+ // it is still only owned in one place by one java object
+ // (this object of type VariantVariant)
+ // enclosedVariant.putEmpty(); // don't know if this would have had
+ // side effects
+ if (JacobObject.isDebugEnabled()) {
+ JacobObject
+ .debug("Zeroing out enclosed Variant's ref to windows memory");
+ }
+ enclosedVariant.m_pVariant = 0;
+ return enclosedVariantAsJava;
+ } else {
+ throw new IllegalStateException(
+ "getVariant() only legal on Variants of type VariantVariant, not "
+ + this.getvt());
+ }
+ }
+
+ /**
+ * @deprecated superseded by SafeArray
+ * @return never returns anything
+ * @throws com.jacob.com.NotImplementedException
+ */
+ @Deprecated
+ public Variant[] getVariantArray() {
+ throw new NotImplementedException("Not implemented");
+ }
+
+ /**
+ * @return the Variant Array that represents the data in the Variant
+ * @deprecated superseded by SafeArray
+ * @throws com.jacob.com.NotImplementedException
+ */
+ @Deprecated
+ public Variant[] getVariantArrayRef() {
+ throw new NotImplementedException("Not implemented");
+ }
+
+ /**
+ *
+ * @return the value in this Variant as a boolean, null if not a boolean
+ */
+ private native boolean getVariantBoolean();
+
+ private native boolean getVariantBooleanRef();
+
+ /**
+ * @return the value in this Variant as a byte, null if not a byte
+ */
+ private native byte getVariantByte();
+
+ /**
+ * @return the value in this Variant as a byte, null if not a byte
+ */
+ private native byte getVariantByteRef();
+
+ /**
+ * @return the value in this Variant as a long, null if not a long
+ */
+ private native long getVariantCurrency();
+
+ /**
+ * @return the value in this Variant as a long, null if not a long
+ */
+ private native long getVariantCurrencyRef();
+
+ /**
+ * @return double return the date (as a double) value held in this variant
+ * (fails on other types?)
+ */
+ private native double getVariantDate();
+
+ /**
+ * get the content of this variant as a double representing a date
+ *
+ * @return double
+ */
+ private native double getVariantDateRef();
+
+ /**
+ * @return the value in this Variant as a decimal, null if not a decimal
+ */
+ private native Object getVariantDec();
+
+ /**
+ * @return the value in this Variant (byref) as a decimal, null if not a
+ * decimal
+ */
+ private native Object getVariantDecRef();
+
+ /**
+ * @return double get the content of this variant as a double
+ */
+ private native double getVariantDouble();
+
+ /**
+ * @return double get the content of this variant as a double
+ */
+ private native double getVariantDoubleRef();
+
+ private native int getVariantError();
+
+ private native int getVariantErrorRef();
+
+ /**
+ * @return returns the value as a float if the type is of type float
+ */
+ private native float getVariantFloat();
+
+ /**
+ * @return returns the value as a float if the type is of type float
+ */
+ private native float getVariantFloatRef();
+
+ /**
+ * @return the int value held in this variant (fails on other types?)
+ */
+ private native int getVariantInt();
+
+ /**
+ * @return the int value held in this variant (fails on other types?)
+ */
+ private native int getVariantIntRef();
+
+ /**
+ * @return the value in this Variant as a long, null if not a long
+ */
+ private native long getVariantLong();
+
+ /**
+ * @return the value in this Variant as a long, null if not a long
+ */
+ private native long getVariantLongRef();
+
+ /**
+ * get the content of this variant as a short
+ *
+ * @return short
+ */
+ private native short getVariantShort();
+
+ /**
+ * @return short the content of this variant as a short
+ */
+ private native short getVariantShortRef();
+
+ /**
+ * Native method that actually extracts a string value from the variant
+ *
+ * @return
+ */
+ private native String getVariantString();
+
+ /**
+ * @return String the content of this variant as a string
+ */
+ private native String getVariantStringRef();
+
+ /**
+ * Returns the variant type via a native method call
+ *
+ * @return short one of the VT_xx types
+ */
+ private native short getVariantType();
+
+ /**
+ * Returns the variant type via a native method call. Added 1.12 pre 6 -
+ * VT_VARIANT support is at an alpha level
+ *
+ * @return Variant one of the VT_Variant types
+ */
+ private native int getVariantVariant();
+
+ /**
+ * Reports the type of the underlying Variant object
+ *
+ * @return returns the variant type as a short, one of the Variantxxx values
+ * defined as statics in this class. returns VariantNull if not
+ * initialized
+ * @throws IllegalStateException
+ * if there is no underlying windows data structure
+ */
+ public short getvt() {
+ if (m_pVariant != 0) {
+ return getVariantType();
+ } else {
+ throw new IllegalStateException("uninitialized Variant");
+ }
+ }
+
+ /**
+ * initializes the COM Variant and puts its reference in this instance
+ */
+ protected native void init();
+
+ /**
+ *
+ * @return returns true if the variant is considered null
+ * @throws IllegalStateException
+ * if there is no underlying windows memory
+ */
+ public boolean isNull() {
+ getvt();
+ return isVariantConsideredNull();
+ }
+
+ /**
+ * is the variant null or empty or error or null dispatch
+ *
+ * @return true if it is null or false if not
+ */
+ private native boolean isVariantConsideredNull();
+
+ /**
+ * sets the type to VT_ERROR and the error message to DISP_E_PARAMNOTFOIUND
+ *
+ * @deprecated replaced by putNoParam()
+ */
+ @Deprecated
+ public void noParam() {
+ putNoParam();
+ }
+
+ /**
+ * returns true if the passed in Variant is a constant that should not be
+ * freed
+ *
+ * @param pVariant
+ * @return boolean that is true if Variant is a type of constant, VT_FALSE,
+ * VT_TRUE, VT_MISSING, DEFAULT
+ */
+ protected boolean objectIsAConstant(Variant pVariant) {
+ if (pVariant == VT_FALSE || pVariant == VT_TRUE
+ || pVariant == VT_MISSING || pVariant == DEFAULT) {
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+
+ /**
+ * puts a boolean into the variant and sets it's type
+ *
+ * @param in
+ * the new value
+ */
+ public void putBoolean(boolean in) {
+ // verify we aren't released yet
+ getvt();
+ putVariantBoolean(in);
+ }
+
+ /**
+ * pushes a boolean into the variant by ref and sets the type of the variant
+ * to boolean
+ *
+ * @param in
+ */
+ public void putBooleanRef(boolean in) {
+ // verify we aren't released yet
+ getvt();
+ putVariantBooleanRef(in);
+ }
+
+ /**
+ * pushes a byte into the varaint and sets the type
+ *
+ * @param in
+ */
+ public void putByte(byte in) {
+ // verify we aren't released yet
+ getvt();
+ putVariantByte(in);
+ };
+
+ /**
+ * @deprecated superseded by SafeArray
+ * @param in
+ * doesn't matter because this method does nothing
+ * @throws com.jacob.com.NotImplementedException
+ */
+ @Deprecated
+ public void putByteArray(Object in) {
+ throw new NotImplementedException("Not implemented");
+ }
+
+ /**
+ * pushes a byte into the variant by ref and sets the type
+ *
+ * @param in
+ */
+ public void putByteRef(byte in) {
+ // verify we aren't released yet
+ getvt();
+ putVariantByteRef(in);
+ }
+
+ /**
+ * @param in
+ * the object that would be wrapped by the Variant if this method
+ * was implemented
+ * @deprecated superseded by SafeArray
+ * @throws com.jacob.com.NotImplementedException
+ */
+ @Deprecated
+ public void putCharArray(Object in) {
+ throw new NotImplementedException("Not implemented");
+ }
+
+ /**
+ * Puts a value in as a currency and sets the variant type. MS Currency
+ * objects are 64 bit fixed point numbers with 15 digits to the left and 4
+ * to the right of the decimal place.
+ *
+ * @param in
+ * the long that will be put into the 64 bit currency object.
+ */
+ public void putCurrency(Currency in) {
+ // verify we aren't released yet
+ getvt();
+ putVariantCurrency(in.longValue());
+ }
+
+ /**
+ * Pushes a long into the variant as currency and sets the type. MS Currency
+ * objects are 64 bit fixed point numbers with 15 digits to the left and 4
+ * to the right of the decimal place.
+ *
+ * @param in
+ * the long that will be put into the 64 bit currency object
+ */
+ public void putCurrencyRef(Currency in) {
+ // verify we aren't released yet
+ getvt();
+ putVariantCurrencyRef(in.longValue());
+ }
+
+ /**
+ * converts a java date to a windows time and calls putDate(double) SF
+ * 959382
+ *
+ * @param inDate
+ * a Java date to be converted
+ * @throws IllegalArgumentException
+ * if inDate = null
+ */
+ public void putDate(Date inDate) {
+ if (inDate == null) {
+ throw new IllegalArgumentException(
+ "Cannot put null in as windows date");
+ // do nothing
+ } else {
+ putDate(DateUtilities.convertDateToWindowsTime(inDate));
+ }
+ }
+
+ /**
+ * puts a windows date double into the variant and sets the type
+ *
+ * @param in
+ */
+ public void putDate(double in) {
+ // verify we aren't released yet
+ getvt();
+ putVariantDate(in);
+ }
+
+ /**
+ * converts a java date to a windows time and calls putDateRef(double) SF
+ * 959382
+ *
+ * @param inDate
+ * a Java date to be converted
+ * @throws IllegalArgumentException
+ * if inDate = null
+ */
+ public void putDateRef(Date inDate) {
+ if (inDate == null) {
+ throw new IllegalArgumentException(
+ "Cannot put null in as windows date");
+ // do nothing
+ } else {
+ putDateRef(DateUtilities.convertDateToWindowsTime(inDate));
+ }
+ }
+
+ /**
+ * set the content of this variant to a date (VT_DATE|VT_BYREF)
+ *
+ * @param in
+ */
+ public void putDateRef(double in) {
+ // verify we aren't released
+ getvt();
+ putVariantDateRef(in);
+ }
+
+ /**
+ * This actual does all the validating and massaging of the BigDecimalValues
+ * when converting them to MS Decimal types
+ *
+ * @param in
+ * number to be made into VT_DECIMAL
+ * @param byRef
+ * store by reference or not
+ * @param roundingBehavior
+ * one of the BigDecimal ROUND_xxx methods. Any method other than
+ * ROUND_UNECESSARY means that the value will be rounded to fit
+ */
+ private void putDecimal(BigDecimal in, boolean byRef) {
+ // verify we aren't released
+ getvt();
+ // first validate the min and max
+ VariantUtilities.validateDecimalMinMax(in);
+ BigInteger allWordBigInt;
+ allWordBigInt = in.unscaledValue();
+ // Assume any required rounding has been done.
+ VariantUtilities.validateDecimalScaleAndBits(in);
+ // finally we can do what we actually came here to do
+ int sign = in.signum();
+ // VT_DECIMAL always has positive value with just the sign
+ // flipped
+ if (in.signum() < 0) {
+ in = in.negate();
+ }
+ // ugh, reusing allWordBigInt but now should always be positive
+ // and any round is applied
+ allWordBigInt = in.unscaledValue();
+ byte scale = (byte) in.scale();
+ int lowWord = allWordBigInt.intValue();
+ BigInteger middleWordBigInt = allWordBigInt.shiftRight(32);
+ int middleWord = middleWordBigInt.intValue();
+ BigInteger highWordBigInt = allWordBigInt.shiftRight(64);
+ int highWord = highWordBigInt.intValue();
+ if (byRef) {
+ putVariantDecRef(sign, scale, lowWord, middleWord, highWord);
+ } else {
+ putVariantDec(sign, scale, lowWord, middleWord, highWord);
+ }
+ }
+
+ /**
+ * EXPERIMENTAL 1.14 feature to support rounded decimals.
+ *
+ * Set the value of this variant and set the type. This may throw exceptions
+ * more often than the caller expects because most callers don't manage the
+ * scale of their BigDecimal objects.
+ *
+ * This default set method throws exceptions if precision or size is out of
+ * bounds
+ *
+ * There are 12 bytes available for the integer number.
+ *
+ * There is 1 byte for the scale.
+ *
+ * @param in
+ * the BigDecimal that will be converted to VT_DECIMAL
+ * @throws IllegalArgumentException
+ * if the scale is > 28, the maximum for VT_DECIMAL or if there
+ * are more than 12 bytes worth the digits
+ */
+ public void putDecimal(BigDecimal in) {
+ putDecimal(in, false);
+ }
+
+ /**
+ * Set the value of this variant and set the type. This may throw exceptions
+ * more often than the caller expects because most callers don't manage the
+ * scale of their BigDecimal objects.
+ *
+ * This default set method throws exceptions if precision or size is out of
+ * bounds
+ *
+ * There are 12 bytes available for the integer number.
+ *
+ * There is 1 byte for the scale.
+ *
+ * @param in
+ * the BigDecimal that will be converted to VT_DECIMAL
+ * @throws IllegalArgumentException
+ * if the scale is > 28, the maximum for VT_DECIMAL or if there
+ * are more than 12 bytes worth the digits
+ */
+ public void putDecimalRef(BigDecimal in) {
+ putDecimal(in, true);
+ }
+
+ /**
+ * This acts a cover for putVariant Dispatch.
+ *
+ * @param in
+ * the Dispatch we're putting down in the COM variant space.
+ */
+ public void putDispatch(Dispatch in) {
+ putVariantDispatch(in);
+ }
+
+ /**
+ * Dispatch and dispatchRef are treated the same This is a cover for
+ * putVariantDispatch(). putDispatch and putDispatchRef are treated the same
+ * because no one has written the COM code for putDispatchRef.
+ *
+ * @param in
+ * the Dispatch we're putting down in the COM variant space.
+ */
+ public void putDispatchRef(Dispatch in) {
+ putVariantDispatch(in);
+ }
+
+ /**
+ * wraps this Variant around the passed in double.
+ *
+ * @param in
+ */
+ public void putDouble(double in) {
+ // verify we aren't released yet
+ getvt();
+ putVariantDouble(in);
+ }
+
+ /**
+ * set the content of this variant to a double (VT_R8|VT_BYREF)
+ *
+ * @param in
+ */
+ public void putDoubleRef(double in) {
+ // verify we aren't released
+ getvt();
+ putVariantDoubleRef(in);
+ }
+
+ /**
+ * sets the type to VariantEmpty
+ *
+ */
+ public void putEmpty() {
+ // verify we aren't released yet
+ getvt();
+ putVariantEmpty();
+ }
+
+ /**
+ * puts an error code (I think) into the variant and sets the type
+ *
+ * @param in
+ */
+ public void putError(int in) {
+ // verify we aren't released yet
+ getvt();
+ putVariantError(in);
+ }
+
+ /**
+ * pushes an error code into the variant by ref and sets the type
+ *
+ * @param in
+ */
+ public void putErrorRef(int in) {
+ // verify we aren't released yet
+ getvt();
+ putVariantErrorRef(in);
+ }
+
+ /**
+ * fills the Variant with a float and sets the type to float
+ *
+ * @param in
+ */
+ public void putFloat(float in) {
+ // verify we haven't been released yet
+ getvt();
+ putVariantFloat(in);
+ }
+
+ /**
+ * pushes a float into the variant and sets the type
+ *
+ * @param in
+ */
+ public void putFloatRef(float in) {
+ // verify we aren't released yet
+ getvt();
+ putVariantFloatRef(in);
+ }
+
+ /**
+ * set the value of this variant and set the type
+ *
+ * @param in
+ */
+ public void putInt(int in) {
+ // verify we aren't released yet
+ getvt();
+ putVariantInt(in);
+ }
+
+ /**
+ * set the content of this variant to an int (VT_I4|VT_BYREF)
+ *
+ * @param in
+ */
+ public void putIntRef(int in) {
+ // verify we aren't released
+ getvt();
+ putVariantIntRef(in);
+ }
+
+ /**
+ * Puts a 64 bit Java Long into a 64 bit Variant Long. Only works on x64
+ * systems otherwise throws an error. 64 bit long support added 1.14
+ *
+ * @param in
+ * the long that will be put into the 64 bit Long object.
+ */
+ public void putLong(long in) {
+ // verify we aren't released yet
+ getvt();
+ putVariantLong(in);
+ }
+
+ /**
+ * Puts a 64 bit Java Long into a 64 bit Variant Long. Only works on x64
+ * systems otherwise throws an error. 64 bit long support added 1.14
+ *
+ * @param in
+ * the long that will be put into the 64 bit Long object.
+ */
+ public void putLongRef(long in) {
+ // verify we aren't released yet
+ getvt();
+ putVariantLongRef(in);
+ }
+
+ /**
+ * sets the type to VT_ERROR and the error message to DISP_E_PARAMNOTFOIUND
+ */
+ public void putNoParam() {
+ // verify we aren't released yet
+ getvt();
+ putVariantNoParam();
+ }
+
+ /**
+ * Sets the type to VariantDispatch and sets the value to null Equivalent to
+ * VB's nothing
+ */
+ public void putNothing() {
+ // verify we aren't released yet
+ getvt();
+ putVariantNothing();
+ }
+
+ /**
+ * Set this Variant's type to VT_NULL (the VB equivalent of NULL)
+ */
+ public void putNull() {
+ // verify we aren't released yet
+ getvt();
+ putVariantNull();
+ }
+
+ /**
+ * Puts an object into the Variant -- converts to Dispatch. Acts as a cover
+ * for putVariantDispatch(); This primarily exists to support jacobgen. This
+ * should be deprecated.
+ *
+ * @param in
+ * the object we are putting into the Variant, assumes a
+ * @see Variant#putDispatch(Dispatch)
+ * @deprecated should use putDispatch()
+ */
+ @Deprecated
+ public void putObject(Object in) {
+ // this should verify in instanceof Dispatch
+ putVariantDispatch(in);
+ }
+
+ /**
+ * Just a cover for putObject(). We shouldn't accept any old random object.
+ * This has been left in to support jacobgen. This should be deprecated.
+ *
+ * @param in
+ * @deprecated
+ */
+ @Deprecated
+ public void putObjectRef(Object in) {
+ putObject(in);
+ }
+
+ /**
+ * have no idea...
+ *
+ * @param in
+ */
+ public void putSafeArray(SafeArray in) {
+ // verify we haven't been released yet
+ getvt();
+ putVariantSafeArray(in);
+ }
+
+ /**
+ * have no idea...
+ *
+ * @param in
+ */
+ public void putSafeArrayRef(SafeArray in) {
+ // verify we haven't been released yet
+ getvt();
+ putVariantSafeArrayRef(in);
+ }
+
+ /**
+ * set the content of this variant to a short (VT_I2)
+ *
+ * @param in
+ */
+ public void putShort(short in) {
+ // verify we aren't released
+ getvt();
+ putVariantShort(in);
+ }
+
+ /**
+ * set the content of this variant to a short (VT_I2|VT_BYREF)
+ *
+ * @param in
+ */
+ public void putShortRef(short in) {
+ // verify we aren't released
+ getvt();
+ putVariantShortRef(in);
+ }
+
+ /**
+ * put a string into the variant and set its type
+ *
+ * @param in
+ */
+ public void putString(String in) {
+ // verify we aren't released yet
+ getvt();
+ putVariantString(in);
+ }
+
+ /**
+ * set the content of this variant to a string (VT_BSTR|VT_BYREF)
+ *
+ * @param in
+ */
+ public void putStringRef(String in) {
+ // verify we aren't released
+ getvt();
+ putVariantStringRef(in);
+ }
+
+ /**
+ * Puts a variant into this variant making it type VT_VARIANT. Added 1.12
+ * pre 6
+ *
+ * @param objectToBeWrapped
+ * A object that is to be referenced by this variant. If
+ * objectToBeWrapped is already of type Variant, then it is used.
+ * If objectToBeWrapped is not Variant then
+ *
+ *
+ * @see com.jacob.com.JacobObject#safeRelease()
+ */
+ @Override
+ public void safeRelease() {
+ // The well known constants should not be released.
+ // Unfortunately this doesn't fix any other classes that are
+ // keeping constants around in their static ivars.
+ // those will still be busted.
+ //
+ // The only inconsistency here is that we leak
+ // when this class is unloaded because we won't
+ // free the memory even if the constants are being
+ // finalized. this is not a big deal at all.
+ // another way around this would be to create the constants
+ // in their own thread so that they would never be released
+ if (!objectIsAConstant(this)) {
+ super.safeRelease();
+ if (m_pVariant != 0) {
+ release();
+ m_pVariant = 0;
+ } else {
+ // looks like a double release
+ // this should almost always happen due to gc
+ // after someone has called ComThread.Release
+ if (isDebugEnabled()) {
+ debug("Variant: " + this.hashCode() + " double release");
+ // Throwable x = new Throwable();
+ // x.printStackTrace();
+ }
+ }
+ } else {
+ if (isDebugEnabled()) {
+ debug("Variant: " + this.hashCode()
+ + " don't want to release a constant");
+ }
+ }
+ }
+
+ /**
+ * this is supposed to cause the underlying variant object struct to be
+ * rebuilt from a previously serialized byte array.
+ *
+ * @param ba
+ */
+ protected native void SerializationReadFromBytes(byte[] ba);
+
+ /**
+ * this is supposed to create a byte array that represents the underlying
+ * variant object structure
+ */
+ protected native byte[] SerializationWriteToBytes();
+
+ /**
+ * @deprecated should be replaced by changeType() followed by getBoolean()
+ * @return the value of this variant as boolean (after possible conversion)
+ */
+ @Deprecated
+ public boolean toBoolean() {
+ changeType(Variant.VariantBoolean);
+ return getBoolean();
+ }
+
+ /**
+ * attempts to return the content of this variant as a double (after
+ * possible conversion)
+ *
+ * @deprecated should be replaced by changeType() followed by getByte()
+ * @return byte
+ */
+ @Deprecated
+ public byte toByte() {
+ changeType(Variant.VariantByte);
+ return getByte();
+ }
+
+ /**
+ * @deprecated superseded by SafeArray
+ * @return nothing because this method is not implemented
+ * @throws com.jacob.com.NotImplementedException
+ */
+ @Deprecated
+ public Object toByteArray() {
+ throw new NotImplementedException("Not implemented");
+ }
+
+ /**
+ * @deprecated superseded by SafeArray
+ * @return never returns anything
+ * @throws com.jacob.com.NotImplementedException
+ */
+ @Deprecated
+ public Object toCharArray() {
+ throw new NotImplementedException("Not implemented");
+ }
+
+ /**
+ * @deprecated should be replaced by changeType() followed by getCurrency
+ * @return the content of this variant as a long representing a monetary
+ * amount
+ */
+ @Deprecated
+ public Currency toCurrency() {
+ changeType(Variant.VariantCurrency);
+ return getCurrency();
+ }
+
+ /**
+ * @deprecated should use changeType() followed by getDate()
+ * @return the value of this variant as a date (after possible conversion)
+ */
+ @Deprecated
+ public double toDate() {
+ changeType(VariantDate);
+ return getDate();
+ }
+
+ /**
+ * @return the content of this variant as a Dispatch object (after possible
+ * conversion)
+ */
+ public Dispatch toDispatch() {
+ // now make the native call
+ return toVariantDispatch();
+ }
+
+ /**
+ * @deprecated should call changeType() then getDouble()
+ * @return the content of this variant as a double (after possible
+ * conversion)
+ */
+ @Deprecated
+ public double toDouble() {
+ changeType(Variant.VariantDouble);
+ return getDouble();
+ }
+
+ /** @return the value of this variant as an enumeration (java style) */
+ public native EnumVariant toEnumVariant();
+
+ /**
+ * converts to an error type and returns the error
+ *
+ * @deprecated should use changeType() followed by getError()
+ * @return the error as an int (after conversion)
+ */
+ @Deprecated
+ public int toError() {
+ changeType(Variant.VariantError);
+ return getError();
+ }
+
+ /**
+ * attempts to return the contents of this variant as a float (after
+ * possible conversion)
+ *
+ * @deprecated should use changeType() and getFloat() instead
+ * @return float
+ */
+ @Deprecated
+ public float toFloat() {
+ changeType(Variant.VariantFloat);
+ return getFloat();
+ }
+
+ /**
+ * @deprecated should use changeType() followed by getInt()
+ * @return the value of this variant as an int (after possible conversion)
+ */
+ @Deprecated
+ public int toInt() {
+ changeType(VariantInt);
+ return getInt();
+ }
+
+ /**
+ * Returns the windows time contained in this Variant as a Java Date
+ * converts to a date like many of the other toXXX() methods SF 959382.
+ *
+ * This method added 12/2005 for possible use by jacobgen instead of its
+ * conversion code
+ *
+ * This does not convert the data
+ *
+ * @deprecated callers should use getDate()
+ * @return java.util.Date version of this variant if it is a date, otherwise
+ * null
+ *
+ */
+ @Deprecated
+ public Date toJavaDate() {
+ changeType(Variant.VariantDate);
+ return getJavaDate();
+ }
+
+ /**
+ * Convert a JACOB Variant value to a Java object (type conversions).
+ * provided in Sourceforge feature request 959381. See
+ * JavaVariantConverter..convertVariantTJavaObject(Variant) for more
+ * information.
+ *
+ * @return Corresponding Java object of the type matching the Variant type.
+ * @throws IllegalStateException
+ * if no underlying windows data structure
+ * @throws NotImplementedException
+ * if unsupported conversion is requested
+ * @throws JacobException
+ * if the calculated result was a JacobObject usually as a
+ * result of error
+ */
+ public Object toJavaObject() throws JacobException {
+ return VariantUtilities.variantToObject(this);
+ }
+
+ /**
+ * Acts a a cover for toDispatch. This primarily exists to support jacobgen.
+ *
+ * @deprecated this is a cover for toDispatch();
+ * @return Object returned by toDispatch()
+ * @see Variant#toDispatch() instead
+ */
+ @Deprecated
+ public Object toObject() {
+ return toDispatch();
+ }
+
+ /**
+ * By default toSafeArray makes a deep copy due to the fact that this
+ * Variant owns the embedded SafeArray and will destroy it when it gc's
+ * calls toSafeArray(true).
+ *
+ * @return the object converted to a SafeArray
+ */
+ public SafeArray toSafeArray() {
+ // verify we haven't been released yet
+ getvt();
+ return toSafeArray(true);
+ }
+
+ /**
+ * This lets folk turn into a safe array without a deep copy. Should this
+ * API be public?
+ *
+ * @param deepCopy
+ * @return SafeArray constructed
+ */
+ public SafeArray toSafeArray(boolean deepCopy) {
+ // verify we haven't been released yet
+ getvt();
+ return toVariantSafeArray(deepCopy);
+ }
+
+ /**
+ * I don't know what this is. Is it some legacy (pre 1.8) thing?
+ *
+ * @deprecated
+ * @return this object as a dispatch object by calling toDispatch()
+ */
+ @Deprecated
+ public Object toScriptObject() {
+ return toDispatch();
+ }
+
+ /**
+ * attempts to return the contents of this Variant as a short (after
+ * possible conversion)
+ *
+ * @deprecated callers should use changeType() followed by getShort()
+ * @return short
+ */
+ @Deprecated
+ public short toShort() {
+ this.changeType(Variant.VariantShort);
+ return getShort();
+ }
+
+ /**
+ * This method now correctly implements java toString() semantics Attempts
+ * to return the content of this variant as a string
+ *
+ * Unlike other toXXX() methods, it does not do a type conversion except for
+ * special data types (it shouldn't do any!)
+ *
+ * Converts Variant.VariantArray types to SafeArrays
+ *
+ * @return Corresponding Java object of the type matching the Variant type.
+ * @throws IllegalStateException
+ * if no underlying windows data structure
+ * @throws NotImplementedException
+ * if unsupported conversion is requested
+ * @throws JacobException
+ * if the calculated result was a JacobObject usually as a
+ * result of error
+ */
+ protected static Object variantToObject(Variant sourceData) {
+ Object result = null;
+
+ short type = sourceData.getvt(); // variant type
+
+ if ((type & Variant.VariantArray) == Variant.VariantArray) { // array
+ // returned?
+ SafeArray array = null;
+ type = (short) (type - Variant.VariantArray);
+ // From SF Bug 1840487
+ // This did call toSafeArray(false) but that meant
+ // this was the only variantToObject() that didn't have its own
+ // copy of the data so you would end up with weird run time
+ // errors after some GC. So now we just get stupid about it and
+ // always make a copy just like toSafeArray() does.
+ array = sourceData.toSafeArray();
+ result = array;
+ } else { // non-array object returned
+ switch (type) {
+ case Variant.VariantEmpty: // 0
+ case Variant.VariantNull: // 1
+ break;
+ case Variant.VariantShort: // 2
+ result = new Short(sourceData.getShort());
+ break;
+ case Variant.VariantShort | Variant.VariantByref: // 2
+ result = new Short(sourceData.getShortRef());
+ break;
+ case Variant.VariantInt: // 3
+ result = new Integer(sourceData.getInt());
+ break;
+ case Variant.VariantInt | Variant.VariantByref: // 3
+ result = new Integer(sourceData.getIntRef());
+ break;
+ case Variant.VariantFloat: // 4
+ result = new Float(sourceData.getFloat());
+ break;
+ case Variant.VariantFloat | Variant.VariantByref: // 4
+ result = new Float(sourceData.getFloatRef());
+ break;
+ case Variant.VariantDouble: // 5
+ result = new Double(sourceData.getDouble());
+ break;
+ case Variant.VariantDouble | Variant.VariantByref: // 5
+ result = new Double(sourceData.getDoubleRef());
+ break;
+ case Variant.VariantCurrency: // 6
+ result = sourceData.getCurrency();
+ break;
+ case Variant.VariantCurrency | Variant.VariantByref: // 6
+ result = sourceData.getCurrencyRef();
+ break;
+ case Variant.VariantDate: // 7
+ result = sourceData.getJavaDate();
+ break;
+ case Variant.VariantDate | Variant.VariantByref: // 7
+ result = sourceData.getJavaDateRef();
+ break;
+ case Variant.VariantString: // 8
+ result = sourceData.getString();
+ break;
+ case Variant.VariantString | Variant.VariantByref: // 8
+ result = sourceData.getStringRef();
+ break;
+ case Variant.VariantDispatch: // 9
+ result = sourceData.getDispatch();
+ break;
+ case Variant.VariantDispatch | Variant.VariantByref: // 9
+ result = sourceData.getDispatchRef(); // Can dispatches even
+ // be byRef?
+ break;
+ case Variant.VariantError: // 10
+ result = new NotImplementedException(
+ "toJavaObject() Not implemented for VariantError");
+ break;
+ case Variant.VariantBoolean: // 11
+ result = new Boolean(sourceData.getBoolean());
+ break;
+ case Variant.VariantBoolean | Variant.VariantByref: // 11
+ result = new Boolean(sourceData.getBooleanRef());
+ break;
+ case Variant.VariantVariant: // 12 they are always by ref
+ result = new NotImplementedException(
+ "toJavaObject() Not implemented for VariantVariant without ByRef");
+ break;
+ case Variant.VariantVariant | Variant.VariantByref: // 12
+ result = sourceData.getVariant();
+ break;
+ case Variant.VariantObject: // 13
+ result = new NotImplementedException(
+ "toJavaObject() Not implemented for VariantObject");
+ break;
+ case Variant.VariantDecimal: // 14
+ result = sourceData.getDecimal();
+ break;
+ case Variant.VariantDecimal | Variant.VariantByref: // 14
+ result = sourceData.getDecimalRef();
+ break;
+ case Variant.VariantByte: // 17
+ result = new Byte(sourceData.getByte());
+ break;
+ case Variant.VariantByte | Variant.VariantByref: // 17
+ result = new Byte(sourceData.getByteRef());
+ break;
+ case Variant.VariantLongInt: // 20
+ result = new Long(sourceData.getLong());
+ break;
+ case Variant.VariantLongInt | Variant.VariantByref: // 20
+ result = new Long(sourceData.getLongRef());
+ break;
+ case Variant.VariantTypeMask: // 4095
+ result = new NotImplementedException(
+ "toJavaObject() Not implemented for VariantBstrBlob/VariantTypeMask");
+ break;
+ case Variant.VariantArray: // 8192
+ result = new NotImplementedException(
+ "toJavaObject() Not implemented for VariantArray");
+ break;
+ case Variant.VariantByref: // 16384
+ result = new NotImplementedException(
+ "toJavaObject() Not implemented for VariantByref");
+ break;
+ default:
+ result = new NotImplementedException("Unknown return type: "
+ + type);
+ // there was a "return result" here that caused defect 1602118
+ // so it was removed
+ break;
+ }// switch (type)
+
+ if (result instanceof JacobException) {
+ throw (JacobException) result;
+ }
+ }
+
+ return result;
+ }// toJava()
+
+ /**
+ * Verifies that we have a scale 0 <= x <= 28 and now more than 96 bits of
+ * data. The roundToMSDecimal method will attempt to adjust a BigDecimal to
+ * pass this set of tests
+ *
+ * @param in
+ * @throws IllegalArgumentException
+ * if out of bounds
+ */
+ protected static void validateDecimalScaleAndBits(BigDecimal in) {
+ BigInteger allWordBigInt = in.unscaledValue();
+ if (in.scale() > 28) {
+ // should this cast to a string and call putStringRef()?
+ throw new IllegalArgumentException(
+ "VT_DECIMAL only supports a maximum scale of 28 and the passed"
+ + " in value has a scale of " + in.scale());
+ } else if (in.scale() < 0) {
+ // should this cast to a string and call putStringRef()?
+ throw new IllegalArgumentException(
+ "VT_DECIMAL only supports a minimum scale of 0 and the passed"
+ + " in value has a scale of " + in.scale());
+ } else if (allWordBigInt.bitLength() > 12 * 8) {
+ throw new IllegalArgumentException(
+ "VT_DECIMAL supports a maximum of "
+ + 12
+ * 8
+ + " bits not counting scale and the number passed in has "
+ + allWordBigInt.bitLength());
+
+ } else {
+ // no bounds problem to be handled
+ }
+
+ }
+
+ /**
+ * Largest possible number with scale set to 0
+ */
+ private static final BigDecimal LARGEST_DECIMAL = new BigDecimal(
+ new BigInteger("ffffffffffffffffffffffff", 16));
+ /**
+ * Smallest possible number with scale set to 0. MS doesn't support negative
+ * scales like BigDecimal.
+ */
+ private static final BigDecimal SMALLEST_DECIMAL = new BigDecimal(
+ new BigInteger("ffffffffffffffffffffffff", 16).negate());
+
+ /**
+ * Does any validation that couldn't have been fixed by rounding or scale
+ * modification.
+ *
+ * @param in
+ * The BigDecimal to be validated
+ * @throws IllegalArgumentException
+ * if the number is too large or too small or null
+ */
+ protected static void validateDecimalMinMax(BigDecimal in) {
+ if (in == null) {
+ throw new IllegalArgumentException(
+ "null is not a supported Decimal value.");
+ } else if (LARGEST_DECIMAL.compareTo(in) < 0) {
+ throw new IllegalArgumentException(
+ "Value too large for VT_DECIMAL data type:" + in.toString()
+ + " integer: " + in.toBigInteger().toString(16)
+ + " scale: " + in.scale());
+ } else if (SMALLEST_DECIMAL.compareTo(in) > 0) {
+ throw new IllegalArgumentException(
+ "Value too small for VT_DECIMAL data type:" + in.toString()
+ + " integer: " + in.toBigInteger().toString(16)
+ + " scale: " + in.scale());
+ }
+
+ }
+
+ /**
+ * Rounds the scale and bit length so that it will pass
+ * validateDecimalScaleBits(). Developers should call this method if they
+ * really want MS Decimal and don't want to lose precision.
+ *
+ * Changing the scale on a number that can fit in an MS Decimal can change
+ * the number's representation enough that it will round to a number too
+ * large to be represented by an MS VT_DECIMAL
+ *
+ * @param sourceDecimal
+ * @return BigDecimal a new big decimal that was rounded to fit in an MS
+ * VT_DECIMAL
+ */
+ public static BigDecimal roundToMSDecimal(BigDecimal sourceDecimal) {
+ BigInteger sourceDecimalIntComponent = sourceDecimal.unscaledValue();
+ BigDecimal destinationDecimal = new BigDecimal(
+ sourceDecimalIntComponent, sourceDecimal.scale());
+ int roundingModel = BigDecimal.ROUND_HALF_UP;
+ validateDecimalMinMax(destinationDecimal);
+ // First limit the number of digits and then the precision.
+ // Try and round to 29 digits because we can sometimes do that
+ BigInteger allWordBigInt;
+ allWordBigInt = destinationDecimal.unscaledValue();
+ if (allWordBigInt.bitLength() > 96) {
+ destinationDecimal = destinationDecimal.round(new MathContext(29));
+ // see if 29 digits uses more than 96 bits
+ if (allWordBigInt.bitLength() > 96) {
+ // Dang. It was over 97 bits so shorten it one more digit to
+ // stay <= 96 bits
+ destinationDecimal = destinationDecimal.round(new MathContext(
+ 28));
+ }
+ }
+ // the bit manipulations above may change the scale so do it afterwards
+ // round the scale to the max MS can support
+ if (destinationDecimal.scale() > 28) {
+ destinationDecimal = destinationDecimal.setScale(28, roundingModel);
+ }
+ if (destinationDecimal.scale() < 0) {
+ destinationDecimal = destinationDecimal.setScale(0, roundingModel);
+ }
+ return destinationDecimal;
+ }
+}
diff --git a/vendor/jacob/1.15-M4/java/com/jacob/com/VariantViaEvent.java b/vendor/jacob/1.15-M4/java/com/jacob/com/VariantViaEvent.java
new file mode 100644
index 0000000..649d2bc
--- /dev/null
+++ b/vendor/jacob/1.15-M4/java/com/jacob/com/VariantViaEvent.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 1999-2004 Sourceforge JACOB Project.
+ * All rights reserved. Originator: Dan Adler (http://danadler.com).
+ * Get more information about JACOB at http://sourceforge.net/projects/jacob-project
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package com.jacob.com;
+
+/**
+ * a public class to variant that is used to track which variant objects are
+ * created by event callbacks This is solely used for that purpose.
+ */
+public class VariantViaEvent extends Variant {
+
+ /**
+ * Standard constructor used by JNI event handling layer
+ */
+ public VariantViaEvent() {
+ super();
+ }
+}
diff --git a/vendor/jacob/1.15-M4/java/com/jacob/com/WrongThreadException.java b/vendor/jacob/1.15-M4/java/com/jacob/com/WrongThreadException.java
new file mode 100644
index 0000000..938e40c
--- /dev/null
+++ b/vendor/jacob/1.15-M4/java/com/jacob/com/WrongThreadException.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1999-2004 Sourceforge JACOB Project.
+ * All rights reserved. Originator: Dan Adler (http://danadler.com).
+ * Get more information about JACOB at http://sourceforge.net/projects/jacob-project
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package com.jacob.com;
+
+/**
+ * thrown in util.cpp
+ */
+public class WrongThreadException extends JacobException {
+ /**
+ * identifier generated by Eclipse
+ */
+ private static final long serialVersionUID = 6308780364980228692L;
+
+ /**
+ * standard 0 arg constructor with no message
+ *
+ */
+ public WrongThreadException() {
+ super("No Message Provided.");
+ }
+
+ /**
+ * standard constructor with a string message
+ *
+ * @param s
+ */
+ public WrongThreadException(String s) {
+ super(s);
+ }
+}
\ No newline at end of file
diff --git a/vendor/jdk/1.6.0_23/include/classfile_constants.h b/vendor/jdk/1.6.0_23/include/classfile_constants.h
new file mode 100644
index 0000000..30e839e
--- /dev/null
+++ b/vendor/jdk/1.6.0_23/include/classfile_constants.h
@@ -0,0 +1,523 @@
+/*
+ * %W% %E%
+ *
+ * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ *
+ */
+
+#ifndef CLASSFILE_CONSTANTS_H
+#define CLASSFILE_CONSTANTS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Flags */
+
+enum {
+ JVM_ACC_PUBLIC = 0x0001,
+ JVM_ACC_PRIVATE = 0x0002,
+ JVM_ACC_PROTECTED = 0x0004,
+ JVM_ACC_STATIC = 0x0008,
+ JVM_ACC_FINAL = 0x0010,
+ JVM_ACC_SYNCHRONIZED = 0x0020,
+ JVM_ACC_SUPER = 0x0020,
+ JVM_ACC_VOLATILE = 0x0040,
+ JVM_ACC_BRIDGE = 0x0040,
+ JVM_ACC_TRANSIENT = 0x0080,
+ JVM_ACC_VARARGS = 0x0080,
+ JVM_ACC_NATIVE = 0x0100,
+ JVM_ACC_INTERFACE = 0x0200,
+ JVM_ACC_ABSTRACT = 0x0400,
+ JVM_ACC_STRICT = 0x0800,
+ JVM_ACC_SYNTHETIC = 0x1000,
+ JVM_ACC_ANNOTATION = 0x2000,
+ JVM_ACC_ENUM = 0x4000
+};
+
+/* Used in newarray instruction. */
+
+enum {
+ JVM_T_BOOLEAN = 4,
+ JVM_T_CHAR = 5,
+ JVM_T_FLOAT = 6,
+ JVM_T_DOUBLE = 7,
+ JVM_T_BYTE = 8,
+ JVM_T_SHORT = 9,
+ JVM_T_INT = 10,
+ JVM_T_LONG = 11
+};
+
+/* Constant Pool Entries */
+
+enum {
+ JVM_CONSTANT_Utf8 = 1,
+ JVM_CONSTANT_Unicode = 2, /* unused */
+ JVM_CONSTANT_Integer = 3,
+ JVM_CONSTANT_Float = 4,
+ JVM_CONSTANT_Long = 5,
+ JVM_CONSTANT_Double = 6,
+ JVM_CONSTANT_Class = 7,
+ JVM_CONSTANT_String = 8,
+ JVM_CONSTANT_Fieldref = 9,
+ JVM_CONSTANT_Methodref = 10,
+ JVM_CONSTANT_InterfaceMethodref = 11,
+ JVM_CONSTANT_NameAndType = 12
+};
+
+/* StackMapTable type item numbers */
+
+enum {
+ JVM_ITEM_Top = 0,
+ JVM_ITEM_Integer = 1,
+ JVM_ITEM_Float = 2,
+ JVM_ITEM_Double = 3,
+ JVM_ITEM_Long = 4,
+ JVM_ITEM_Null = 5,
+ JVM_ITEM_UninitializedThis = 6,
+ JVM_ITEM_Object = 7,
+ JVM_ITEM_Uninitialized = 8
+};
+
+/* Type signatures */
+
+enum {
+ JVM_SIGNATURE_ARRAY = '[',
+ JVM_SIGNATURE_BYTE = 'B',
+ JVM_SIGNATURE_CHAR = 'C',
+ JVM_SIGNATURE_CLASS = 'L',
+ JVM_SIGNATURE_ENDCLASS = ';',
+ JVM_SIGNATURE_ENUM = 'E',
+ JVM_SIGNATURE_FLOAT = 'F',
+ JVM_SIGNATURE_DOUBLE = 'D',
+ JVM_SIGNATURE_FUNC = '(',
+ JVM_SIGNATURE_ENDFUNC = ')',
+ JVM_SIGNATURE_INT = 'I',
+ JVM_SIGNATURE_LONG = 'J',
+ JVM_SIGNATURE_SHORT = 'S',
+ JVM_SIGNATURE_VOID = 'V',
+ JVM_SIGNATURE_BOOLEAN = 'Z'
+};
+
+/* Opcodes */
+
+enum {
+ JVM_OPC_nop = 0,
+ JVM_OPC_aconst_null = 1,
+ JVM_OPC_iconst_m1 = 2,
+ JVM_OPC_iconst_0 = 3,
+ JVM_OPC_iconst_1 = 4,
+ JVM_OPC_iconst_2 = 5,
+ JVM_OPC_iconst_3 = 6,
+ JVM_OPC_iconst_4 = 7,
+ JVM_OPC_iconst_5 = 8,
+ JVM_OPC_lconst_0 = 9,
+ JVM_OPC_lconst_1 = 10,
+ JVM_OPC_fconst_0 = 11,
+ JVM_OPC_fconst_1 = 12,
+ JVM_OPC_fconst_2 = 13,
+ JVM_OPC_dconst_0 = 14,
+ JVM_OPC_dconst_1 = 15,
+ JVM_OPC_bipush = 16,
+ JVM_OPC_sipush = 17,
+ JVM_OPC_ldc = 18,
+ JVM_OPC_ldc_w = 19,
+ JVM_OPC_ldc2_w = 20,
+ JVM_OPC_iload = 21,
+ JVM_OPC_lload = 22,
+ JVM_OPC_fload = 23,
+ JVM_OPC_dload = 24,
+ JVM_OPC_aload = 25,
+ JVM_OPC_iload_0 = 26,
+ JVM_OPC_iload_1 = 27,
+ JVM_OPC_iload_2 = 28,
+ JVM_OPC_iload_3 = 29,
+ JVM_OPC_lload_0 = 30,
+ JVM_OPC_lload_1 = 31,
+ JVM_OPC_lload_2 = 32,
+ JVM_OPC_lload_3 = 33,
+ JVM_OPC_fload_0 = 34,
+ JVM_OPC_fload_1 = 35,
+ JVM_OPC_fload_2 = 36,
+ JVM_OPC_fload_3 = 37,
+ JVM_OPC_dload_0 = 38,
+ JVM_OPC_dload_1 = 39,
+ JVM_OPC_dload_2 = 40,
+ JVM_OPC_dload_3 = 41,
+ JVM_OPC_aload_0 = 42,
+ JVM_OPC_aload_1 = 43,
+ JVM_OPC_aload_2 = 44,
+ JVM_OPC_aload_3 = 45,
+ JVM_OPC_iaload = 46,
+ JVM_OPC_laload = 47,
+ JVM_OPC_faload = 48,
+ JVM_OPC_daload = 49,
+ JVM_OPC_aaload = 50,
+ JVM_OPC_baload = 51,
+ JVM_OPC_caload = 52,
+ JVM_OPC_saload = 53,
+ JVM_OPC_istore = 54,
+ JVM_OPC_lstore = 55,
+ JVM_OPC_fstore = 56,
+ JVM_OPC_dstore = 57,
+ JVM_OPC_astore = 58,
+ JVM_OPC_istore_0 = 59,
+ JVM_OPC_istore_1 = 60,
+ JVM_OPC_istore_2 = 61,
+ JVM_OPC_istore_3 = 62,
+ JVM_OPC_lstore_0 = 63,
+ JVM_OPC_lstore_1 = 64,
+ JVM_OPC_lstore_2 = 65,
+ JVM_OPC_lstore_3 = 66,
+ JVM_OPC_fstore_0 = 67,
+ JVM_OPC_fstore_1 = 68,
+ JVM_OPC_fstore_2 = 69,
+ JVM_OPC_fstore_3 = 70,
+ JVM_OPC_dstore_0 = 71,
+ JVM_OPC_dstore_1 = 72,
+ JVM_OPC_dstore_2 = 73,
+ JVM_OPC_dstore_3 = 74,
+ JVM_OPC_astore_0 = 75,
+ JVM_OPC_astore_1 = 76,
+ JVM_OPC_astore_2 = 77,
+ JVM_OPC_astore_3 = 78,
+ JVM_OPC_iastore = 79,
+ JVM_OPC_lastore = 80,
+ JVM_OPC_fastore = 81,
+ JVM_OPC_dastore = 82,
+ JVM_OPC_aastore = 83,
+ JVM_OPC_bastore = 84,
+ JVM_OPC_castore = 85,
+ JVM_OPC_sastore = 86,
+ JVM_OPC_pop = 87,
+ JVM_OPC_pop2 = 88,
+ JVM_OPC_dup = 89,
+ JVM_OPC_dup_x1 = 90,
+ JVM_OPC_dup_x2 = 91,
+ JVM_OPC_dup2 = 92,
+ JVM_OPC_dup2_x1 = 93,
+ JVM_OPC_dup2_x2 = 94,
+ JVM_OPC_swap = 95,
+ JVM_OPC_iadd = 96,
+ JVM_OPC_ladd = 97,
+ JVM_OPC_fadd = 98,
+ JVM_OPC_dadd = 99,
+ JVM_OPC_isub = 100,
+ JVM_OPC_lsub = 101,
+ JVM_OPC_fsub = 102,
+ JVM_OPC_dsub = 103,
+ JVM_OPC_imul = 104,
+ JVM_OPC_lmul = 105,
+ JVM_OPC_fmul = 106,
+ JVM_OPC_dmul = 107,
+ JVM_OPC_idiv = 108,
+ JVM_OPC_ldiv = 109,
+ JVM_OPC_fdiv = 110,
+ JVM_OPC_ddiv = 111,
+ JVM_OPC_irem = 112,
+ JVM_OPC_lrem = 113,
+ JVM_OPC_frem = 114,
+ JVM_OPC_drem = 115,
+ JVM_OPC_ineg = 116,
+ JVM_OPC_lneg = 117,
+ JVM_OPC_fneg = 118,
+ JVM_OPC_dneg = 119,
+ JVM_OPC_ishl = 120,
+ JVM_OPC_lshl = 121,
+ JVM_OPC_ishr = 122,
+ JVM_OPC_lshr = 123,
+ JVM_OPC_iushr = 124,
+ JVM_OPC_lushr = 125,
+ JVM_OPC_iand = 126,
+ JVM_OPC_land = 127,
+ JVM_OPC_ior = 128,
+ JVM_OPC_lor = 129,
+ JVM_OPC_ixor = 130,
+ JVM_OPC_lxor = 131,
+ JVM_OPC_iinc = 132,
+ JVM_OPC_i2l = 133,
+ JVM_OPC_i2f = 134,
+ JVM_OPC_i2d = 135,
+ JVM_OPC_l2i = 136,
+ JVM_OPC_l2f = 137,
+ JVM_OPC_l2d = 138,
+ JVM_OPC_f2i = 139,
+ JVM_OPC_f2l = 140,
+ JVM_OPC_f2d = 141,
+ JVM_OPC_d2i = 142,
+ JVM_OPC_d2l = 143,
+ JVM_OPC_d2f = 144,
+ JVM_OPC_i2b = 145,
+ JVM_OPC_i2c = 146,
+ JVM_OPC_i2s = 147,
+ JVM_OPC_lcmp = 148,
+ JVM_OPC_fcmpl = 149,
+ JVM_OPC_fcmpg = 150,
+ JVM_OPC_dcmpl = 151,
+ JVM_OPC_dcmpg = 152,
+ JVM_OPC_ifeq = 153,
+ JVM_OPC_ifne = 154,
+ JVM_OPC_iflt = 155,
+ JVM_OPC_ifge = 156,
+ JVM_OPC_ifgt = 157,
+ JVM_OPC_ifle = 158,
+ JVM_OPC_if_icmpeq = 159,
+ JVM_OPC_if_icmpne = 160,
+ JVM_OPC_if_icmplt = 161,
+ JVM_OPC_if_icmpge = 162,
+ JVM_OPC_if_icmpgt = 163,
+ JVM_OPC_if_icmple = 164,
+ JVM_OPC_if_acmpeq = 165,
+ JVM_OPC_if_acmpne = 166,
+ JVM_OPC_goto = 167,
+ JVM_OPC_jsr = 168,
+ JVM_OPC_ret = 169,
+ JVM_OPC_tableswitch = 170,
+ JVM_OPC_lookupswitch = 171,
+ JVM_OPC_ireturn = 172,
+ JVM_OPC_lreturn = 173,
+ JVM_OPC_freturn = 174,
+ JVM_OPC_dreturn = 175,
+ JVM_OPC_areturn = 176,
+ JVM_OPC_return = 177,
+ JVM_OPC_getstatic = 178,
+ JVM_OPC_putstatic = 179,
+ JVM_OPC_getfield = 180,
+ JVM_OPC_putfield = 181,
+ JVM_OPC_invokevirtual = 182,
+ JVM_OPC_invokespecial = 183,
+ JVM_OPC_invokestatic = 184,
+ JVM_OPC_invokeinterface = 185,
+ JVM_OPC_xxxunusedxxx = 186,
+ JVM_OPC_new = 187,
+ JVM_OPC_newarray = 188,
+ JVM_OPC_anewarray = 189,
+ JVM_OPC_arraylength = 190,
+ JVM_OPC_athrow = 191,
+ JVM_OPC_checkcast = 192,
+ JVM_OPC_instanceof = 193,
+ JVM_OPC_monitorenter = 194,
+ JVM_OPC_monitorexit = 195,
+ JVM_OPC_wide = 196,
+ JVM_OPC_multianewarray = 197,
+ JVM_OPC_ifnull = 198,
+ JVM_OPC_ifnonnull = 199,
+ JVM_OPC_goto_w = 200,
+ JVM_OPC_jsr_w = 201,
+ JVM_OPC_MAX = 201
+};
+
+/* Opcode length initializer, use with something like:
+ * unsigned char opcode_length[JVM_OPC_MAX+1] = JVM_OPCODE_LENGTH_INITIALIZER;
+ */
+#define JVM_OPCODE_LENGTH_INITIALIZER { \
+ 1, /* nop */ \
+ 1, /* aconst_null */ \
+ 1, /* iconst_m1 */ \
+ 1, /* iconst_0 */ \
+ 1, /* iconst_1 */ \
+ 1, /* iconst_2 */ \
+ 1, /* iconst_3 */ \
+ 1, /* iconst_4 */ \
+ 1, /* iconst_5 */ \
+ 1, /* lconst_0 */ \
+ 1, /* lconst_1 */ \
+ 1, /* fconst_0 */ \
+ 1, /* fconst_1 */ \
+ 1, /* fconst_2 */ \
+ 1, /* dconst_0 */ \
+ 1, /* dconst_1 */ \
+ 2, /* bipush */ \
+ 3, /* sipush */ \
+ 2, /* ldc */ \
+ 3, /* ldc_w */ \
+ 3, /* ldc2_w */ \
+ 2, /* iload */ \
+ 2, /* lload */ \
+ 2, /* fload */ \
+ 2, /* dload */ \
+ 2, /* aload */ \
+ 1, /* iload_0 */ \
+ 1, /* iload_1 */ \
+ 1, /* iload_2 */ \
+ 1, /* iload_3 */ \
+ 1, /* lload_0 */ \
+ 1, /* lload_1 */ \
+ 1, /* lload_2 */ \
+ 1, /* lload_3 */ \
+ 1, /* fload_0 */ \
+ 1, /* fload_1 */ \
+ 1, /* fload_2 */ \
+ 1, /* fload_3 */ \
+ 1, /* dload_0 */ \
+ 1, /* dload_1 */ \
+ 1, /* dload_2 */ \
+ 1, /* dload_3 */ \
+ 1, /* aload_0 */ \
+ 1, /* aload_1 */ \
+ 1, /* aload_2 */ \
+ 1, /* aload_3 */ \
+ 1, /* iaload */ \
+ 1, /* laload */ \
+ 1, /* faload */ \
+ 1, /* daload */ \
+ 1, /* aaload */ \
+ 1, /* baload */ \
+ 1, /* caload */ \
+ 1, /* saload */ \
+ 2, /* istore */ \
+ 2, /* lstore */ \
+ 2, /* fstore */ \
+ 2, /* dstore */ \
+ 2, /* astore */ \
+ 1, /* istore_0 */ \
+ 1, /* istore_1 */ \
+ 1, /* istore_2 */ \
+ 1, /* istore_3 */ \
+ 1, /* lstore_0 */ \
+ 1, /* lstore_1 */ \
+ 1, /* lstore_2 */ \
+ 1, /* lstore_3 */ \
+ 1, /* fstore_0 */ \
+ 1, /* fstore_1 */ \
+ 1, /* fstore_2 */ \
+ 1, /* fstore_3 */ \
+ 1, /* dstore_0 */ \
+ 1, /* dstore_1 */ \
+ 1, /* dstore_2 */ \
+ 1, /* dstore_3 */ \
+ 1, /* astore_0 */ \
+ 1, /* astore_1 */ \
+ 1, /* astore_2 */ \
+ 1, /* astore_3 */ \
+ 1, /* iastore */ \
+ 1, /* lastore */ \
+ 1, /* fastore */ \
+ 1, /* dastore */ \
+ 1, /* aastore */ \
+ 1, /* bastore */ \
+ 1, /* castore */ \
+ 1, /* sastore */ \
+ 1, /* pop */ \
+ 1, /* pop2 */ \
+ 1, /* dup */ \
+ 1, /* dup_x1 */ \
+ 1, /* dup_x2 */ \
+ 1, /* dup2 */ \
+ 1, /* dup2_x1 */ \
+ 1, /* dup2_x2 */ \
+ 1, /* swap */ \
+ 1, /* iadd */ \
+ 1, /* ladd */ \
+ 1, /* fadd */ \
+ 1, /* dadd */ \
+ 1, /* isub */ \
+ 1, /* lsub */ \
+ 1, /* fsub */ \
+ 1, /* dsub */ \
+ 1, /* imul */ \
+ 1, /* lmul */ \
+ 1, /* fmul */ \
+ 1, /* dmul */ \
+ 1, /* idiv */ \
+ 1, /* ldiv */ \
+ 1, /* fdiv */ \
+ 1, /* ddiv */ \
+ 1, /* irem */ \
+ 1, /* lrem */ \
+ 1, /* frem */ \
+ 1, /* drem */ \
+ 1, /* ineg */ \
+ 1, /* lneg */ \
+ 1, /* fneg */ \
+ 1, /* dneg */ \
+ 1, /* ishl */ \
+ 1, /* lshl */ \
+ 1, /* ishr */ \
+ 1, /* lshr */ \
+ 1, /* iushr */ \
+ 1, /* lushr */ \
+ 1, /* iand */ \
+ 1, /* land */ \
+ 1, /* ior */ \
+ 1, /* lor */ \
+ 1, /* ixor */ \
+ 1, /* lxor */ \
+ 3, /* iinc */ \
+ 1, /* i2l */ \
+ 1, /* i2f */ \
+ 1, /* i2d */ \
+ 1, /* l2i */ \
+ 1, /* l2f */ \
+ 1, /* l2d */ \
+ 1, /* f2i */ \
+ 1, /* f2l */ \
+ 1, /* f2d */ \
+ 1, /* d2i */ \
+ 1, /* d2l */ \
+ 1, /* d2f */ \
+ 1, /* i2b */ \
+ 1, /* i2c */ \
+ 1, /* i2s */ \
+ 1, /* lcmp */ \
+ 1, /* fcmpl */ \
+ 1, /* fcmpg */ \
+ 1, /* dcmpl */ \
+ 1, /* dcmpg */ \
+ 3, /* ifeq */ \
+ 3, /* ifne */ \
+ 3, /* iflt */ \
+ 3, /* ifge */ \
+ 3, /* ifgt */ \
+ 3, /* ifle */ \
+ 3, /* if_icmpeq */ \
+ 3, /* if_icmpne */ \
+ 3, /* if_icmplt */ \
+ 3, /* if_icmpge */ \
+ 3, /* if_icmpgt */ \
+ 3, /* if_icmple */ \
+ 3, /* if_acmpeq */ \
+ 3, /* if_acmpne */ \
+ 3, /* goto */ \
+ 3, /* jsr */ \
+ 2, /* ret */ \
+ 99, /* tableswitch */ \
+ 99, /* lookupswitch */ \
+ 1, /* ireturn */ \
+ 1, /* lreturn */ \
+ 1, /* freturn */ \
+ 1, /* dreturn */ \
+ 1, /* areturn */ \
+ 1, /* return */ \
+ 3, /* getstatic */ \
+ 3, /* putstatic */ \
+ 3, /* getfield */ \
+ 3, /* putfield */ \
+ 3, /* invokevirtual */ \
+ 3, /* invokespecial */ \
+ 3, /* invokestatic */ \
+ 5, /* invokeinterface */ \
+ 0, /* xxxunusedxxx */ \
+ 3, /* new */ \
+ 2, /* newarray */ \
+ 3, /* anewarray */ \
+ 1, /* arraylength */ \
+ 1, /* athrow */ \
+ 3, /* checkcast */ \
+ 3, /* instanceof */ \
+ 1, /* monitorenter */ \
+ 1, /* monitorexit */ \
+ 0, /* wide */ \
+ 4, /* multianewarray */ \
+ 3, /* ifnull */ \
+ 3, /* ifnonnull */ \
+ 5, /* goto_w */ \
+ 5 /* jsr_w */ \
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* CLASSFILE_CONSTANTS */
diff --git a/vendor/jdk/1.6.0_23/include/jawt.h b/vendor/jdk/1.6.0_23/include/jawt.h
new file mode 100644
index 0000000..87e0b18
--- /dev/null
+++ b/vendor/jdk/1.6.0_23/include/jawt.h
@@ -0,0 +1,278 @@
+/*
+ * %W% %E%
+ *
+ * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+ */
+
+#ifndef _JAVASOFT_JAWT_H_
+#define _JAVASOFT_JAWT_H_
+
+#include "jni.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * AWT native interface (new in JDK 1.3)
+ *
+ * The AWT native interface allows a native C or C++ application a means
+ * by which to access native structures in AWT. This is to facilitate moving
+ * legacy C and C++ applications to Java and to target the needs of the
+ * community who, at present, wish to do their own native rendering to canvases
+ * for performance reasons. Standard extensions such as Java3D also require a
+ * means to access the underlying native data structures of AWT.
+ *
+ * There may be future extensions to this API depending on demand.
+ *
+ * A VM does not have to implement this API in order to pass the JCK.
+ * It is recommended, however, that this API is implemented on VMs that support
+ * standard extensions, such as Java3D.
+ *
+ * Since this is a native API, any program which uses it cannot be considered
+ * 100% pure java.
+ */
+
+/*
+ * AWT Native Drawing Surface (JAWT_DrawingSurface).
+ *
+ * For each platform, there is a native drawing surface structure. This
+ * platform-specific structure can be found in jawt_md.h. It is recommended
+ * that additional platforms follow the same model. It is also recommended
+ * that VMs on Win32 and Solaris support the existing structures in jawt_md.h.
+ *
+ *******************
+ * EXAMPLE OF USAGE:
+ *******************
+ *
+ * In Win32, a programmer wishes to access the HWND of a canvas to perform
+ * native rendering into it. The programmer has declared the paint() method
+ * for their canvas subclass to be native:
+ *
+ *
+ * MyCanvas.java:
+ *
+ * import java.awt.*;
+ *
+ * public class MyCanvas extends Canvas {
+ *
+ * static {
+ * System.loadLibrary("mylib");
+ * }
+ *
+ * public native void paint(Graphics g);
+ * }
+ *
+ *
+ * myfile.c:
+ *
+ * #include "jawt_md.h"
+ * #include
+ * Copyright (c) 1999-2008
+ * Melloware, Inc.
+ * @param identifier the unique Identifer the Hotkey was assigned
+ */
+ void onHotKey( int identifier );
+}
\ No newline at end of file
diff --git a/vendor/jintellitype/1.3.6/java/com/melloware/jintellitype/IntellitypeListener.java b/vendor/jintellitype/1.3.6/java/com/melloware/jintellitype/IntellitypeListener.java
new file mode 100644
index 0000000..a9d5aa8
--- /dev/null
+++ b/vendor/jintellitype/1.3.6/java/com/melloware/jintellitype/IntellitypeListener.java
@@ -0,0 +1,51 @@
+/**
+ * JIntellitype
+ * -----------------
+ * Copyright 2005-2008 Emil A. Lefkof III, Melloware Inc.
+ *
+ * I always give it my best shot to make a program useful and solid, but
+ * remeber that there is absolutely no warranty for using this program as
+ * stated in the following terms:
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.melloware.jintellitype;
+
+
+/**
+ * Listener interface for Windows Intellitype events. Intellitype are Windows
+ * App Commands that are specialand were introduced with Microsoft Keyboards
+ * that had special keys for Play, Pause, Stop, Next etc for controlling
+ * Media applications like Windows Media Player, Itunes, and Winamp.
+ *
+ * If you have ever wanted your Swing/SWT application to respond to these global
+ * events you now can with JIntellitype. Just implement this interface and
+ * you can now take action when those special Media keys are pressed.
+ *
+ * Copyright (c) 1999-2008
+ * Melloware, Inc.
+ * @param command the WM_APPCOMMAND that was pressed
+ */
+ void onIntellitype( int command );
+}
\ No newline at end of file
diff --git a/vendor/jintellitype/1.3.6/java/com/melloware/jintellitype/JIntellitype.java b/vendor/jintellitype/1.3.6/java/com/melloware/jintellitype/JIntellitype.java
new file mode 100644
index 0000000..7f734d6
--- /dev/null
+++ b/vendor/jintellitype/1.3.6/java/com/melloware/jintellitype/JIntellitype.java
@@ -0,0 +1,665 @@
+/**
+ * JIntellitype ----------------- Copyright 2005-2008 Emil A. Lefkof III,
+ * Melloware Inc. I always give it my best shot to make a program useful and
+ * solid, but remeber that there is absolutely no warranty for using this
+ * program as stated in the following terms: Licensed under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
+ * or agreed to in writing, software distributed under the License is
+ * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language
+ * governing permissions and limitations under the License.
+ */
+package com.melloware.jintellitype;
+
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import javax.swing.SwingUtilities;
+
+/**
+ * JIntellitype A Java Implementation for using the Windows API Intellitype
+ * commands and the RegisterHotKey and UnRegisterHotkey API calls for globally
+ * responding to key events. Intellitype are commands that are using for Play,
+ * Stop, Next on Media keyboards or some laptops that have those special keys.
+ *
+ * JIntellitype class that is used to call Windows API calls using the
+ * JIntellitype.dll.
+ *
+ * This file comes with native code in JINTELLITYPE.DLL The DLL should go in
+ * C:/WINDOWS/SYSTEM or in your current directory
+ *
+ *
+ * Copyright (c) 1999-2008 Melloware, Inc.
+ * @param jarPath the path to the JAR
+ * @param filePath the file path to extract to
+ * @throws IOException if any IO error occurs
+ */
+ private void fromJarToFs(String jarPath, String filePath) throws IOException {
+ File file = new File(filePath);
+ if (file.exists()) {
+ boolean success = file.delete();
+ if (!success) {
+ throw new IOException("couldn't delete " + filePath);
+ }
+ }
+ InputStream is = null;
+ OutputStream os = null;
+ try {
+ is = ClassLoader.getSystemClassLoader().getResourceAsStream(jarPath);
+ os = new FileOutputStream(filePath);
+ byte[] buffer = new byte[8192];
+ int bytesRead;
+ while ((bytesRead = is.read(buffer)) != -1) {
+ os.write(buffer, 0, bytesRead);
+ }
+ } finally {
+ if (is != null) {
+ is.close();
+ }
+ if (os != null) {
+ os.close();
+ }
+ }
+ }
+
+ /**
+ * Gets the singleton instance of the JIntellitype object.
+ *
+ * But the possibility of creation of more instance is only before the
+ * instance is created. Since all code defined inside getInstance method is
+ * in the synchronized block, even the subsequent requests will also come and
+ * wait in the synchronized block. This is a performance issue. The same can
+ * be solved using double-checked lock. Following is the implementation of
+ * Singleton with lazy initialization and double-checked lock.
+ *
+ * @return an instance of JIntellitype class
+ */
+ public static JIntellitype getInstance() {
+ if (!isInitialized) {
+ synchronized (JIntellitype.class) {
+ if (!isInitialized) {
+ jintellitype = new JIntellitype();
+ isInitialized = true;
+ }
+ }
+ }
+ return jintellitype;
+ }
+
+ /**
+ * Adds a listener for hotkeys.
+ *
+ * @param listener the HotKeyListener to be added
+ */
+ public void addHotKeyListener(HotkeyListener listener) {
+ hotkeyListeners.add(listener);
+ }
+
+ /**
+ * Adds a listener for intellitype commands.
+ *
+ * @param listener the IntellitypeListener to be added
+ */
+ public void addIntellitypeListener(IntellitypeListener listener) {
+ intellitypeListeners.add(listener);
+ }
+
+ /**
+ * Cleans up all resources used by JIntellitype.
+ */
+ public void cleanUp() {
+ try {
+ terminate();
+ } catch (UnsatisfiedLinkError ex) {
+ throw new JIntellitypeException(ERROR_MESSAGE, ex);
+ } catch (RuntimeException ex) {
+ throw new JIntellitypeException(ex);
+ }
+ }
+
+ /**
+ * Registers a Hotkey with windows. This combination will be responded to by
+ * all registered HotKeyListeners. Uses the JIntellitypeConstants for MOD,
+ * ALT, CTRL, and WINDOWS keys.
+ *
+ * @param identifier a unique identifier for this key combination
+ * @param modifier MOD_SHIFT, MOD_ALT, MOD_CONTROL, MOD_WIN from
+ * JIntellitypeConstants, or 0 if no modifier needed
+ * @param keycode the key to respond to in Ascii integer, 65 for A
+ */
+ public void registerHotKey(int identifier, int modifier, int keycode) {
+ try {
+ int modifiers = swingToIntelliType(modifier);
+ if (modifiers == 0) {
+ modifiers = modifier;
+ }
+ regHotKey(identifier, modifier, keycode);
+ } catch (UnsatisfiedLinkError ex) {
+ throw new JIntellitypeException(ERROR_MESSAGE, ex);
+ } catch (RuntimeException ex) {
+ throw new JIntellitypeException(ex);
+ }
+ }
+
+ /**
+ * Registers a Hotkey with windows. This combination will be responded to by
+ * all registered HotKeyListeners. Use the Swing InputEvent constants from
+ * java.awt.InputEvent.
+ *
+ * @param identifier a unique identifier for this key combination
+ * @param modifier InputEvent.SHIFT_MASK, InputEvent.ALT_MASK,
+ * InputEvent.CTRL_MASK, or 0 if no modifier needed
+ * @param keycode the key to respond to in Ascii integer, 65 for A
+ */
+ public void registerSwingHotKey(int identifier, int modifier, int keycode) {
+ try {
+ regHotKey(identifier, swingToIntelliType(modifier), keycode);
+ } catch (UnsatisfiedLinkError ex) {
+ throw new JIntellitypeException(ERROR_MESSAGE, ex);
+ } catch (RuntimeException ex) {
+ throw new JIntellitypeException(ex);
+ }
+ }
+
+ /**
+ * Registers a Hotkey with windows. This combination will be responded to by
+ * all registered HotKeyListeners. Use the identifiers CTRL, SHIFT, ALT
+ * and/or WIN.
+ *
+ * @param identifier a unique identifier for this key combination
+ * @param modifierAndKeyCode String with modifiers separated by + and keycode
+ * (e.g. CTRL+SHIFT+A)
+ * @see #registerHotKey(int, int, int)
+ * @see #registerSwingHotKey(int, int, int)
+ */
+ public void registerHotKey(int identifier, String modifierAndKeyCode) {
+ String[] split = modifierAndKeyCode.split("\\+");
+ int mask = 0;
+ int keycode = 0;
+
+ for (int i = 0; i < split.length; i++) {
+ if ("ALT".equalsIgnoreCase(split[i])) {
+ mask += JIntellitype.MOD_ALT;
+ } else if ("CTRL".equalsIgnoreCase(split[i]) || "CONTROL".equalsIgnoreCase(split[i])) {
+ mask += JIntellitype.MOD_CONTROL;
+ } else if ("SHIFT".equalsIgnoreCase(split[i])) {
+ mask += JIntellitype.MOD_SHIFT;
+ } else if ("WIN".equalsIgnoreCase(split[i])) {
+ mask += JIntellitype.MOD_WIN;
+ } else if (keycodeMap.containsKey(split[i].toLowerCase())) {
+ keycode = keycodeMap.get(split[i].toLowerCase());
+ }
+ }
+ registerHotKey(identifier, mask, keycode);
+ }
+
+ /**
+ * Removes a listener for hotkeys.
+ */
+ public void removeHotKeyListener(HotkeyListener listener) {
+ hotkeyListeners.remove(listener);
+ }
+
+ /**
+ * Removes a listener for intellitype commands.
+ */
+ public void removeIntellitypeListener(IntellitypeListener listener) {
+ intellitypeListeners.remove(listener);
+ }
+
+ /**
+ * Unregisters a previously registered Hotkey identified by its unique
+ * identifier.
+ *
+ * @param identifier the unique identifer of this Hotkey
+ */
+ public void unregisterHotKey(int identifier) {
+ try {
+ unregHotKey(identifier);
+ } catch (UnsatisfiedLinkError ex) {
+ throw new JIntellitypeException(ERROR_MESSAGE, ex);
+ } catch (RuntimeException ex) {
+ throw new JIntellitypeException(ex);
+ }
+ }
+
+ /**
+ * Checks to see if this application is already running.
+ *
+ * @param appTitle the name of the application to check for
+ * @return true if running, false if not running
+ */
+ public static boolean checkInstanceAlreadyRunning(String appTitle) {
+ return getInstance().isRunning(appTitle);
+ }
+
+ /**
+ * Checks to make sure the OS is a Windows flavor and that the JIntellitype
+ * DLL is found in the path and the JDK is 32 bit not 64 bit. The DLL
+ * currently only supports 32 bit JDK.
+ *
+ * @return true if Jintellitype may be used, false if not
+ */
+ public static boolean isJIntellitypeSupported() {
+ boolean result = false;
+ String os = "none";
+
+ try {
+ os = System.getProperty("os.name").toLowerCase();
+ } catch (SecurityException ex) {
+ // we are not allowed to look at this property
+ System.err.println("Caught a SecurityException reading the system property "
+ + "'os.name'; the SystemUtils property value will default to null.");
+ }
+
+ // only works on Windows OS currently
+ if (os.startsWith("windows")) {
+ // try an get the instance and if it succeeds then return true
+ try {
+ getInstance();
+ result = true;
+ } catch (Exception e) {
+ result = false;
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Gets the libraryLocation.
+ *
+ * @return Returns the libraryLocation.
+ */
+ public static String getLibraryLocation() {
+ return libraryLocation;
+ }
+
+ /**
+ * Sets the libraryLocation.
+ *
+ * @param libraryLocation The libraryLocation to set.
+ */
+ public static void setLibraryLocation(String libraryLocation) {
+ final File dll = new File(libraryLocation);
+ if (!dll.isAbsolute()) {
+ JIntellitype.libraryLocation = dll.getAbsolutePath();
+ } else {
+ // absolute path, no further calculation needed
+ JIntellitype.libraryLocation = libraryLocation;
+ }
+ }
+
+ /**
+ * Notifies all listeners that Hotkey was pressed.
+ *
+ * @param identifier the unique identifier received
+ */
+ protected void onHotKey(final int identifier) {
+ for (final HotkeyListener hotkeyListener : hotkeyListeners) {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ hotkeyListener.onHotKey(identifier);
+ }
+ });
+ }
+ }
+
+ /**
+ * Notifies all listeners that Intellitype command was received.
+ *
+ * @param command the unique WM_APPCOMMAND received
+ */
+ protected void onIntellitype(final int command) {
+ for (final IntellitypeListener intellitypeListener : intellitypeListeners) {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ intellitypeListener.onIntellitype(command);
+ }
+ });
+ }
+ }
+
+ /**
+ * Swing modifier value to Jintellipad conversion. If no conversion needed
+ * just return the original value. This lets users pass either the original
+ * JIntellitype constants or Swing InputEvent constants.
+ *
+ * @param swingKeystrokeModifier the Swing KeystrokeModifier to check
+ * @return Jintellitype the JIntellitype modifier value
+ */
+ protected static int swingToIntelliType(int swingKeystrokeModifier) {
+ int mask = 0;
+ if ((swingKeystrokeModifier & InputEvent.SHIFT_MASK) == InputEvent.SHIFT_MASK) {
+ mask += JIntellitype.MOD_SHIFT;
+ }
+ if ((swingKeystrokeModifier & InputEvent.ALT_MASK) == InputEvent.ALT_MASK) {
+ mask += JIntellitype.MOD_ALT;
+ }
+ if ((swingKeystrokeModifier & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK) {
+ mask += JIntellitype.MOD_CONTROL;
+ }
+ if ((swingKeystrokeModifier & InputEvent.SHIFT_DOWN_MASK) == InputEvent.SHIFT_DOWN_MASK) {
+ mask += JIntellitype.MOD_SHIFT;
+ }
+ if ((swingKeystrokeModifier & InputEvent.ALT_DOWN_MASK) == InputEvent.ALT_DOWN_MASK) {
+ mask += JIntellitype.MOD_ALT;
+ }
+ if ((swingKeystrokeModifier & InputEvent.CTRL_DOWN_MASK) == InputEvent.CTRL_DOWN_MASK) {
+ mask += JIntellitype.MOD_CONTROL;
+ }
+ return mask;
+ }
+
+ /**
+ * Puts all constants from {@link java.awt.event.KeyEvent} in a keycodeMap.
+ * The key is the lower case form of it.
+ * @return Map containing key->keycode mapping DOCU Now enables the user to
+ * use all keys specified here instead of just [A-Z],[0-9] as before
+ */
+ private HashMap
+ * @param appName = the title of the hidden window to search for
+ */
+ private synchronized native boolean isRunning(String appName);
+}
\ No newline at end of file
diff --git a/vendor/jintellitype/1.3.6/java/com/melloware/jintellitype/JIntellitypeConstants.java b/vendor/jintellitype/1.3.6/java/com/melloware/jintellitype/JIntellitypeConstants.java
new file mode 100644
index 0000000..dfa2af5
--- /dev/null
+++ b/vendor/jintellitype/1.3.6/java/com/melloware/jintellitype/JIntellitypeConstants.java
@@ -0,0 +1,182 @@
+/**
+ * JIntellitype
+ * -----------------
+ * Copyright 2005-2008 Emil A. Lefkof III, Melloware Inc.
+ *
+ * I always give it my best shot to make a program useful and solid, but
+ * remeber that there is absolutely no warranty for using this program as
+ * stated in the following terms:
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.melloware.jintellitype;
+
+/**
+ * Constants from the Windows API used in JIntellitype.
+ *
+ * Message information can be found on MSDN here:
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardinput/keyboardinputreference/keyboardinputmessages/wm_appcommand.asp
+ *
+ * Copyright (c) 1999-2008
+ * Melloware, Inc.
+ * Copyright (c) 1999-2008
+ * Melloware, Inc.
+ * Copyright (c) 1999-2008
+ * Melloware, Inc.
+ * @return the full version number of this application
+ */
+ private static String getProjectVersion() {
+ String version;
+
+ try {
+ final Properties pomProperties = new Properties();
+ pomProperties.load(Main.class.getResourceAsStream("/META-INF/maven/com.melloware/jintellitype/pom.properties"));
+ version = pomProperties.getProperty("version");
+ } catch (Exception e) {
+ version = "RUNNING.IN.IDE.FULL";
+ }
+ return version;
+ }
+}
\ No newline at end of file
diff --git a/vendor/jlgui/3.0/lib/basicplayer3.0.jar b/vendor/jlgui/3.0/lib/basicplayer3.0.jar
new file mode 100644
index 0000000..a45e1fc
Binary files /dev/null and b/vendor/jlgui/3.0/lib/basicplayer3.0.jar differ
diff --git a/vendor/jlgui/3.0/lib/commons-logging-api.jar b/vendor/jlgui/3.0/lib/commons-logging-api.jar
new file mode 100644
index 0000000..ade9a13
Binary files /dev/null and b/vendor/jlgui/3.0/lib/commons-logging-api.jar differ
diff --git a/vendor/jlgui/3.0/lib/jflac-1.2.jar b/vendor/jlgui/3.0/lib/jflac-1.2.jar
new file mode 100644
index 0000000..0de540f
Binary files /dev/null and b/vendor/jlgui/3.0/lib/jflac-1.2.jar differ
diff --git a/vendor/jlgui/3.0/lib/jl1.0.jar b/vendor/jlgui/3.0/lib/jl1.0.jar
new file mode 100644
index 0000000..17f7c0a
Binary files /dev/null and b/vendor/jlgui/3.0/lib/jl1.0.jar differ
diff --git a/vendor/jlgui/3.0/lib/jmactritonusspi1.74.jar b/vendor/jlgui/3.0/lib/jmactritonusspi1.74.jar
new file mode 100644
index 0000000..a5073e2
Binary files /dev/null and b/vendor/jlgui/3.0/lib/jmactritonusspi1.74.jar differ
diff --git a/vendor/jlgui/3.0/lib/jogg-0.0.7.jar b/vendor/jlgui/3.0/lib/jogg-0.0.7.jar
new file mode 100644
index 0000000..1cbd1ad
Binary files /dev/null and b/vendor/jlgui/3.0/lib/jogg-0.0.7.jar differ
diff --git a/vendor/jlgui/3.0/lib/jorbis-0.0.15.jar b/vendor/jlgui/3.0/lib/jorbis-0.0.15.jar
new file mode 100644
index 0000000..4cf51f9
Binary files /dev/null and b/vendor/jlgui/3.0/lib/jorbis-0.0.15.jar differ
diff --git a/vendor/jlgui/3.0/lib/jspeex0.9.7.jar b/vendor/jlgui/3.0/lib/jspeex0.9.7.jar
new file mode 100644
index 0000000..f7a1861
Binary files /dev/null and b/vendor/jlgui/3.0/lib/jspeex0.9.7.jar differ
diff --git a/vendor/jlgui/3.0/lib/kj_dsp1.1.jar b/vendor/jlgui/3.0/lib/kj_dsp1.1.jar
new file mode 100644
index 0000000..2cb3479
Binary files /dev/null and b/vendor/jlgui/3.0/lib/kj_dsp1.1.jar differ
diff --git a/vendor/jlgui/3.0/lib/mp3spi1.9.4.jar b/vendor/jlgui/3.0/lib/mp3spi1.9.4.jar
new file mode 100644
index 0000000..019b86c
Binary files /dev/null and b/vendor/jlgui/3.0/lib/mp3spi1.9.4.jar differ
diff --git a/vendor/jlgui/3.0/lib/tritonus_share.jar b/vendor/jlgui/3.0/lib/tritonus_share.jar
new file mode 100644
index 0000000..d21ba89
Binary files /dev/null and b/vendor/jlgui/3.0/lib/tritonus_share.jar differ
diff --git a/vendor/jlgui/3.0/lib/vorbisspi1.0.2.jar b/vendor/jlgui/3.0/lib/vorbisspi1.0.2.jar
new file mode 100644
index 0000000..1a924af
Binary files /dev/null and b/vendor/jlgui/3.0/lib/vorbisspi1.0.2.jar differ
diff --git a/vendor/jlgui/3.0/src/META-INF/services/org.apache.commons.logging.LogFactory b/vendor/jlgui/3.0/src/META-INF/services/org.apache.commons.logging.LogFactory
new file mode 100644
index 0000000..8693527
--- /dev/null
+++ b/vendor/jlgui/3.0/src/META-INF/services/org.apache.commons.logging.LogFactory
@@ -0,0 +1 @@
+org.apache.commons.logging.impl.LogFactoryImpl
diff --git a/vendor/jlgui/3.0/src/javazoom/jlgui/basicplayer/BasicController.java b/vendor/jlgui/3.0/src/javazoom/jlgui/basicplayer/BasicController.java
new file mode 100644
index 0000000..93944fd
--- /dev/null
+++ b/vendor/jlgui/3.0/src/javazoom/jlgui/basicplayer/BasicController.java
@@ -0,0 +1,102 @@
+/*
+ * BasicController.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.basicplayer;
+
+import java.io.File;
+import java.io.InputStream;
+import java.net.URL;
+
+/**
+ * This interface defines player controls available.
+ */
+public interface BasicController
+{
+ /**
+ * Open inputstream to play.
+ * @param in
+ * @throws BasicPlayerException
+ */
+ public void open(InputStream in) throws BasicPlayerException;
+
+ /**
+ * Open file to play.
+ * @param file
+ * @throws BasicPlayerException
+ */
+ public void open(File file) throws BasicPlayerException;
+
+ /**
+ * Open URL to play.
+ * @param url
+ * @throws BasicPlayerException
+ */
+ public void open(URL url) throws BasicPlayerException;
+
+ /**
+ * Skip bytes.
+ * @param bytes
+ * @return bytes skipped according to audio frames constraint.
+ * @throws BasicPlayerException
+ */
+ public long seek(long bytes) throws BasicPlayerException;
+
+ /**
+ * Start playback.
+ * @throws BasicPlayerException
+ */
+ public void play() throws BasicPlayerException;
+
+ /**
+ * Stop playback.
+ * @throws BasicPlayerException
+ */
+ public void stop() throws BasicPlayerException;
+
+ /**
+ * Pause playback.
+ * @throws BasicPlayerException
+ */
+ public void pause() throws BasicPlayerException;
+
+ /**
+ * Resume playback.
+ * @throws BasicPlayerException
+ */
+ public void resume() throws BasicPlayerException;
+
+ /**
+ * Sets Pan (Balance) value.
+ * Linear scale : -1.0 <--> +1.0
+ * @param pan value from -1.0 to +1.0
+ * @throws BasicPlayerException
+ */
+ public void setPan(double pan) throws BasicPlayerException;
+
+ /**
+ * Sets Gain value.
+ * Linear scale 0.0 <--> 1.0
+ * @param gain value from 0.0 to 1.0
+ * @throws BasicPlayerException
+ */
+ public void setGain(double gain) throws BasicPlayerException;
+}
diff --git a/vendor/jlgui/3.0/src/javazoom/jlgui/basicplayer/BasicPlayer.java b/vendor/jlgui/3.0/src/javazoom/jlgui/basicplayer/BasicPlayer.java
new file mode 100644
index 0000000..a69dd8f
--- /dev/null
+++ b/vendor/jlgui/3.0/src/javazoom/jlgui/basicplayer/BasicPlayer.java
@@ -0,0 +1,1038 @@
+/*
+ * BasicPlayer.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.basicplayer;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import javax.sound.sampled.AudioFileFormat;
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.Control;
+import javax.sound.sampled.DataLine;
+import javax.sound.sampled.FloatControl;
+import javax.sound.sampled.Line;
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.Mixer;
+import javax.sound.sampled.SourceDataLine;
+import javax.sound.sampled.UnsupportedAudioFileException;
+import javazoom.spi.PropertiesContainer;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.tritonus.share.sampled.TAudioFormat;
+import org.tritonus.share.sampled.file.TAudioFileFormat;
+
+/**
+ * BasicPlayer is a threaded simple player class based on JavaSound API.
+ * It has been successfully tested under J2SE 1.3.x, 1.4.x and 1.5.x.
+ */
+public class BasicPlayer implements BasicController, Runnable
+{
+ public static int EXTERNAL_BUFFER_SIZE = 4000 * 4;
+ public static int SKIP_INACCURACY_SIZE = 1200;
+ protected Thread m_thread = null;
+ protected Object m_dataSource;
+ protected AudioInputStream m_encodedaudioInputStream;
+ protected int encodedLength = -1;
+ protected AudioInputStream m_audioInputStream;
+ protected AudioFileFormat m_audioFileFormat;
+ protected SourceDataLine m_line;
+ protected FloatControl m_gainControl;
+ protected FloatControl m_panControl;
+ protected String m_mixerName = null;
+ private int m_lineCurrentBufferSize = -1;
+ private int lineBufferSize = -1;
+ private long threadSleep = -1;
+ private static Log log = LogFactory.getLog(BasicPlayer.class);
+ /**
+ * These variables are used to distinguish stopped, paused, playing states.
+ * We need them to control Thread.
+ */
+ public static final int UNKNOWN = -1;
+ public static final int PLAYING = 0;
+ public static final int PAUSED = 1;
+ public static final int STOPPED = 2;
+ public static final int OPENED = 3;
+ public static final int SEEKING = 4;
+ private int m_status = UNKNOWN;
+ // Listeners to be notified.
+ private Collection m_listeners = null;
+ private Map empty_map = new HashMap();
+
+ /**
+ * Constructs a Basic Player.
+ */
+ public BasicPlayer()
+ {
+ m_dataSource = null;
+ m_listeners = new ArrayList();
+ reset();
+ }
+
+ protected void reset()
+ {
+ m_status = UNKNOWN;
+ if (m_audioInputStream != null)
+ {
+ synchronized (m_audioInputStream)
+ {
+ closeStream();
+ }
+ }
+ m_audioInputStream = null;
+ m_audioFileFormat = null;
+ m_encodedaudioInputStream = null;
+ encodedLength = -1;
+ if (m_line != null)
+ {
+ m_line.stop();
+ m_line.close();
+ m_line = null;
+ }
+ m_gainControl = null;
+ m_panControl = null;
+ }
+
+ /**
+ * Add listener to be notified.
+ * @param bpl
+ */
+ public void addBasicPlayerListener(BasicPlayerListener bpl)
+ {
+ m_listeners.add(bpl);
+ }
+
+ /**
+ * Return registered listeners.
+ * @return
+ */
+ public Collection getListeners()
+ {
+ return m_listeners;
+ }
+
+ /**
+ * Remove registered listener.
+ * @param bpl
+ */
+ public void removeBasicPlayerListener(BasicPlayerListener bpl)
+ {
+ if (m_listeners != null)
+ {
+ m_listeners.remove(bpl);
+ }
+ }
+
+ /**
+ * Set SourceDataLine buffer size. It affects audio latency.
+ * (the delay between line.write(data) and real sound).
+ * Minimum value should be over 10000 bytes.
+ * @param size -1 means maximum buffer size available.
+ */
+ public void setLineBufferSize(int size)
+ {
+ lineBufferSize = size;
+ }
+
+ /**
+ * Return SourceDataLine buffer size.
+ * @return -1 maximum buffer size.
+ */
+ public int getLineBufferSize()
+ {
+ return lineBufferSize;
+ }
+
+ /**
+ * Return SourceDataLine current buffer size.
+ * @return
+ */
+ public int getLineCurrentBufferSize()
+ {
+ return m_lineCurrentBufferSize;
+ }
+
+ /**
+ * Set thread sleep time.
+ * Default is -1 (no sleep time).
+ * @param time in milliseconds.
+ */
+ public void setSleepTime(long time)
+ {
+ threadSleep = time;
+ }
+
+ /**
+ * Return thread sleep time in milliseconds.
+ * @return -1 means no sleep time.
+ */
+ public long getSleepTime()
+ {
+ return threadSleep;
+ }
+
+ /**
+ * Returns BasicPlayer status.
+ * @return status
+ */
+ public int getStatus()
+ {
+ return m_status;
+ }
+
+ /**
+ * Open file to play.
+ */
+ public void open(File file) throws BasicPlayerException
+ {
+ log.info("open(" + file + ")");
+ if (file != null)
+ {
+ m_dataSource = file;
+ initAudioInputStream();
+ }
+ }
+
+ /**
+ * Open URL to play.
+ */
+ public void open(URL url) throws BasicPlayerException
+ {
+ log.info("open(" + url + ")");
+ if (url != null)
+ {
+ m_dataSource = url;
+ initAudioInputStream();
+ }
+ }
+
+ /**
+ * Open inputstream to play.
+ */
+ public void open(InputStream inputStream) throws BasicPlayerException
+ {
+ log.info("open(" + inputStream + ")");
+ if (inputStream != null)
+ {
+ m_dataSource = inputStream;
+ initAudioInputStream();
+ }
+ }
+
+ /**
+ * Inits AudioInputStream and AudioFileFormat from the data source.
+ * @throws BasicPlayerException
+ */
+ protected void initAudioInputStream() throws BasicPlayerException
+ {
+ try
+ {
+ reset();
+ notifyEvent(BasicPlayerEvent.OPENING, getEncodedStreamPosition(), -1, m_dataSource);
+ if (m_dataSource instanceof URL)
+ {
+ initAudioInputStream((URL) m_dataSource);
+ }
+ else if (m_dataSource instanceof File)
+ {
+ initAudioInputStream((File) m_dataSource);
+ }
+ else if (m_dataSource instanceof InputStream)
+ {
+ initAudioInputStream((InputStream) m_dataSource);
+ }
+ createLine();
+ // Notify listeners with AudioFileFormat properties.
+ Map properties = null;
+ if (m_audioFileFormat instanceof TAudioFileFormat)
+ {
+ // Tritonus SPI compliant audio file format.
+ properties = ((TAudioFileFormat) m_audioFileFormat).properties();
+ // Clone the Map because it is not mutable.
+ properties = deepCopy(properties);
+ }
+ else properties = new HashMap();
+ // Add JavaSound properties.
+ if (m_audioFileFormat.getByteLength() > 0) properties.put("audio.length.bytes", new Integer(m_audioFileFormat.getByteLength()));
+ if (m_audioFileFormat.getFrameLength() > 0) properties.put("audio.length.frames", new Integer(m_audioFileFormat.getFrameLength()));
+ if (m_audioFileFormat.getType() != null) properties.put("audio.type", (m_audioFileFormat.getType().toString()));
+ // Audio format.
+ AudioFormat audioFormat = m_audioFileFormat.getFormat();
+ if (audioFormat.getFrameRate() > 0) properties.put("audio.framerate.fps", new Float(audioFormat.getFrameRate()));
+ if (audioFormat.getFrameSize() > 0) properties.put("audio.framesize.bytes", new Integer(audioFormat.getFrameSize()));
+ if (audioFormat.getSampleRate() > 0) properties.put("audio.samplerate.hz", new Float(audioFormat.getSampleRate()));
+ if (audioFormat.getSampleSizeInBits() > 0) properties.put("audio.samplesize.bits", new Integer(audioFormat.getSampleSizeInBits()));
+ if (audioFormat.getChannels() > 0) properties.put("audio.channels", new Integer(audioFormat.getChannels()));
+ if (audioFormat instanceof TAudioFormat)
+ {
+ // Tritonus SPI compliant audio format.
+ Map addproperties = ((TAudioFormat) audioFormat).properties();
+ properties.putAll(addproperties);
+ }
+ // Add SourceDataLine
+ properties.put("basicplayer.sourcedataline", m_line);
+ Iterator it = m_listeners.iterator();
+ while (it.hasNext())
+ {
+ BasicPlayerListener bpl = (BasicPlayerListener) it.next();
+ bpl.opened(m_dataSource, properties);
+ }
+ m_status = OPENED;
+ notifyEvent(BasicPlayerEvent.OPENED, getEncodedStreamPosition(), -1, null);
+ }
+ catch (LineUnavailableException e)
+ {
+ throw new BasicPlayerException(e);
+ }
+ catch (UnsupportedAudioFileException e)
+ {
+ throw new BasicPlayerException(e);
+ }
+ catch (IOException e)
+ {
+ throw new BasicPlayerException(e);
+ }
+ }
+
+ /**
+ * Inits Audio ressources from file.
+ */
+ protected void initAudioInputStream(File file) throws UnsupportedAudioFileException, IOException
+ {
+ m_audioInputStream = AudioSystem.getAudioInputStream(file);
+ m_audioFileFormat = AudioSystem.getAudioFileFormat(file);
+ }
+
+ /**
+ * Inits Audio ressources from URL.
+ */
+ protected void initAudioInputStream(URL url) throws UnsupportedAudioFileException, IOException
+ {
+ m_audioInputStream = AudioSystem.getAudioInputStream(url);
+ m_audioFileFormat = AudioSystem.getAudioFileFormat(url);
+ }
+
+ /**
+ * Inits Audio ressources from InputStream.
+ */
+ protected void initAudioInputStream(InputStream inputStream) throws UnsupportedAudioFileException, IOException
+ {
+ m_audioInputStream = AudioSystem.getAudioInputStream(inputStream);
+ m_audioFileFormat = AudioSystem.getAudioFileFormat(inputStream);
+ }
+
+ /**
+ * Inits Audio ressources from AudioSystem.
+ * Accessed by native code. DO NOT RENAME THIS FIELD.
+ */
+ private Object o;
+
+ /**
+ * Constructor for Holder.
+ *
+ * @param o the Object to encapsulate, may be
+ * Updates the error code field. See {@link #getLastError()}.
+ *
+ * @return
+ * Updates the error code field. See {@link #getLastError()}.
+ *
+ * @param param the parameter, may be
+ * Updates the error code field. See {@link #getLastError()}.
+ *
+ * During this operation, the contents of the array might be changed.
+ *
+ * @param params the parameter array, may be
+ * Updates the error code field. See {@link #getLastError()}.
+ *
+ * @return an
+ * Updates the error code field. See {@link #getLastError()}.
+ *
+ * @param param the parameter, may be
+ * Updates the error code field. See {@link #getLastError()}.
+ *
+ * During this operation, the contents of the array might be changed.
+ *
+ * @param params the parameter array, may be
+ * Before being able to use NativeCall, the {@link #init()} method must have
+ * been called:
+ *
+ * Accessed by native code. DO NOT RENAME THIS FIELD.
+ */
+ private int lastErrorCode;
+
+ /**
+ * The internal handle to the function and the module.
+ *
+ * These are set in native code, so ignore any warnings.
+ *
+ * Accessed by native code. DO NOT RENAME THIS FIELD.
+ */
+ private int functionHandle, moduleHandle;
+
+ /**
+ * The name of the function to call.
+ *
+ * Accessed by native code. DO NOT RENAME THIS FIELD.
+ */
+ private String function;
+
+ /**
+ * The name of the module to call.
+ *
+ * Accessed by native code. DO NOT RENAME THIS FIELD.
+ */
+ private String module;
+
+ /**
+ * Initialize JNI field and method IDs
+ */
+ private static native void initIDs();
+
+ /**
+ * Whether the class has been initialized properly.
+ */
+ private static boolean initialized = false;
+
+ /**
+ * Before NativeCall may be used, this method must be called.
+ * It loads the native library, prepares JNI field and method IDs and loads
+ * the matching {@link Verifier}.
+ *
+ * Multiple calls are ignored.
+ *
+ * @throws IOException if an IOException occured during unpacking of
+ * the native library
+ * @throws SecurityException if accessing system properties was forbidden
+ * by the {@link SecurityManager}
+ * @throws UnsatisfiedLinkError if the
+ * Failure to call this method might result in memory leaks.
+ *
+ * Updates the error code field. See {@link #getLastError()}.
+ */
+ public native synchronized void destroy();
+
+ /**
+ * Checks the supplied Object array for illegal/unsupported types.
+ *
+ * During the verification, the contents of the array might be
+ * changed.
+ *
+ * @param params the Object array, may be
+ * Updates the error code field. See {@link #getLastError()}.
+ */
+ public native void executeCall();
+
+ /**
+ * Calls the function using the given parameter.
+ *
+ * Updates the error code field. See {@link #getLastError()}.
+ *
+ * @param param the parameter, may be
+ * Updates the error code field. See {@link #getLastError()}.
+ *
+ * During this operation, the contents of the array might be changed.
+ *
+ * @param params the parameter array, may be
+ * The arrays are always Contains the main NativeCall classes. For instant API information, see:null
+ */
+ private String findUserSpecifiedLogClassName()
+ {
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic("Trying to get log class from attribute '" + LOG_PROPERTY + "'");
+ }
+ String specifiedClass = (String) getAttribute(LOG_PROPERTY);
+
+ if (specifiedClass == null) { // @deprecated
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic("Trying to get log class from attribute '" +
+ LOG_PROPERTY_OLD + "'");
+ }
+ specifiedClass = (String) getAttribute(LOG_PROPERTY_OLD);
+ }
+
+ if (specifiedClass == null) {
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic("Trying to get log class from system property '" +
+ LOG_PROPERTY + "'");
+ }
+ try {
+ specifiedClass = getSystemProperty(LOG_PROPERTY, null);
+ } catch (SecurityException e) {
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic("No access allowed to system property '" +
+ LOG_PROPERTY + "' - " + e.getMessage());
+ }
+ }
+ }
+
+ if (specifiedClass == null) { // @deprecated
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic("Trying to get log class from system property '" +
+ LOG_PROPERTY_OLD + "'");
+ }
+ try {
+ specifiedClass = getSystemProperty(LOG_PROPERTY_OLD, null);
+ } catch (SecurityException e) {
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic("No access allowed to system property '" +
+ LOG_PROPERTY_OLD + "' - " + e.getMessage());
+ }
+ }
+ }
+
+ // Remove any whitespace; it's never valid in a classname so its
+ // presence just means a user mistake. As we know what they meant,
+ // we may as well strip the spaces.
+ if (specifiedClass != null) {
+ specifiedClass = specifiedClass.trim();
+ }
+
+ return specifiedClass;
+ }
+
+
+ /**
+ * Attempts to load the given class, find a suitable constructor,
+ * and instantiate an instance of Log.
+ *
+ * @param logAdapterClassName classname of the Log implementation
+ *
+ * @param logCategory argument to pass to the Log implementation's
+ * constructor
+ *
+ * @param affectState true if this object's state should
+ * be affected by this method call, false otherwise.
+ *
+ * @return an instance of the given class, or null if the logging
+ * library associated with the specified adapter is not available.
+ *
+ * @throws LogConfigurationException if there was a serious error with
+ * configuration and the handleFlawedDiscovery method decided this
+ * problem was fatal.
+ */
+ private Log createLogFromClass(String logAdapterClassName,
+ String logCategory,
+ boolean affectState)
+ throws LogConfigurationException {
+
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic("Attempting to instantiate '" + logAdapterClassName + "'");
+ }
+
+ Object[] params = { logCategory };
+ Log logAdapter = null;
+ Constructor constructor = null;
+
+ Class logAdapterClass = null;
+ ClassLoader currentCL = getBaseClassLoader();
+
+ for(;;) {
+ // Loop through the classloader hierarchy trying to find
+ // a viable classloader.
+ logDiagnostic(
+ "Trying to load '"
+ + logAdapterClassName
+ + "' from classloader "
+ + objectId(currentCL));
+ try {
+ if (isDiagnosticsEnabled()) {
+ // Show the location of the first occurrence of the .class file
+ // in the classpath. This is the location that ClassLoader.loadClass
+ // will load the class from -- unless the classloader is doing
+ // something weird.
+ URL url;
+ String resourceName = logAdapterClassName.replace('.', '/') + ".class";
+ if (currentCL != null) {
+ url = currentCL.getResource(resourceName );
+ } else {
+ url = ClassLoader.getSystemResource(resourceName + ".class");
+ }
+
+ if (url == null) {
+ logDiagnostic("Class '" + logAdapterClassName + "' [" + resourceName + "] cannot be found.");
+ } else {
+ logDiagnostic("Class '" + logAdapterClassName + "' was found at '" + url + "'");
+ }
+ }
+
+ Class c = null;
+ try {
+ c = Class.forName(logAdapterClassName, true, currentCL);
+ } catch (ClassNotFoundException originalClassNotFoundException) {
+ // The current classloader was unable to find the log adapter
+ // in this or any ancestor classloader. There's no point in
+ // trying higher up in the hierarchy in this case..
+ String msg = "" + originalClassNotFoundException.getMessage();
+ logDiagnostic(
+ "The log adapter '"
+ + logAdapterClassName
+ + "' is not available via classloader "
+ + objectId(currentCL)
+ + ": "
+ + msg.trim());
+ try {
+ // Try the class classloader.
+ // This may work in cases where the TCCL
+ // does not contain the code executed or JCL.
+ // This behaviour indicates that the application
+ // classloading strategy is not consistent with the
+ // Java 1.2 classloading guidelines but JCL can
+ // and so should handle this case.
+ c = Class.forName(logAdapterClassName);
+ } catch (ClassNotFoundException secondaryClassNotFoundException) {
+ // no point continuing: this adapter isn't available
+ msg = "" + secondaryClassNotFoundException.getMessage();
+ logDiagnostic(
+ "The log adapter '"
+ + logAdapterClassName
+ + "' is not available via the LogFactoryImpl class classloader: "
+ + msg.trim());
+ break;
+ }
+ }
+
+ constructor = c.getConstructor(logConstructorSignature);
+ Object o = constructor.newInstance(params);
+
+ // Note that we do this test after trying to create an instance
+ // [rather than testing Log.class.isAssignableFrom(c)] so that
+ // we don't complain about Log hierarchy problems when the
+ // adapter couldn't be instantiated anyway.
+ if (o instanceof Log) {
+ logAdapterClass = c;
+ logAdapter = (Log) o;
+ break;
+ }
+
+ // Oops, we have a potential problem here. An adapter class
+ // has been found and its underlying lib is present too, but
+ // there are multiple Log interface classes available making it
+ // impossible to cast to the type the caller wanted. We
+ // certainly can't use this logger, but we need to know whether
+ // to keep on discovering or terminate now.
+ //
+ // The handleFlawedHierarchy method will throw
+ // LogConfigurationException if it regards this problem as
+ // fatal, and just return if not.
+ handleFlawedHierarchy(currentCL, c);
+ } catch (NoClassDefFoundError e) {
+ // We were able to load the adapter but it had references to
+ // other classes that could not be found. This simply means that
+ // the underlying logger library is not present in this or any
+ // ancestor classloader. There's no point in trying higher up
+ // in the hierarchy in this case..
+ String msg = "" + e.getMessage();
+ logDiagnostic(
+ "The log adapter '"
+ + logAdapterClassName
+ + "' is missing dependencies when loaded via classloader "
+ + objectId(currentCL)
+ + ": "
+ + msg.trim());
+ break;
+ } catch (ExceptionInInitializerError e) {
+ // A static initializer block or the initializer code associated
+ // with a static variable on the log adapter class has thrown
+ // an exception.
+ //
+ // We treat this as meaning the adapter's underlying logging
+ // library could not be found.
+ String msg = "" + e.getMessage();
+ logDiagnostic(
+ "The log adapter '"
+ + logAdapterClassName
+ + "' is unable to initialize itself when loaded via classloader "
+ + objectId(currentCL)
+ + ": "
+ + msg.trim());
+ break;
+ } catch(LogConfigurationException e) {
+ // call to handleFlawedHierarchy above must have thrown
+ // a LogConfigurationException, so just throw it on
+ throw e;
+ } catch(Throwable t) {
+ // handleFlawedDiscovery will determine whether this is a fatal
+ // problem or not. If it is fatal, then a LogConfigurationException
+ // will be thrown.
+ handleFlawedDiscovery(logAdapterClassName, currentCL, t);
+ }
+
+ if (currentCL == null) {
+ break;
+ }
+
+ // try the parent classloader
+ // currentCL = currentCL.getParent();
+ currentCL = getParentClassLoader(currentCL);
+ }
+
+ if ((logAdapter != null) && affectState) {
+ // We've succeeded, so set instance fields
+ this.logClassName = logAdapterClassName;
+ this.logConstructor = constructor;
+
+ // Identify the setLogFactory method (if there is one)
+ try {
+ this.logMethod = logAdapterClass.getMethod("setLogFactory",
+ logMethodSignature);
+ logDiagnostic("Found method setLogFactory(LogFactory) in '"
+ + logAdapterClassName + "'");
+ } catch (Throwable t) {
+ this.logMethod = null;
+ logDiagnostic(
+ "[INFO] '" + logAdapterClassName
+ + "' from classloader " + objectId(currentCL)
+ + " does not declare optional method "
+ + "setLogFactory(LogFactory)");
+ }
+
+ logDiagnostic(
+ "Log adapter '" + logAdapterClassName
+ + "' from classloader " + objectId(logAdapterClass.getClassLoader())
+ + " has been selected for use.");
+ }
+
+ return logAdapter;
+ }
+
+
+ /**
+ * Return the classloader from which we should try to load the logging
+ * adapter classes.
+ * LogConfigurationException that wraps
+ * the passed Throwable.
+ *
+ * @param logAdapterClassName is the class name of the Log implementation
+ * that could not be instantiated. Cannot be null.
+ *
+ * @param classLoader is the classloader that we were trying to load the
+ * logAdapterClassName from when the exception occurred.
+ *
+ * @param discoveryFlaw is the Throwable created by the classloader
+ *
+ * @throws LogConfigurationException ALWAYS
+ */
+ private void handleFlawedDiscovery(String logAdapterClassName,
+ ClassLoader classLoader,
+ Throwable discoveryFlaw) {
+
+ if (isDiagnosticsEnabled()) {
+ logDiagnostic("Could not instantiate Log '"
+ + logAdapterClassName + "' -- "
+ + discoveryFlaw.getClass().getName() + ": "
+ + discoveryFlaw.getLocalizedMessage());
+
+ if (discoveryFlaw instanceof InvocationTargetException ) {
+ // Ok, the lib is there but while trying to create a real underlying
+ // logger something failed in the underlying lib; display info about
+ // that if possible.
+ InvocationTargetException ite = (InvocationTargetException)discoveryFlaw;
+ Throwable cause = ite.getTargetException();
+ if (cause != null) {
+ logDiagnostic("... InvocationTargetException: " +
+ cause.getClass().getName() + ": " +
+ cause.getLocalizedMessage());
+
+ if (cause instanceof ExceptionInInitializerError) {
+ ExceptionInInitializerError eiie = (ExceptionInInitializerError)cause;
+ Throwable cause2 = eiie.getException();
+ if (cause2 != null) {
+ logDiagnostic("... ExceptionInInitializerError: " +
+ cause2.getClass().getName() + ": " +
+ cause2.getLocalizedMessage());
+ }
+ }
+ }
+ }
+ }
+
+ if (!allowFlawedDiscovery) {
+ throw new LogConfigurationException(discoveryFlaw);
+ }
+ }
+
+
+ /**
+ * Report a problem loading the log adapter, then either return
+ * (if the situation is considered recoverable) or throw a
+ * LogConfigurationException.
+ *
+ *
+ * org.apache.commons.logging.Log
+ * that wraps the avalon-logkit
+ * logging system. Configuration of LogKit is left to the user.
+ * LogKit accepts only String messages.
+ * Therefore, this implementation converts object messages into strings
+ * by called their toString() method before logging them.LogKit logger */
+ protected transient Logger logger = null;
+
+ /** Name of this logger */
+ protected String name = null;
+
+
+ // ------------------------------------------------------------ Constructor
+
+
+ /**
+ * Construct LogKitLogger which wraps the LogKit
+ * logger with given name.
+ *
+ * @param name log name
+ */
+ public LogKitLogger(String name) {
+ this.name = name;
+ this.logger = getLogger();
+ }
+
+
+ // --------------------------------------------------------- Public Methods
+
+
+ /**
+ * org.apache.log.Priority.DEBUG.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#trace(Object)
+ */
+ public void trace(Object message) {
+ debug(message);
+ }
+
+
+ /**
+ * Logs a message with org.apache.log.Priority.DEBUG.
+ *
+ * @param message to log
+ * @param t log this cause
+ * @see org.apache.commons.logging.Log#trace(Object, Throwable)
+ */
+ public void trace(Object message, Throwable t) {
+ debug(message, t);
+ }
+
+
+ /**
+ * Logs a message with org.apache.log.Priority.DEBUG.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#debug(Object)
+ */
+ public void debug(Object message) {
+ if (message != null) {
+ getLogger().debug(String.valueOf(message));
+ }
+ }
+
+
+ /**
+ * Logs a message with org.apache.log.Priority.DEBUG.
+ *
+ * @param message to log
+ * @param t log this cause
+ * @see org.apache.commons.logging.Log#debug(Object, Throwable)
+ */
+ public void debug(Object message, Throwable t) {
+ if (message != null) {
+ getLogger().debug(String.valueOf(message), t);
+ }
+ }
+
+
+ /**
+ * Logs a message with org.apache.log.Priority.INFO.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#info(Object)
+ */
+ public void info(Object message) {
+ if (message != null) {
+ getLogger().info(String.valueOf(message));
+ }
+ }
+
+
+ /**
+ * Logs a message with org.apache.log.Priority.INFO.
+ *
+ * @param message to log
+ * @param t log this cause
+ * @see org.apache.commons.logging.Log#info(Object, Throwable)
+ */
+ public void info(Object message, Throwable t) {
+ if (message != null) {
+ getLogger().info(String.valueOf(message), t);
+ }
+ }
+
+
+ /**
+ * Logs a message with org.apache.log.Priority.WARN.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#warn(Object)
+ */
+ public void warn(Object message) {
+ if (message != null) {
+ getLogger().warn(String.valueOf(message));
+ }
+ }
+
+
+ /**
+ * Logs a message with org.apache.log.Priority.WARN.
+ *
+ * @param message to log
+ * @param t log this cause
+ * @see org.apache.commons.logging.Log#warn(Object, Throwable)
+ */
+ public void warn(Object message, Throwable t) {
+ if (message != null) {
+ getLogger().warn(String.valueOf(message), t);
+ }
+ }
+
+
+ /**
+ * Logs a message with org.apache.log.Priority.ERROR.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#error(Object)
+ */
+ public void error(Object message) {
+ if (message != null) {
+ getLogger().error(String.valueOf(message));
+ }
+ }
+
+
+ /**
+ * Logs a message with org.apache.log.Priority.ERROR.
+ *
+ * @param message to log
+ * @param t log this cause
+ * @see org.apache.commons.logging.Log#error(Object, Throwable)
+ */
+ public void error(Object message, Throwable t) {
+ if (message != null) {
+ getLogger().error(String.valueOf(message), t);
+ }
+ }
+
+
+ /**
+ * Logs a message with org.apache.log.Priority.FATAL_ERROR.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#fatal(Object)
+ */
+ public void fatal(Object message) {
+ if (message != null) {
+ getLogger().fatalError(String.valueOf(message));
+ }
+ }
+
+
+ /**
+ * Logs a message with org.apache.log.Priority.FATAL_ERROR.
+ *
+ * @param message to log
+ * @param t log this cause
+ * @see org.apache.commons.logging.Log#fatal(Object, Throwable)
+ */
+ public void fatal(Object message, Throwable t) {
+ if (message != null) {
+ getLogger().fatalError(String.valueOf(message), t);
+ }
+ }
+
+
+ /**
+ * Checks whether the LogKit logger will log messages of priority DEBUG.
+ */
+ public boolean isDebugEnabled() {
+ return getLogger().isDebugEnabled();
+ }
+
+
+ /**
+ * Checks whether the LogKit logger will log messages of priority ERROR.
+ */
+ public boolean isErrorEnabled() {
+ return getLogger().isErrorEnabled();
+ }
+
+
+ /**
+ * Checks whether the LogKit logger will log messages of priority FATAL_ERROR.
+ */
+ public boolean isFatalEnabled() {
+ return getLogger().isFatalErrorEnabled();
+ }
+
+
+ /**
+ * Checks whether the LogKit logger will log messages of priority INFO.
+ */
+ public boolean isInfoEnabled() {
+ return getLogger().isInfoEnabled();
+ }
+
+
+ /**
+ * Checks whether the LogKit logger will log messages of priority DEBUG.
+ */
+ public boolean isTraceEnabled() {
+ return getLogger().isDebugEnabled();
+ }
+
+
+ /**
+ * Checks whether the LogKit logger will log messages of priority WARN.
+ */
+ public boolean isWarnEnabled() {
+ return getLogger().isWarnEnabled();
+ }
+
+
+}
diff --git a/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/NoOpLog.java b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/NoOpLog.java
new file mode 100644
index 0000000..229cdff
--- /dev/null
+++ b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/NoOpLog.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.commons.logging.impl;
+
+
+import java.io.Serializable;
+import org.apache.commons.logging.Log;
+
+
+/**
+ *
+ *
+ *
+ * org.apache.commons.logging.simplelog.defaultlog -
+ * Default logging detail level for all instances of SimpleLog.
+ * Must be one of ("trace", "debug", "info", "warn", "error", or "fatal").
+ * If not specified, defaults to "info". org.apache.commons.logging.simplelog.log.xxxxx -
+ * Logging detail level for a SimpleLog instance named "xxxxx".
+ * Must be one of ("trace", "debug", "info", "warn", "error", or "fatal").
+ * If not specified, the default logging detail level is used.org.apache.commons.logging.simplelog.showlogname -
+ * Set to true if you want the Log instance name to be
+ * included in output messages. Defaults to false.org.apache.commons.logging.simplelog.showShortLogname -
+ * Set to true if you want the last component of the name to be
+ * included in output messages. Defaults to true.org.apache.commons.logging.simplelog.showdatetime -
+ * Set to true if you want the current date and time
+ * to be included in output messages. Default is false.org.apache.commons.logging.simplelog.dateTimeFormat -
+ * The date and time format to be used in the output messages.
+ * The pattern describing the date and time format is the same that is
+ * used in java.text.SimpleDateFormat. If the format is not
+ * specified or is invalid, the default format is used.
+ * The default format is yyyy/MM/dd HH:mm:ss:SSS zzz."simplelog.properties", and includes any matching definitions
+ * from this resource (if it exists).SimpleLog start with this */
+ static protected final String systemPrefix =
+ "org.apache.commons.logging.simplelog.";
+
+ /** Properties loaded from simplelog.properties */
+ static protected final Properties simpleLogProps = new Properties();
+
+ /** The default format to use when formating dates */
+ static protected final String DEFAULT_DATE_TIME_FORMAT =
+ "yyyy/MM/dd HH:mm:ss:SSS zzz";
+
+ /** Include the instance name in the log message? */
+ static protected boolean showLogName = false;
+ /** Include the short name ( last component ) of the logger in the log
+ * message. Defaults to true - otherwise we'll be lost in a flood of
+ * messages without knowing who sends them.
+ */
+ static protected boolean showShortName = true;
+ /** Include the current time in the log message */
+ static protected boolean showDateTime = false;
+ /** The date and time format to use in the log message */
+ static protected String dateTimeFormat = DEFAULT_DATE_TIME_FORMAT;
+
+ /**
+ * Used to format times.
+ * write() to cause it to be written.StringBuffer to the appropriate output destination. The
+ * default implementation writes to System.err.StringBuffer containing the accumulated
+ * text to be logged
+ */
+ protected void write(StringBuffer buffer) {
+
+ System.err.println(buffer.toString());
+
+ }
+
+
+ /**
+ * Is the given log level currently enabled?
+ *
+ * @param logLevel is this level enabled?
+ */
+ protected boolean isLevelEnabled(int logLevel) {
+ // log level are numerically ordered so can use simple numeric
+ // comparison
+ return (logLevel >= currentLogLevel);
+ }
+
+
+ // -------------------------------------------------------- Log Implementation
+
+
+ /**
+ * Logs a message with
+ * org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_DEBUG.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#debug(Object)
+ */
+ public final void debug(Object message) {
+
+ if (isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG)) {
+ log(SimpleLog.LOG_LEVEL_DEBUG, message, null);
+ }
+ }
+
+
+ /**
+ * Logs a message with
+ * org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_DEBUG.
+ *
+ * @param message to log
+ * @param t log this cause
+ * @see org.apache.commons.logging.Log#debug(Object, Throwable)
+ */
+ public final void debug(Object message, Throwable t) {
+
+ if (isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG)) {
+ log(SimpleLog.LOG_LEVEL_DEBUG, message, t);
+ }
+ }
+
+
+ /**
+ * Logs a message with
+ * org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_TRACE.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#trace(Object)
+ */
+ public final void trace(Object message) {
+
+ if (isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE)) {
+ log(SimpleLog.LOG_LEVEL_TRACE, message, null);
+ }
+ }
+
+
+ /**
+ * Logs a message with
+ * org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_TRACE.
+ *
+ * @param message to log
+ * @param t log this cause
+ * @see org.apache.commons.logging.Log#trace(Object, Throwable)
+ */
+ public final void trace(Object message, Throwable t) {
+
+ if (isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE)) {
+ log(SimpleLog.LOG_LEVEL_TRACE, message, t);
+ }
+ }
+
+
+ /**
+ * Logs a message with
+ * org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_INFO.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#info(Object)
+ */
+ public final void info(Object message) {
+
+ if (isLevelEnabled(SimpleLog.LOG_LEVEL_INFO)) {
+ log(SimpleLog.LOG_LEVEL_INFO,message,null);
+ }
+ }
+
+
+ /**
+ * Logs a message with
+ * org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_INFO.
+ *
+ * @param message to log
+ * @param t log this cause
+ * @see org.apache.commons.logging.Log#info(Object, Throwable)
+ */
+ public final void info(Object message, Throwable t) {
+
+ if (isLevelEnabled(SimpleLog.LOG_LEVEL_INFO)) {
+ log(SimpleLog.LOG_LEVEL_INFO, message, t);
+ }
+ }
+
+
+ /**
+ * Logs a message with
+ * org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_WARN.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#warn(Object)
+ */
+ public final void warn(Object message) {
+
+ if (isLevelEnabled(SimpleLog.LOG_LEVEL_WARN)) {
+ log(SimpleLog.LOG_LEVEL_WARN, message, null);
+ }
+ }
+
+
+ /**
+ * Logs a message with
+ * org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_WARN.
+ *
+ * @param message to log
+ * @param t log this cause
+ * @see org.apache.commons.logging.Log#warn(Object, Throwable)
+ */
+ public final void warn(Object message, Throwable t) {
+
+ if (isLevelEnabled(SimpleLog.LOG_LEVEL_WARN)) {
+ log(SimpleLog.LOG_LEVEL_WARN, message, t);
+ }
+ }
+
+
+ /**
+ * Logs a message with
+ * org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_ERROR.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#error(Object)
+ */
+ public final void error(Object message) {
+
+ if (isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR)) {
+ log(SimpleLog.LOG_LEVEL_ERROR, message, null);
+ }
+ }
+
+
+ /**
+ * Logs a message with
+ * org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_ERROR.
+ *
+ * @param message to log
+ * @param t log this cause
+ * @see org.apache.commons.logging.Log#error(Object, Throwable)
+ */
+ public final void error(Object message, Throwable t) {
+
+ if (isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR)) {
+ log(SimpleLog.LOG_LEVEL_ERROR, message, t);
+ }
+ }
+
+
+ /**
+ * Log a message with
+ * org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_FATAL.
+ *
+ * @param message to log
+ * @see org.apache.commons.logging.Log#fatal(Object)
+ */
+ public final void fatal(Object message) {
+
+ if (isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL)) {
+ log(SimpleLog.LOG_LEVEL_FATAL, message, null);
+ }
+ }
+
+
+ /**
+ * Logs a message with
+ * org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_FATAL.
+ *
+ * @param message to log
+ * @param t log this cause
+ * @see org.apache.commons.logging.Log#fatal(Object, Throwable)
+ */
+ public final void fatal(Object message, Throwable t) {
+
+ if (isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL)) {
+ log(SimpleLog.LOG_LEVEL_FATAL, message, t);
+ }
+ }
+
+
+ /**
+ * String
+ * concatenation to be avoided when the message will be ignored by the
+ * logger. String
+ * concatenation to be avoided when the message will be ignored by the
+ * logger. String
+ * concatenation to be avoided when the message will be ignored by the
+ * logger. String
+ * concatenation to be avoided when the message will be ignored by the
+ * logger. String
+ * concatenation to be avoided when the message will be ignored by the
+ * logger. String
+ * concatenation to be avoided when the message will be ignored by the
+ * logger. Hashtable that uses WeakReference's
+ * to hold its keys thus allowing them to be reclaimed by the garbage collector.
+ * The associated values are retained using strong references.Hashtable as closely as
+ * possible. It therefore does not accept null values or keys.Hashtable in LogFactory. This application requires
+ * good liveliness for get and put. Various tradeoffs
+ * have been made with this in mind.
+ * Hashtable used in LogFactory for J2EE enviroments
+ * running 1.3+ JVMs. Use of this class in most cases (see below) will
+ * allow classloaders to be collected by the garbage collector without the need
+ * to call {@link org.apache.commons.logging.LogFactory#release(ClassLoader) LogFactory.release(ClassLoader)}.
+ * org.apache.commons.logging.LogFactory checks whether this class
+ * can be supported by the current JVM, and if so then uses it to store
+ * references to the LogFactory implementationd it loads
+ * (rather than using a standard Hashtable instance).
+ * Having this class used instead of Hashtable solves
+ * certain issues related to dynamic reloading of applications in J2EE-style
+ * environments. However this class requires java 1.3 or later (due to its use
+ * of java.lang.ref.WeakReference and associates).
+ * And by the way, this extends Hashtable rather than HashMap
+ * for backwards compatibility reasons. See the documentation
+ * for method LogFactory.createFactoryStore for more details.LogFactory's factories member! If LogFactory.release()
+ * is called whenever component is unloaded, the classloaders will be correctly
+ * garbage collected; this should be done by any container that
+ * bundles commons-logging by default. However, holding the classloader
+ * references weakly ensures that the classloader will be garbage collected
+ * without the container performing this step. LogFactory is
+ * loaded by the container classloader but a subclass of
+ * LogFactory [LogFactory1] is loaded by the component's
+ * classloader and an instance stored in the static map associated with the
+ * base LogFactory class, then there is a strong reference from the LogFactory
+ * class to the LogFactory1 instance (as normal) and a strong reference from
+ * the LogFactory1 instance to the component classloader via
+ * getClass().getClassLoader(). This chain of references will prevent
+ * collection of the child classloader.LogFactory implementation is
+ * loaded by a child classloader (e.g. a web app classloader).LogFactory. Creating custom LogFactory subclasses is,
+ * however, rare. The standard LogFactoryImpl class should be sufficient
+ * for most or all users.null
+ */
+ private Referenced(Object referant) {
+ reference = new WeakReference(referant);
+ // Calc a permanent hashCode so calls to Hashtable.remove()
+ // work if the WeakReference has been cleared
+ hashCode = referant.hashCode();
+ }
+
+ /**
+ *
+ * @throws NullPointerException if key is null
+ */
+ private Referenced(Object key, ReferenceQueue queue) {
+ reference = new WeakKey(key, queue, this);
+ // Calc a permanent hashCode so calls to Hashtable.remove()
+ // work if the WeakReference has been cleared
+ hashCode = key.hashCode();
+
+ }
+
+ public int hashCode() {
+ return hashCode;
+ }
+
+ private Object getValue() {
+ return reference.get();
+ }
+
+ public boolean equals(Object o) {
+ boolean result = false;
+ if (o instanceof Referenced) {
+ Referenced otherKey = (Referenced) o;
+ Object thisKeyValue = getValue();
+ Object otherKeyValue = otherKey.getValue();
+ if (thisKeyValue == null) {
+ result = (otherKeyValue == null);
+
+ // Since our hashcode was calculated from the original
+ // non-null referant, the above check breaks the
+ // hashcode/equals contract, as two cleared Referenced
+ // objects could test equal but have different hashcodes.
+ // We can reduce (not eliminate) the chance of this
+ // happening by comparing hashcodes.
+ if (result == true) {
+ result = (this.hashCode() == otherKey.hashCode());
+ }
+ // In any case, as our c'tor does not allow null referants
+ // and Hashtable does not do equality checks between
+ // existing keys, normal hashtable operations should never
+ // result in an equals comparison between null referants
+ }
+ else
+ {
+ result = thisKeyValue.equals(otherKeyValue);
+ }
+ }
+ return result;
+ }
+ }
+
+ /**
+ * WeakReference subclass that holds a hard reference to an
+ * associated value and also makes accessible
+ * the Referenced object holding it.
+ */
+ private final static class WeakKey extends WeakReference {
+
+ private final Referenced referenced;
+
+ private WeakKey(Object key,
+ ReferenceQueue queue,
+ Referenced referenced) {
+ super(key, queue);
+ this.referenced = referenced;
+ }
+
+ private Referenced getReferenced() {
+ return referenced;
+ }
+ }
+}
diff --git a/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/package.html b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/package.html
new file mode 100644
index 0000000..5344784
--- /dev/null
+++ b/vendor/commons-logging/1.1.1/java/org/apache/commons/logging/impl/package.html
@@ -0,0 +1,22 @@
+
+
+
+Overview
+
+
+
+
+
+java.util.logging.Logger instance.Logger.Quick Start Guide
+
+
+ import org.apache.commons.logging.Log;
+ import org.apache.commons.logging.LogFactory;
+
+ public class Foo {
+
+ private Log log = LogFactory.getLog(Foo.class);
+
+ public void foo() {
+ ...
+ try {
+ if (log.isDebugEnabled()) {
+ log.debug("About to do something to object " + name);
+ }
+ name.bar();
+ } catch (IllegalStateException e) {
+ log.error("Something bad happened to " + name, e);
+ }
+ ...
+ }
+
+
+Configuring the Commons Logging Package
+
+
+Choosing a
+
+LogFactory ImplementationLogFactory instance that will be used
+to create Log instances for this
+application. This is normally accomplished by calling the static
+getFactory() method. This method implements the following
+discovery algorithm to select the name of the LogFactory
+implementation class this application wants to use:
+
+
+org.apache.commons.logging.LogFactory.META-INF/services/org.apache.commons.logging.LogFactory
+ whose first line is assumed to contain the desired class name.commons-logging.properties
+ visible in the application class path, with a property named
+ org.apache.commons.logging.LogFactory defining the
+ desired implementation class name.commons-logging.properties file is found, all of the
+properties defined there are also used to set configuration attributes on
+the instantiated LogFactory instance.LogFactory class itself
+otherwise. This allows a copy of commons-logging.jar to be
+shared in a multiple class loader environment (such as a servlet container),
+but still allow each web application to provide its own LogFactory
+implementation, if it so desires. An instance of this class will then be
+created, and cached per class loader.
+
+
+The Default
+
+LogFactory ImplementationLogFactory
+implementation class (
+org.apache.commons.logging.impl.LogFactoryImpl) that is selected if no
+other implementation class name can be discovered. Its primary purpose is
+to create (as necessary) and return Log instances
+in response to calls to the getInstance() method. The default
+implementation uses the following rules:
+
+
+Log instance of the same name will be created.
+ Subsequent getInstance() calls to the same
+ LogFactory instance, with the same name or Class
+ parameter, will return the same Log instance.Log instance must be created, the default
+ LogFactory implementation uses the following discovery
+ process:
+
+
org.apache.commons.logging.Log (for backwards
+ compatibility to pre-1.0 versions of this API, an attribute
+ org.apache.commons.logging.log is also consulted).org.apache.commons.logging.Log (for backwards
+ compatibility to pre-1.0 versions of this API, a system property
+ org.apache.commons.logging.log is also consulted).LogFactory class otherwise.Log
+ implementation class, passing the specified name as the single
+ argument to its constructor.Configuring the Underlying Logging System
+
+Log implementations (such as the one for Log4J)
+require an external configuration file for the entire logging environment.
+This file should be prepared in a manner that is specific to the actual logging
+technology being used.Using the Logging Package APIs
+
+
+
+
+trace(), debug(),
+ info(), warn(), error, and
+ fatal()).LogFactory also offers a static method
+getLog() that combines the typical two-step pattern:
+ Log log = LogFactory.getFactory().getInstance(Foo.class);
+
+
+ Log log = LogFactory.getLog(Foo.class);
+
+
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class MyComponent {
+
+ protected Log log =
+ LogFactory.getLog(MyComponent.class);
+
+ // Called once at startup time
+ public void start() {
+ ...
+ log.info("MyComponent started");
+ ...
+ }
+
+ // Called once at shutdown time
+ public void stop() {
+ ...
+ log.info("MyComponent stopped");
+ ...
+ }
+
+ // Called repeatedly to process a particular argument value
+ // which you want logged if debugging is enabled
+ public void process(String value) {
+ ...
+ // Do the string concatenation only if logging is enabled
+ if (log.isDebugEnabled())
+ log.debug("MyComponent processing " + value);
+ ...
+ }
+
+}
+
+
+
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITArtwork.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITArtwork.java
new file mode 100644
index 0000000..53846c9
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITArtwork.java
@@ -0,0 +1,55 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents a artwork.
+ *
+ * Defines a single piece of artwork.
+ *
+ * Artwork is always associated with an individual track.
+ * To add a piece of artwork to a track, use IITTrack::AddArtworkFromFile().
+ * The IITTrack::Artwork property
+ *
+ * To get a collection of artwork associated with a track call
+ * ITTrack.getArtwork().
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITArtwork extends ITObject {
+
+ public ITArtwork (Dispatch d) {
+ super(d);
+ }
+
+ /**
+ * Delete this object.
+ */
+ public void delete() {
+ Dispatch.call(object, "Delete");
+ }
+
+ /**
+ * Returns the kind of the object.
+ * @return Returns the kind of the object.
+ */
+ public ITArtworkFormat getFormat() {
+ return ITArtworkFormat.values()[Dispatch.get(object, "Format").getInt()];
+ }
+
+ // TODO: Comments
+
+ public boolean getIsDownloadedArtwork() {
+ return Dispatch.get(object, "IsDownloadedArtwork").getBoolean();
+ }
+
+ public String getDescription() {
+ return Dispatch.get(object, "Description").getString();
+
+ }
+
+ public void SaveArtworkToFile(String filePath) {
+ Dispatch.call(object, "SaveArtworkToFile",filePath);
+ }
+
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITArtworkCollection.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITArtworkCollection.java
new file mode 100644
index 0000000..c1d8afa
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITArtworkCollection.java
@@ -0,0 +1,55 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents a collection of Artwork objects.
+ *
+ * Note that collection indices are always 1-based.
+ *
+ * You can retrieve all the Artworks defined for a source using
+ * ITSource.getArtwork().
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITArtworkCollection {
+
+ protected Dispatch object;
+
+ public ITArtworkCollection(Dispatch d) {
+ object = d;
+ }
+
+ /**
+ * Returns the number of playlists in the collection.
+ * @return Returns the number of playlists in the collection.
+ */
+ public int getCount() {
+ return Dispatch.get(object, "Count").getInt();
+ }
+
+ /**
+ * Returns an ITArtwork object corresponding to the given index (1-based).
+ * @param index Index of the playlist to retrieve, must be less than or
+ * equal to ITArtworkCollection.getCount().
+ * @return Returns an ITArtwork object corresponding to the given index.
+ * Will be set to NULL if no playlist could be retrieved.
+ */
+ public ITArtwork getItem (int index) {
+ Dispatch item = Dispatch.call(object, "Item", index).toDispatch();
+ return new ITArtwork(item);
+ }
+
+ /**
+ * Returns an ITArtwork object with the specified persistent ID. See the
+ * documentation on ITObject for more information on persistent IDs.
+ * @param highID The high 32 bits of the 64-bit persistent ID.
+ * @param lowID The low 32 bits of the 64-bit persistent ID.
+ * @return Returns an ITArtwork object with the specified persistent ID.
+ * Will be set to NULL if no playlist could be retrieved.
+ */
+ public ITArtwork getItemByPersistentID (int highID, int lowID) {
+ Dispatch item = Dispatch.call(object, "ItemByPersistentID", highID, lowID).toDispatch();
+ return new ITArtwork(item);
+ }
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITArtworkFormat.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITArtworkFormat.java
new file mode 100644
index 0000000..ed4b61e
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITArtworkFormat.java
@@ -0,0 +1,13 @@
+package com.dt.iTunesController;
+
+/**
+ * Specifies the Artwork kind.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public enum ITArtworkFormat {
+ ITArtworkFormatUnknown,
+ ITArtworkFormatJPEG,
+ ITArtworkFormatPNG,
+ ITArtworkFormatBMP;
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITAudioCDPlaylist.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITAudioCDPlaylist.java
new file mode 100644
index 0000000..bc12943
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITAudioCDPlaylist.java
@@ -0,0 +1,76 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents an audio CD playlist.
+ *
+ * An audio CD playlist is always associated with an IITSource of kind
+ * ITSourceKindAudioCD.
+ *
+ * You can retrieve all the playlists defined for a source using
+ * ITSource.getPlaylists().
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITAudioCDPlaylist extends ITPlaylist {
+
+ public ITAudioCDPlaylist(Dispatch d) {
+ super(d);
+ }
+
+ /**
+ * Returns the audio CD's artist.
+ * @return Returns the audio CD's artist.
+ */
+ public String getArtist() {
+ return Dispatch.get(object, "Artist").getString();
+ }
+
+ /**
+ * Returns true if this audio CD is a compilation album.
+ * @return Returns true if this audio CD is a compilation album.
+ */
+ public boolean isCompilation() {
+ return Dispatch.get(object, "Compilation").getBoolean();
+ }
+
+ /**
+ * Returns the audio CD's composer.
+ * @return Returns the audio CD's composer.
+ */
+ public String getComposer() {
+ return Dispatch.get(object, "Composer").getString();
+ }
+
+ /**
+ * Returns the total number of discs in this CD's album.
+ * @return Returns the total number of discs in this CD's album.
+ */
+ public long getDiscCount() {
+ return Dispatch.get(object, "DiscCount").getLong();
+ }
+
+ /**
+ * Returns the index of the CD disc in the source album.
+ * @return Returns the index of the CD disc in the source album.
+ */
+ public long getDiscNumber() {
+ return Dispatch.get(object, "DiscNumber").getLong();
+ }
+
+ /**
+ * Returns the audio CD's genre.
+ * @return Returns the audio CD's genre.
+ */
+ public String getGenre() {
+ return Dispatch.get(object, "Genre").getString();
+ }
+
+ /**
+ * Reveals the CD playlist in the main browser window.
+ */
+ public void reveal() {
+ Dispatch.call(object, "Reveal");
+ }
+
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITBrowserWindow.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITBrowserWindow.java
new file mode 100644
index 0000000..16dc6cf
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITBrowserWindow.java
@@ -0,0 +1,45 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents the main browser window.
+ *
+ * You can retrieve the main browser window using
+ * iTunes.BrowserWindow().
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+
+public class ITBrowserWindow extends ITWindow {
+
+ public ITBrowserWindow (Dispatch d) {
+ super(d);
+ }
+
+ /**
+ * Returns the kind of the object.
+ * @return Returns the kind of the object.
+ */
+ public boolean getMiniPlayer() {
+ return Dispatch.get(object, "MiniPlayer").getBoolean();
+ }
+
+ // TODO: Comments
+
+ public ITTrackCollection getSelectedTracks() {
+ Dispatch collection = Dispatch.call(object, "SelectedTracks").getDispatch();
+ return new ITTrackCollection(collection);
+ }
+
+ public ITPlaylist getSelectedPlaylist() {
+ Dispatch playlist = Dispatch.get(object, "SelectedPlaylist").toDispatch();
+ return new ITPlaylist(playlist);
+ }
+
+ public void setSelectedPlaylist(ITPlaylist playlist) {
+ Dispatch dispatchRef = playlist.fetchDispatch();
+ Dispatch.put(object, "SelectedPlaylist", dispatchRef);
+ }
+
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITCOMDisabledReason.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITCOMDisabledReason.java
new file mode 100644
index 0000000..500280c
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITCOMDisabledReason.java
@@ -0,0 +1,12 @@
+package com.dt.iTunesController;
+
+/**
+ * Specifies the reason the COM interface is being disabled.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public enum ITCOMDisabledReason {
+ ITCOMDisabledReasonOther,
+ ITCOMDisabledReasonDialog,
+ ITCOMDisabledReasonQuitting;
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITEQPreset.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITEQPreset.java
new file mode 100644
index 0000000..1d00cfb
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITEQPreset.java
@@ -0,0 +1,236 @@
+package com.dt.iTunesController;
+
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents an equalizer preset.
+ * You can retrieve or set the currently selected EQ preset using the
+ * iTunes.getCurrentEQPreset() method.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITEQPreset {
+
+ protected Dispatch object;
+
+ public ITEQPreset(Dispatch d) {
+ object = d;
+ }
+
+ /**
+ * Returns the name of the EQ Preset (e.g. "Acoustic").
+ * @return Returns the name of the EQ Preset (e.g. "Acoustic").
+ */
+ public String getName() {
+ return Dispatch.get(object, "Name").getString();
+ }
+
+ /**
+ * Returns true if the EQ preset can be modified.
+ * @return True if the EQ preset can be modified.
+ */
+ public boolean getModifiable() {
+ return Dispatch.get(object, "Modifiable").getBoolean();
+ }
+
+ /**
+ * Set the equalizer preamp level (-12.0 db to +12.0 db).
+ * @param level The new equalizer preamp level (-12.0 db to +12.0 db).
+ */
+ public void setPreamp(double level) {
+ Dispatch.put(object, "Preamp", level);
+ }
+
+ /**
+ * Returns the equalizer preamp level (-12.0db to +12.0db).
+ * @return Returns the equalizer preamp level (-12.0db to +12.0db).
+ */
+ public double getPreamp() {
+ return Dispatch.get(object, "Preamp").getDouble();
+ }
+
+ /**
+ * Set the equalizer 32Hz level (-12.0 db to +12.0 db).
+ * @param level The new equalizer 32Hz level (-12.0 db to +12.0db).
+ */
+ public void setBand1(double level) {
+ Dispatch.put(object, "Band1", level);
+ }
+
+ /**
+ * Returns the equalizer 32Hz level (-12.0 db to +12.0 db).
+ * @return Returns the equalizer 32Hz level (-12.0 db to +12.0 db).
+ */
+ public double getBand1() {
+ return Dispatch.get(object, "Band1").getDouble();
+ }
+
+ /**
+ * Set the equalizer 64Hz level (-12.0 db to +12.0 db).
+ * @param level The new equalizer 64Hz level (-12.0 db to +12.0db).
+ */
+ public void setBand2(double level) {
+ Dispatch.put(object, "Band2", level);
+ }
+
+ /**
+ * Returns the equalizer 64Hz level (-12.0 db to +12.0 db).
+ * @return Returns the equalizer 64Hz level (-12.0 db to +12.0 db).
+ */
+ public double getBand2() {
+ return Dispatch.get(object, "Band2").getDouble();
+ }
+
+ /**
+ * Set the equalizer 125Hz level (-12.0 db to +12.0 db).
+ * @param level The new equalizer 125Hz level (-12.0 db to +12.0db).
+ */
+ public void setBand3(double level) {
+ Dispatch.put(object, "Band3", level);
+ }
+
+ /**
+ * Returns the equalizer 125Hz level (-12.0 db to +12.0 db).
+ * @return Returns the equalizer 125Hz level (-12.0 db to +12.0 db).
+ */
+ public double getBand3() {
+ return Dispatch.get(object, "Band3").getDouble();
+ }
+
+ /**
+ * Set the equalizer 250Hz level (-12.0 db to +12.0 db).
+ * @param level The new equalizer 250Hz level (-12.0 db to +12.0db).
+ */
+ public void setBand4(double level) {
+ Dispatch.put(object, "Band4", level);
+ }
+
+ /**
+ * Returns the equalizer 250Hz level (-12.0 db to +12.0 db).
+ * @return Returns the equalizer 250Hz level (-12.0 db to +12.0 db).
+ */
+ public double getBand4() {
+ return Dispatch.get(object, "Band4").getDouble();
+ }
+
+ /**
+ * Set the equalizer 500Hz level (-12.0 db to +12.0 db).
+ * @param level The new equalizer 500Hz level (-12.0 db to +12.0db).
+ */
+ public void setBand5(double level) {
+ Dispatch.put(object, "Band5", level);
+ }
+
+ /**
+ * Returns the equalizer 500Hz level (-12.0 db to +12.0 db).
+ * @return Returns the equalizer 500Hz level (-12.0 db to +12.0 db).
+ */
+ public double getBand5() {
+ return Dispatch.get(object, "Band5").getDouble();
+ }
+
+ /**
+ * Set the equalizer 1KHz level (-12.0 db to +12.0 db).
+ * @param level The new equalizer 1KHz level (-12.0 db to +12.0db).
+ */
+ public void setBand6(double level) {
+ Dispatch.put(object, "Band6", level);
+ }
+
+ /**
+ * Returns the equalizer 1KHz level (-12.0 db to +12.0 db).
+ * @return Returns the equalizer 1KHz level (-12.0 db to +12.0 db).
+ */
+ public double getBand6() {
+ return Dispatch.get(object, "Band6").getDouble();
+ }
+
+ /**
+ * Set the equalizer 2KHz level (-12.0 db to +12.0 db).
+ * @param level The new equalizer 2KHz level (-12.0 db to +12.0db).
+ */
+ public void setBand7(double level) {
+ Dispatch.put(object, "Band7", level);
+ }
+
+ /**
+ * Returns the equalizer 2KHz level (-12.0 db to +12.0 db).
+ * @return Returns the equalizer 2KHz level (-12.0 db to +12.0 db).
+ */
+ public double getBand7() {
+ return Dispatch.get(object, "Band7").getDouble();
+ }
+
+ /**
+ * Set the equalizer 4KHz level (-12.0 db to +12.0 db).
+ * @param level The new equalizer 4KHz level (-12.0 db to +12.0db).
+ */
+ public void setBand8(double level) {
+ Dispatch.put(object, "Band8", level);
+ }
+
+ /**
+ * Returns the equalizer 4KHz level (-12.0 db to +12.0 db).
+ * @return Returns the equalizer 4KHz level (-12.0 db to +12.0 db).
+ */
+ public double getBand8() {
+ return Dispatch.get(object, "Band8").getDouble();
+ }
+
+ /**
+ * Set the equalizer 8KHz level (-12.0 db to +12.0 db).
+ * @param level The new equalizer 8KHz level (-12.0 db to +12.0db).
+ */
+ public void setBand9(double level) {
+ Dispatch.put(object, "Band9", level);
+ }
+
+ /**
+ * Returns the equalizer 8KHz level (-12.0 db to +12.0 db).
+ * @return Returns the equalizer 8KHz level (-12.0 db to +12.0 db).
+ */
+ public double getBand9() {
+ return Dispatch.get(object, "Band9").getDouble();
+ }
+
+ /**
+ * Set the equalizer 16KHz level (-12.0 db to +12.0 db).
+ * @param level The new equalizer 16KHz level (-12.0 db to +12.0db).
+ */
+ public void setBand10(double level) {
+ Dispatch.put(object, "Band10", level);
+ }
+
+ /**
+ * Returns the equalizer 16KHz level (-12.0 db to +12.0 db).
+ * @return Returns the equalizer 16KHz level (-12.0 db to +12.0 db).
+ */
+ public double getBand10() {
+ return Dispatch.get(object, "Band10").getDouble();
+ }
+
+ /**
+ * Delete this EQ Preset.
+ * Any EQ preset can be deleted, including built-in presets, except for the
+ * Manual preset.
+ * @param updateAllTracks If true, any tracks that use this EQ preet will be
+ * set to have no assigned EQ preset.
+ */
+ public void delete(boolean updateAllTracks) {
+ Dispatch.call(object, "Delete", updateAllTracks);
+ }
+
+ /**
+ * Rename this EQ Preset.
+ * The name of any EQ preset can be changed, including built-in presets,
+ * except for the Manual preset.
+ * EQ preset names cannot start with leading spaces. If you specify a name
+ * that starts with leading spaces they will be stripped out.
+ * @param updateAllTracks If true, any tracks that use this EQ preet will be
+ * updated with the new preset name.
+ */
+ public void rename(String newName, boolean updateAllTracks) {
+ Dispatch.call(object, "Rename", newName, updateAllTracks);
+ }
+
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITFileOrCDTrack.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITFileOrCDTrack.java
new file mode 100644
index 0000000..570896c
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITFileOrCDTrack.java
@@ -0,0 +1,39 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents a file or CD track.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITFileOrCDTrack extends ITTrack {
+
+ public ITFileOrCDTrack (Dispatch d) {
+ super(d);
+ }
+
+ /**
+ * Reveals the track in the main browser window.
+ */
+ public void reveal() {
+ Dispatch.call(object, "Reveal");
+ }
+
+ public ITVideoKind getVideoKind() {
+ return ITVideoKind.values()[Dispatch.get(object, "VideoKind").getInt()];
+ }
+
+ public ITRatingKind getRatingKind() {
+ return ITRatingKind.values()[Dispatch.get(object, "RatingKind").getInt()];
+ }
+
+ public String getLocation() {
+ return Dispatch.get(object, "Location").getString();
+ }
+
+ public ITArtworkCollection getArtworks() {
+ Dispatch artworks = Dispatch.get(object, "Artwork").toDispatch();
+ return new ITArtworkCollection(artworks);
+ }
+
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITLibraryPlaylist.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITLibraryPlaylist.java
new file mode 100644
index 0000000..c19cba8
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITLibraryPlaylist.java
@@ -0,0 +1,20 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents a library playlist.
+ *
+ * A library playlist consists of all the tracks in a user's library.
+ *
+ * For convenience, you can retrieve the main library playlist using
+ * iTunes.getLibraryPlaylist().
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITLibraryPlaylist extends ITPlaylist {
+
+ public ITLibraryPlaylist(Dispatch d) {
+ super(d);
+ }
+
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITObject.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITObject.java
new file mode 100644
index 0000000..27475fd
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITObject.java
@@ -0,0 +1,112 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Defines a source, playlist or track.
+ *
+ * An ITObject uniquely identifies a source, playlist, or track in iTunes using
+ * four separate IDs. These are runtime IDs, they are only valid while the
+ * current instance of iTunes is running.
+ *
+ * As of iTunes 7.7, you can also identify an ITObject using a 64-bit persistent
+ * ID, which is valid across multiple invocations of iTunes.
+ *
+ * The main use of the ITObject interface is to allow clients to track iTunes
+ * database changes using
+ * iTunesEventsInterface.onDatabaseChangedEvent().
+ *
+ * You can retrieve an ITObject with a specified runtime ID using
+ * iTunes.getITObjectByID().
+ *
+ * An ITObject will always have a valid, non-zero source ID.
+ *
+ * An ITObject corresponding to a playlist or track will always have a valid
+ * playlist ID. The playlist ID will be zero for a source.
+ *
+ * An ITObject corresponding to a track will always have a valid track and
+ * track database ID. These IDs will be zero for a source or playlist.
+ *
+ * A track ID is unique within the track's playlist. A track database ID is
+ * unique across all playlists. For example, if the same music file is in two
+ * different playlists, each of the tracks could have different track IDs, but
+ * they will have the same track database ID.
+ *
+ * An ITObject also has a 64-bit persistent ID which can be used to identify
+ * the ITObject across multiple invocations of iTunes.
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITObject {
+
+ protected Dispatch object;
+
+ public ITObject(Dispatch d) {
+ object = d;
+ }
+
+ /**
+ * Returns the JACOB Dispatch object for this object.
+ * @return Returns the JACOB Dispatch object for this object.
+ */
+ public Dispatch fetchDispatch() {
+ return object;
+ }
+
+ /**
+ * Set the name of the object.
+ * @param name The new name of the object.
+ */
+ public void setName (String name) {
+ Dispatch.put(object, "Name", name);
+ }
+
+ /**
+ * Returns the name of the object.
+ * @return Returns the name of the object.
+ */
+ public String getName() {
+ return Dispatch.get(object, "Name").getString();
+ }
+
+ /**
+ * Returns the index of the object in internal application order.
+ * @return The index of the object in internal application order.
+ */
+ public int getIndex() {
+ return Dispatch.get(object, "Index").getInt();
+ }
+
+ /**
+ * Returns the ID that identifies the source.
+ * @return Returns the ID that identifies the source.
+ */
+ public int getSourceID() {
+ return Dispatch.get(object, "SourceID").getInt();
+ }
+
+ /**
+ * Returns the ID that identifies the playlist.
+ * @return Returns the ID that identifies the playlist.
+ */
+ public int getPlaylistID() {
+ return Dispatch.get(object, "PlaylistID").getInt();
+ }
+
+ /**
+ * Returns the ID that identifies the track within the playlist.
+ * @return Returns the ID that identifies the track within the playlist.
+ */
+ public int getTrackID() {
+ return Dispatch.get(object, "TrackID").getInt();
+ }
+
+ /**
+ * Returns the ID that identifies the track, independent of its playlist.
+ * @return Returns the ID that identifies the track, independent of its playlist.
+ */
+ public int getTrackDatabaseID() {
+ return Dispatch.get(object, "TrackDatabaseID").getInt();
+ }
+
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITObjectPersistentID.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITObjectPersistentID.java
new file mode 100644
index 0000000..e5c674b
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITObjectPersistentID.java
@@ -0,0 +1,53 @@
+package com.dt.iTunesController;
+
+/**
+ * Simple utility wrapper class to represent the persistent object identity
+ * ID numbers. Use the getHigh() and getLow() methods individually to get
+ * each ID, or the combined hex string through toString().
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITObjectPersistentID {
+
+ private long High;
+ private long Low;
+ private String hexString;
+
+ /**
+ * Create the ITObjectPersistentID. This class is not intended to be created
+ * manually, and this function should only be used by classes implementing
+ * this utility.
+ * @param high The High Persistent ID
+ * @param low The Low Persistent ID
+ */
+ public ITObjectPersistentID(long high, long low) {
+ this.High=high;
+ this.Low=low;
+ this.hexString = String.format("%8s%8s",Long.toHexString(this.High),Long.toHexString(this.Low)).toUpperCase().replace(' ','0');
+ }
+
+ /**
+ * Returns the high persistent ID.
+ * @return The high persistent ID.
+ */
+ public long getHigh() {
+ return this.High;
+ }
+
+ /**
+ * Returns the low persistent ID.
+ * @return The low persistent ID.
+ */
+ public long getLow() {
+ return this.Low;
+ }
+
+ /**
+ * Return a string representation (in hex) of the persistent IDs.
+ * @return String representation of the persistent IDs.
+ */
+ public String toString() {
+ return this.hexString;
+ }
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITOperationStatus.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITOperationStatus.java
new file mode 100644
index 0000000..cf764aa
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITOperationStatus.java
@@ -0,0 +1,62 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents the status of an asynchronous add or convert operation.
+ *
+ * When a track is added using TLibraryPlaylist.addFile(),
+ * ITLibraryPlaylist.AddFiles(), IITUserPlaylist.addFile(), or
+ * ITUserPlaylist.addFiles(), the add may not complete immediately if iTunes
+ * needs to make a copy of the file.
+ *
+ * Similarly, when converting or importing a file or track using
+ * iTunes.convertFile(), iTunes.convertFiles(),
+ * iTunes.convertTrack() or iTunes.convertTracks(),
+ * the conversion will never complete immediately.
+ *
+ * These methods return an ITOperationStatus object, which can be
+ * polled todetermine when the operation is done. This object will also return
+ * the collection of newly added or converted tracks.
+ *
+ * As of version 1.1 of the iTunes type library, you should use
+ * iTunes.convertFile2(), iTunes.convertFiles2(),
+ * iTunes.convertTrack2() or iTunes.convertTracks2()
+ * instead of the original convert methods. These new methods return an
+ * ITConvertOperationStatus object to allow clients to retrieve
+ * additional conversion progress information.
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITOperationStatus {
+
+ protected Dispatch object;
+
+ public ITOperationStatus(Dispatch d) {
+ object = d;
+ }
+
+ /**
+ * Returns true if the operation is still in progress.
+ * You cannot retrieve the ITOperationStatus.getTracks()
+ * property until the operation completes.
+ * @return Returns true if the operation is still in progress.
+ */
+ public boolean getInProgress() {
+ return Dispatch.get(object, "InProgress").getBoolean();
+ }
+
+ /**
+ * Returns a collection containing the tracks that were generated by the
+ * operation.
+ * You cannot retrieve this property until
+ * ITOperationStatus.getInProgress() returns false
+ * @return Returns a collection containing the tracks that were generated by
+ * the operation.
+ */
+ public ITTrackCollection getTracks() {
+ Dispatch tracks = Dispatch.get(object, "Tracks").toDispatch();
+ return new ITTrackCollection(tracks);
+ }
+
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITPlayerState.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITPlayerState.java
new file mode 100644
index 0000000..4be2a70
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITPlayerState.java
@@ -0,0 +1,13 @@
+package com.dt.iTunesController;
+
+/**
+ * Specifies the state of the player.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public enum ITPlayerState {
+ ITPlayerStateStopped,
+ ITPlayerStatePlaying,
+ ITPlayerStateFastForward,
+ ITPlayerStateRewind;
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITPlaylist.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITPlaylist.java
new file mode 100644
index 0000000..23bf2b9
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITPlaylist.java
@@ -0,0 +1,154 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents a playlist.
+ *
+ * A playlist is always associated with an ITSource.
+ *
+ * You can retrieve all the playlists defined for a source using
+ * ITSource.getPlaylists().
+ *
+ * For convenience, you can retrieve the main library playlist using
+ * iTunes.getLibraryPlaylist().
+ *
+ * You can create a new playlist using iTunes.createPlaylist().
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITPlaylist extends ITObject {
+
+ public ITPlaylist (Dispatch d) {
+ super(d);
+ }
+
+ /**
+ * Delete this object.
+ */
+ public void delete() {
+ Dispatch.call(object, "Delete");
+ }
+
+ /**
+ * Start playing the first track in this object.
+ */
+ public void playFirstTrack() {
+ Dispatch.call(object, "PlayFirstTrack");
+ }
+
+ /**
+ * Print this object.
+ * @param showPrintDialog If true, display the print dialog.
+ * @param printKind The printout kind.
+ * @param theme The name of the theme to use. This corresponds to the name
+ * of a Theme combo box item in the print dialog for the specified printKind
+ * (e.g. "Track length"). This string cannot be longer than 255 characters,
+ * but it may be empty.
+ */
+ public void print(boolean showPrintDialog, ITPlaylistPrintKind printKind, String theme) {
+ Dispatch.call(object, "Print", showPrintDialog, printKind.ordinal(), theme);
+ }
+
+ /**
+ * Returns a collection containing the tracks with the specified text.
+ * @param searchText The text to search for. This string cannot be longer
+ * than 255 chracters.
+ * @param searchFields Specifies which fields of each track should be
+ * searched for searchText.
+ * @return Collection of IITTrack objects. This will be NULL if no tracks
+ * meet the search criteria.
+ */
+ public ITTrackCollection search (String searchText, ITPlaylistSearchField searchFields) {
+ Dispatch collection = Dispatch.call(object, "Search", searchText, searchFields.ordinal()).getDispatch();
+ return new ITTrackCollection(collection);
+ }
+
+ /**
+ * Returns the kind of the object.
+ * @return Returns the kind of the object.
+ */
+ public ITPlaylistKind getKind() {
+ return ITPlaylistKind.values()[Dispatch.get(object, "Kind").getInt()];
+ }
+
+ /**
+ * Returns an ITSource object corresponding to the source that contains the
+ * object.
+ * @return Returns an ITSource object corresponding to the source that
+ * contains the object.
+ */
+ public ITSource getSource() {
+ Dispatch source = Dispatch.get(object, "Source").toDispatch();
+ return new ITSource(source);
+ }
+
+ /**
+ * Returns the total length of all songs in the object (in seconds).
+ * @return Returns the total length of all songs in the object (in
+ * seconds).
+ */
+ public int getDuration() {
+ return Dispatch.get(object, "Duration").getInt();
+ }
+
+ /**
+ * Set whether songs in the object should be played in random order.
+ * @param shouldShuffle True if songs in the object should be played in
+ * random order.
+ */
+ public void setShuffle(boolean shouldShuffle) {
+ Dispatch.put(object, "Shuffle", shouldShuffle);
+ }
+
+ /**
+ * Returns the total size of all songs in the object (in bytes).
+ * @return Returns the total size of all songs in the object (in bytes).
+ */
+ public double getSize() {
+ return Dispatch.get(object, "Size").getDouble();
+ }
+
+ /**
+ * Sets the playback repeat mode.
+ * @param repeatMode The new playback repeat mode.
+ */
+ public void setSongRepeat(ITPlaylistRepeatMode repeatMode) {
+ Dispatch.put(object, "SongRepeat", repeatMode.ordinal());
+ }
+
+ /**
+ * Returns the playback repeat mode.
+ * @return Returns the playback repeat mode.
+ */
+ public ITPlaylistRepeatMode getSongRepeat() {
+ return ITPlaylistRepeatMode.values()[Dispatch.get(object, "SongRepeat").getInt()];
+ }
+
+ /**
+ * Returns the total length of all songs in the object (in MM:SS format).
+ * @return Returns the total length of all songs in the object (in
+ * MM:SS format).
+ */
+ public String getTime() {
+ return Dispatch.get(object, "Time").getString();
+ }
+
+ /**
+ * Returns true if the object is visible in the sources list.
+ * @return True if the object is visible in the sources list.
+ */
+ public boolean getVisible() {
+ return Dispatch.get(object, "Visible").getBoolean();
+ }
+
+ /**
+ * Returns a collection containing the tracks in this object.
+ * @return Collection of ITTrack objects.
+ */
+ public ITTrackCollection getTracks() {
+ Dispatch tracks = Dispatch.get(object, "Tracks").toDispatch();
+ return new ITTrackCollection(tracks);
+ }
+
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITPlaylistCollection.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITPlaylistCollection.java
new file mode 100644
index 0000000..3717735
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITPlaylistCollection.java
@@ -0,0 +1,67 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents a collection of playlist objects.
+ *
+ * Note that collection indices are always 1-based.
+ *
+ * You can retrieve all the playlists defined for a source using
+ * ITSource.getPlaylists().
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITPlaylistCollection {
+
+ protected Dispatch object;
+
+ public ITPlaylistCollection(Dispatch d) {
+ object = d;
+ }
+
+ /**
+ * Returns the number of playlists in the collection.
+ * @return Returns the number of playlists in the collection.
+ */
+ public int getCount() {
+ return Dispatch.get(object, "Count").getInt();
+ }
+
+ /**
+ * Returns an ITPlaylist object corresponding to the given index (1-based).
+ * @param index Index of the playlist to retrieve, must be less than or
+ * equal to ITPlaylistCollection.getCount().
+ * @return Returns an ITPlaylist object corresponding to the given index.
+ * Will be set to NULL if no playlist could be retrieved.
+ */
+ public ITPlaylist getItem (int index) {
+ Dispatch item = Dispatch.call(object, "Item", index).toDispatch();
+ return new ITPlaylist(item);
+ }
+
+ /**
+ * Returns an ITPlaylist object withthe specified name.
+ * @param name The name of the playlist to retrieve.
+ * @return Returns an ITPlaylist object corresponding to the given index.
+ * Will be set to NULL if no playlist could be retrieved.
+ */
+ public ITPlaylist ItemByName (String name) {
+ Dispatch item = Dispatch.call(object, "ItemByName", name).toDispatch();
+ return new ITPlaylist(item);
+ }
+
+ /**
+ * Returns an ITPlaylist object with the specified persistent ID. See the
+ * documentation on ITObject for more information on persistent IDs.
+ * @param highID The high 32 bits of the 64-bit persistent ID.
+ * @param lowID The low 32 bits of the 64-bit persistent ID.
+ * @return Returns an ITPlaylist object with the specified persistent ID.
+ * Will be set to NULL if no playlist could be retrieved.
+ */
+ public ITPlaylist getItemByPersistentID (int highID, int lowID) {
+ Dispatch item = Dispatch.call(object, "ItemByPersistentID", highID, lowID).toDispatch();
+ return new ITPlaylist(item);
+ }
+
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITPlaylistKind.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITPlaylistKind.java
new file mode 100644
index 0000000..e6f685f
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITPlaylistKind.java
@@ -0,0 +1,15 @@
+package com.dt.iTunesController;
+
+/**
+ * Specifies the playlist kind.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public enum ITPlaylistKind {
+ ITPlaylistKindUnknown,
+ ITPlaylistKindLibrary,
+ ITPlaylistKindUser,
+ ITPlaylistKindCD,
+ ITPlaylistKindDevice,
+ ITPlaylistKindRadioTuner;
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITPlaylistPrintKind.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITPlaylistPrintKind.java
new file mode 100644
index 0000000..6fc8ef8
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITPlaylistPrintKind.java
@@ -0,0 +1,14 @@
+package com.dt.iTunesController;
+
+/**
+ * Specifies the kind of playlist printout.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public enum ITPlaylistPrintKind {
+
+ ITPlaylistPrintKindPlaylist,
+ ITPlaylistPrintKindAlbumlist,
+ ITPlaylistPrintKindInsert;
+
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITPlaylistRepeatMode.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITPlaylistRepeatMode.java
new file mode 100644
index 0000000..4b6fc16
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITPlaylistRepeatMode.java
@@ -0,0 +1,14 @@
+package com.dt.iTunesController;
+
+/**
+ * Specifies the playlist playback repeat mode.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public enum ITPlaylistRepeatMode {
+
+ ITPlaylistRepeatModeOff,
+ ITPlaylistRepeatModeOne,
+ ITPlaylistRepeatModeAll;
+
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITPlaylistSearchField.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITPlaylistSearchField.java
new file mode 100644
index 0000000..420b305
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITPlaylistSearchField.java
@@ -0,0 +1,16 @@
+package com.dt.iTunesController;
+
+/**
+ * Specifies the fields in each track that will be searched by
+ * ITPlaylist.search().
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public enum ITPlaylistSearchField {
+ ITPlaylistSearchFieldAll,
+ ITPlaylistSearchFieldVisible,
+ ITPlaylistSearchFieldArtists,
+ ITPlaylistSearchFieldAlbums,
+ ITPlaylistSearchFieldComposers,
+ ITPlaylistSearchFieldSongNames;
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITRatingKind.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITRatingKind.java
new file mode 100644
index 0000000..7d1cb22
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITRatingKind.java
@@ -0,0 +1,11 @@
+package com.dt.iTunesController;
+
+/**
+ * Specifies the rating kind.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public enum ITRatingKind {
+ ITRatingKindUser,
+ ITRatingKindComputed;
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITSource.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITSource.java
new file mode 100644
index 0000000..b0d93fc
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITSource.java
@@ -0,0 +1,51 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents an entry in the Source list (music library, CD, device, etc.).
+ * You can retrieve all the sources using iTunes.getSources().
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITSource extends ITObject {
+
+ public ITSource(Dispatch d) {
+ super(d);
+ }
+
+ /**
+ * Returns the kind of the source.
+ * @return Returns the kind of the source.
+ */
+ public ITSourceKind getKind() {
+ return ITSourceKind.values()[Dispatch.get(object, "Kind").getInt()];
+ }
+
+ /**
+ * Returns the total size of the source, if it has a fixed size.
+ * @return Returns the total size of the source, if it has a fixed size.
+ */
+ public double getCapacity() {
+ return Dispatch.get(object, "Capacity").getDouble();
+ }
+
+ /**
+ * Returns the free space on the source, if it has a fixed size.
+ * @return Returns the free space on the source, if it has a fixed size.
+ */
+ public double getFreespace() {
+ return Dispatch.get(object, "Freespace").getDouble();
+ }
+
+ /**
+ * Returns a collection containing the playlists in this source.
+ * The source's primary playlist is always the first playlist in the
+ * collection.
+ * @return Collection of IITPlaylist objects.
+ */
+ public ITPlaylistCollection getPlaylists() {
+ Dispatch playlists = Dispatch.get(object, "Playlists").toDispatch();
+ return new ITPlaylistCollection(playlists);
+ }
+
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITSourceCollection.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITSourceCollection.java
new file mode 100644
index 0000000..357bdec
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITSourceCollection.java
@@ -0,0 +1,66 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents a collection of source objects.
+ *
+ * Note that collection indices are always 1-based.
+ *
+ * You can retrieve all the sources using ITSource.getSources().
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITSourceCollection {
+
+ protected Dispatch object;
+
+ public ITSourceCollection(Dispatch d) {
+ object = d;
+ }
+
+ /**
+ * Returns the number of sources in the collection.
+ * @return Returns the number of sources in the collection.
+ */
+ public int getCount() {
+ return Dispatch.get(object, "Count").getInt();
+ }
+
+ /**
+ * Returns an ITSource object corresponding to the given index (1-based).
+ * @param index Index of the source to retrieve, must be less than or
+ * equal to ITSourceCollection.getCount().
+ * @return Returns an ITSource object corresponding to the given index.
+ * Will be set to NULL if no source could be retrieved.
+ */
+ public ITSource getItem (int index) {
+ Dispatch item = Dispatch.call(object, "Item", index).toDispatch();
+ return new ITSource(item);
+ }
+
+ /**
+ * Returns an ITSource object withthe specified name.
+ * @param name The name of the source to retrieve.
+ * @return Returns an ITSource object corresponding to the given index.
+ * Will be set to NULL if no source could be retrieved.
+ */
+ public ITSource getItemByName (String name) {
+ Dispatch item = Dispatch.call(object, "ItemByName", name).toDispatch();
+ return new ITSource(item);
+ }
+
+ /**
+ * Returns an ITSource object with the specified persistent ID. See the
+ * documentation on ITObject for more information on persistent IDs.
+ * @param highID The high 32 bits of the 64-bit persistent ID.
+ * @param lowID The low 32 bits of the 64-bit persistent ID.
+ * @return Returns an ITSource object with the specified persistent ID.
+ * Will be set to NULL if no source could be retrieved.
+ */
+ public ITSource getItemByPersistentID (int highID, int lowID) {
+ Dispatch item = Dispatch.call(object, "ItemByPersistentID", highID, lowID).toDispatch();
+ return new ITSource(item);
+ }
+
+}
\ No newline at end of file
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITSourceKind.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITSourceKind.java
new file mode 100644
index 0000000..f332249
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITSourceKind.java
@@ -0,0 +1,17 @@
+package com.dt.iTunesController;
+
+/**
+ * Specifies the source kind.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public enum ITSourceKind {
+ ITSourceKindUnknown,
+ ITSourceKindLibrary,
+ ITSourceKindIPod,
+ ITSourceKindAudioCD,
+ ITSourceKindMP3CD,
+ ITSourceKindDevice,
+ ITSourceKindRadioTuner,
+ ITSourceKindSharedLibrary;
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITTrack.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITTrack.java
new file mode 100644
index 0000000..0046c7e
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITTrack.java
@@ -0,0 +1,492 @@
+package com.dt.iTunesController;
+import com.jacob.com.*;
+import java.util.Date;
+
+/**
+ * Represents a track.
+ *
+ * A track represents a song in a single playlist. A song may be in more than
+ * one playlist, in which case it would be represented by multiple tracks.
+ *
+ * You can retrieve the currently targeted (playing) track using
+ * iTunes.getCurrentTrack().
+ *
+ * Typically, an ITrack is accessed through an ITTrackCollection.
+ *
+ * You can retrieve all the tracks defined for a playlist using
+ * ITPlaylist.getTracks().
+ *
+ * You can retrieve the currently selected track or tracks using
+ * iTunes.getSelectedTracks().
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITTrack extends ITObject {
+
+ public ITTrack (Dispatch d) {
+ super(d);
+ }
+
+ /**
+ * Delete this object.
+ */
+ public void delete() {
+ Dispatch.call(object, "Delete");
+ }
+
+ /**
+ * Start playing this object.
+ */
+ public void play() {
+ Dispatch.call(object, "Play");
+ }
+
+ /**
+ * Set the name of the album containing the object.;
+ * @param album The new name of the album containing the object.
+ */
+ public void setAlbum(String album) {
+ Dispatch.put(object, "Album", album);
+ }
+
+ /**
+ * Returns the name of the album containing the object.
+ * @return Returns the name of the album containing the object.
+ */
+ public String getAlbum() {
+ return Dispatch.get(object, "Album").getString();
+ }
+
+ /**
+ * Set the name of the artist/source of the object.
+ * @param artist The new artist/source of the object.
+ */
+ public void setArtist(String artist) {
+ Dispatch.put(object, "Artist", artist);
+ }
+
+ /**
+ * Returns the name of the artist/source of the object.
+ * @return Returns the name of the artist/source of the object.
+ */
+ public String getArtist() {
+ return Dispatch.get(object, "Artist").getString();
+ }
+
+ /**
+ * Returns the bit rate of the object (in kbps).
+ * @return Returns the bit rate of the object (in kbps).
+ */
+ public int getBitRate() {
+ return Dispatch.get(object, "BitRate").getInt();
+ }
+
+ /**
+ * Set the tempo of the object (in beats per minute).
+ * @param beatsPerMinute The new tempo of the object (in beats per minute).
+ */
+ public void setBPM(int beatsPerMinute) {
+ Dispatch.put(object, "BPM", beatsPerMinute);
+ }
+
+ /**
+ * Returns the tempo of the object (in beats per minute).
+ * @return Returns the tempo of the object (in beats per minute).
+ */
+ public int getBPM() {
+ return Dispatch.get(object, "BPM").getInt();
+ }
+
+ /**
+ * Set freeform notes about the object.
+ * @param comment The new freeform notes about the object.
+ */
+ public void setComment(String comment) {
+ Dispatch.put(object, "Comment", comment);
+ }
+
+ /**
+ * Returns freeform notes about the object.
+ * @return Returns freeform notes about the object.
+ */
+ public String getComment() {
+ return Dispatch.get(object, "Comment").getString();
+ }
+
+ /**
+ * Set whether this object is from a compilation album.
+ * @param isCompilation True if this object should be from a compilation album.
+ */
+ public void setCompilation(boolean isCompilation) {
+ Dispatch.put(object, "Compilation", isCompilation);
+ }
+
+ /**
+ * Returns true if this object is from a compilation album.
+ * @return Returns true if this object is from a compilation album.
+ */
+ public boolean getCompilation() {
+ return Dispatch.get(object, "Compilation").getBoolean();
+ }
+
+ /**
+ * Set the composer of the object.
+ * @param composer The new composer of the object.
+ */
+ public void setComposer (String composer) {
+ Dispatch.put(object, "Composer", composer);
+ }
+
+ /**
+ * Returns the composer of the object.
+ * @return Returns the composer of the object.
+ */
+ public String getComposer() {
+ return Dispatch.get(object, "Composer").getString();
+ }
+
+ /**
+ * Returns the date the object was added to the playlist.
+ * @return Returns the date the object was added to the playlist.
+ */
+ public Date getDateAdded() {
+ return Dispatch.get(object, "DateAdded").getJavaDate();
+ }
+
+ /**
+ * Set the total number of discs in the source album.
+ * @param discCount The new total number of discs in the source album.
+ */
+ public void setDiscCount (int discCount) {
+ Dispatch.put(object, "DiscCount", discCount);
+ }
+
+ /**
+ * Returns the total number of discs in the source album.
+ * @return Returns the total number of discs in the source album.
+ */
+ public int getDiscCount() {
+ return Dispatch.get(object, "DiscCount").getInt();
+ }
+
+ /**
+ * Set the index of the disc containing the object on the source album.
+ * @param discNumber The new index of the disc containing the object on the
+ * source album.
+ */
+ public void setDiscNumber (int discNumber) {
+ Dispatch.put(object, "DiscNumber", discNumber);
+ }
+
+ /**
+ * Returns the index of the disc containing the object on the source album.
+ * @return Returns the index of the disc containing the object on the source
+ * album.
+ */
+ public int getDiscNumber() {
+ return Dispatch.get(object, "DiscNumber").getInt();
+ }
+
+ /**
+ * Returns the length of the object (in seconds).
+ * @return Returns the length of the object (in seconds).
+ */
+ public int getDuration() {
+ return Dispatch.get(object, "Duration").getInt();
+ }
+
+ /**
+ * Set whether this object is checked for playback.
+ * @param shouldBeEnabled True if the object should be checked for playback.
+ */
+ public void setEnabled (boolean shouldBeEnabled) {
+ Dispatch.put(object, "Enabled", shouldBeEnabled);
+ }
+
+ /**
+ * Returns true if the object is checked for playback.
+ * @return Returns true if the object is checked for playback.
+ */
+ public boolean getEnabled() {
+ return Dispatch.get(object, "Enabled").getBoolean();
+ }
+
+ /**
+ * Set the name of the EQ preset of the object.
+ * @param eq The new name of the EQ preset of the object.
+ */
+ public void setEQ (String eq) {
+ Dispatch.put(object, "EQ", eq);
+ }
+
+ /**
+ * Returns the name of the EQ preset of the object.
+ * @return Returns the name of the EQ preset of the object.
+ */
+ public String getEQ() {
+ return Dispatch.get(object, "EQ").getString();
+ }
+
+ /**
+ * Set the stop time of the object (in seconds).
+ * @param finish The new stop time of the object (in seconds).
+ */
+ public void setFinish(int finish) {
+ Dispatch.put(object, "Finish", finish);
+ }
+
+ /**
+ * Returns the stop time of the object (in seconds).
+ * @return Returns the stop time of the object (in seconds).
+ */
+ public int getFinish() {
+ return Dispatch.get(object, "Finish").getInt();
+ }
+
+ /**
+ * Returns the music/audio genre (category) of the object.
+ * @param genre Returns the music/audio genre (category) of the object.
+ */
+ public void setGenre(String genre) {
+ Dispatch.put(object, "Genre", genre);
+ }
+
+ /**
+ * Set the music/audio genre (category) of the object.
+ * @return The new music/audio genre (category) of the object.
+ */
+ public String getGenre() {
+ return Dispatch.get(object, "Genre").getString();
+ }
+
+ /**
+ * Set the grouping (piece) of the object.
+ * Generally used to denote movements within classical work.
+ * @param grouping The new grouping (piece) of the object.
+ */
+ public void setGrouping (String grouping) {
+ Dispatch.put(object, "Grouping", grouping);
+ }
+
+ /**
+ * Returns the grouping (piece) of the object.
+ * Generally used to denote movements within classical work.
+ * @return Returns the grouping (piece) of the object.
+ */
+ public String getGrouping() {
+ return Dispatch.get(object, "Grouping").getString();
+ }
+
+ public ITTrackKind getKind() {
+ return ITTrackKind.values()[Dispatch.get(object, "Kind").getInt()];
+ }
+
+ /**
+ * Returns the text description of the object (e.g. "AAC audio file").
+ * @return Returns the text description of the object (e.g. "AAC audio file").
+ */
+ public String getKindAsString() {
+ return Dispatch.get(object, "KindAsString").getString();
+ }
+
+ /**
+ * Returns the modification date of the content of the object.
+ * @return Returns the modification date of the content of the object.
+ */
+ public Date getModificationDate() {
+ return Dispatch.get(object, "ModificationDate").getJavaDate();
+ }
+
+ /**
+ * Set the number of times the object has been played. This property cannot
+ * be set if the object is not playable (e.g. a PDF file).
+ * @param playedCount The new number of times the object has been played.
+ */
+ public void setPlayedCount (int playedCount) {
+ Dispatch.put(object, "PlayedCount", playedCount);
+ }
+
+ /**
+ * Returns the number of times the object has been played.
+ * @return Returns the number of times the object has been played.
+ */
+ public int getPlayedCount() {
+ return Dispatch.get(object, "PlayedCount").getInt();
+ }
+
+ /**
+ * Set the date and time the object was last played. This property cannot be
+ * set if the object is not playable (e.g. a PDF file).
+ * A value of zero means no played date.
+ * @param playedDate The new date and time the object was last played.
+ */
+ public void setPlayedDate (Date playedDate) {
+ Dispatch.put(object, "PlayedDate", playedDate);
+ }
+
+ /**
+ * Returns the date and time the object was last played.
+ * A value of zero means no played date.
+ * @return Returns the date and time the object was last played.
+ */
+ public Date getPlayedDate() {
+ return Dispatch.get(object, "PlayedDate").getJavaDate();
+ }
+
+ /**
+ * Returns an ITPlaylist object corresponding to the playlist that contains
+ * the object. Use ITFileOrCDTrack::Playlists() or IITURLTrack::Playlists()
+ * to get the collection of all playlists that contain the song this object
+ * represents.
+ * @return Returns an ITPlaylist object corresponding to the playlist that
+ * contains the object.
+ */
+ public ITPlaylist getPlaylist() {
+ Dispatch playlist = Dispatch.get(object, "Playlist").toDispatch();
+ return new ITPlaylist(playlist);
+ }
+
+ /**
+ * Returns the play order index of the object in the owner playlist
+ * (1-based).
+ * You can pass this index to IITTrackCollection::ItemByPlayOrder() for the
+ * collection returned by ITPlaylist::Tracks() to retrieve an ITTrack
+ * object corresponding to this object.
+ * @return Returns the play order index of the object in the owner playlist.
+ */
+ public int getPlayOrderIndex() {
+ return Dispatch.get(object, "PlayOrderIndex").getInt();
+ }
+
+ /**
+ * Set the rating of the object (0 to 100). If the object rating is set to 0,
+ * it will be computed based on the album rating.
+ * @param rating The new rating of the object (0 to 100).
+ */
+ public void setRating (int rating) {
+ Dispatch.put(object, "Rating", rating);
+ }
+
+ /**
+ * Returns the rating of the object (0 to 100). If the object rating has never
+ * been set, or has been set to 0, it will be computed based on the album
+ * rating.
+ * @return Returns the rating of the object (0 to 100).
+ */
+ public int getRating() {
+ return Dispatch.get(object, "Rating").getInt();
+ }
+
+ /**
+ * Returns the sample rate of the object (in Hz).
+ * @return Returns the sample rate of the object (in Hz).
+ */
+ public int getSampleRate() {
+ return Dispatch.get(object, "SampleRate").getInt();
+ }
+
+ /**
+ * Returns the size of the object (in bytes).
+ * @return Returns the size of the object (in bytes).
+ */
+ public int getSize() {
+ return Dispatch.get(object, "Size").getInt();
+ }
+
+ /**
+ * Set the start time of the object (in seconds).
+ * @param start The new start time of the object (in seconds).
+ */
+ public void setStart (int start) {
+ Dispatch.put(object, "Start", start);
+ }
+
+ /**
+ * Returns the start time of the object (in seconds).
+ * @return Returns the start time of the object (in seconds).
+ */
+ public int getStart() {
+ return Dispatch.get(object, "Start").getInt();
+ }
+
+ /**
+ * Returns the length of the object (in MM:SS format).
+ * @return Returns the length of the object (in MM:SS format).
+ */
+ public String getTime() {
+ return Dispatch.get(object, "Time").getString();
+ }
+
+ /**
+ * Set the total number of tracks on the source album.
+ * @param trackCount The new total number of tracks on the source album.
+ */
+ public void setTrackCount (int trackCount) {
+ Dispatch.put(object, "TrackCount", trackCount);
+ }
+
+ /**
+ * Returns the total number of tracks on the source album.
+ * @return Returns the total number of tracks on the source album.
+ */
+ public int getTrackCount() {
+ return Dispatch.get(object, "TrackCount").getInt();
+ }
+
+ /**
+ * Set the index of the object on the source album.
+ * @param trackNumber The new index of the object on the source album.
+ */
+ public void setTrackNumber (int trackNumber) {
+ Dispatch.put(object, "TrackNumber", trackNumber);
+ }
+
+ /**
+ * Returns the index of the object on the source album.
+ * @return Returns the index of the object on the source album.
+ */
+ public int getTrackNumber() {
+ return Dispatch.get(object, "TrackNumebr").getInt();
+ }
+
+ /**
+ * Set the relative volume adjustment of the object (-100% to 100%).
+ * @param volumeAdjustment Set the relative volume adjustment of the object
+ * (-100% to 100%).
+ */
+ public void setVolumeAdjustment (int volumeAdjustment) {
+ Dispatch.put(object, "VolumeAdjustment", volumeAdjustment);
+ }
+
+ /**
+ * Returns the relative volume adjustment of the object (-100% to 100%).
+ * @return Returns the relative volume adjustment of the object (-100% to 100%).
+ */
+ public int getVolumeAdjustment() {
+ return Dispatch.get(object, "VolumeAdjustment").getInt();
+ }
+
+ /**
+ * Set the year the object was recorded/released.
+ * @param year The new year the object was recorded/released.
+ */
+ public void setYear (int year) {
+ Dispatch.put(object, "Year", year);
+ }
+
+ /**
+ * Returns the year the object was recorded/released.
+ * @return Returns the year the object was recorded/released.
+ */
+ public int getYear() {
+ return Dispatch.get(object, "Year").getInt();
+ }
+
+ public ITArtworkCollection getArtwork() {
+ Dispatch art = Dispatch.get(object, "Artwork").toDispatch();
+ return new ITArtworkCollection(art);
+
+ }
+
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITTrackCollection.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITTrackCollection.java
new file mode 100644
index 0000000..b87208f
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITTrackCollection.java
@@ -0,0 +1,91 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents a collection of track objects.
+ *
+ * Note that collection indices are always 1-based.
+ *
+ * You can retrieve all the tracks defined for a playlist using
+ * ITPlaylist.getTracks().
+ *
+ * You can retrieve the currently selected track or tracks using
+ * iTunes.getSelectedTracks().
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITTrackCollection {
+
+ protected Dispatch object;
+
+ public ITTrackCollection(Dispatch d) {
+ object = d;
+ }
+
+ /**
+ * Returns the number of tracks in the collection.
+ * @return Returns the number of tracks in the collection.
+ */
+ public int getCount() {
+ return Dispatch.get(object, "Count").getInt();
+ }
+
+ /**
+ * Returns an ITTrack object corresponding to the given index (1-based).
+ * @param index Index of the track to retrieve, must be less than or
+ * equal to ITTrackCollection.getCount().
+ * @return Returns an ITTrack object corresponding to the given index.
+ * Will be set to NULL if no track could be retrieved.
+ */
+ public ITTrack getItem (int index) {
+ Dispatch item = Dispatch.call(object, "Item", index).toDispatch();
+ ITTrack track = new ITTrack(item);
+ if (track.getKind()==ITTrackKind.ITTrackKindFile) {
+ return new ITFileOrCDTrack(item);
+ } else if (track.getKind()==ITTrackKind.ITTrackKindCD) {
+ return new ITFileOrCDTrack(item);
+ } else if (track.getKind()==ITTrackKind.ITTrackKindURL ) {
+ return new ITURLTrack(item);
+ } else {
+ return track;
+ }
+ }
+
+ /**
+ * Returns an ITTrack object corresponding to the given index (1-based).
+ * @param index Index of the track to retrieve, must be less than or
+ * equal to ITTrackCollection.getCount().
+ * @return Returns an ITTrack object corresponding to the given index.
+ * Will be set to NULL if no track could be retrieved.
+ */
+ public ITTrack getItemByPlayOrder(int index) {
+ Dispatch item = Dispatch.call(object, "ItemByPlayOrder", index).toDispatch();
+ return new ITTrack(item);
+ }
+
+ /**
+ * Returns an ITTrack object withthe specified name.
+ * @param name The name of the track to retrieve.
+ * @return Returns an ITTrack object corresponding to the given index.
+ * Will be set to NULL if no track could be retrieved.
+ */
+ public ITTrack ItemByName (String name) {
+ Dispatch item = Dispatch.call(object, "ItemByName", name).toDispatch();
+ return new ITTrack(item);
+ }
+
+ /**
+ * Returns an ITTrack object with the specified persistent ID. See the
+ * documentation on ITObject for more information on persistent IDs.
+ * @param highID The high 32 bits of the 64-bit persistent ID.
+ * @param lowID The low 32 bits of the 64-bit persistent ID.
+ * @return Returns an ITTrack object with the specified persistent ID.
+ * Will be set to NULL if no track could be retrieved.
+ */
+ public ITTrack getItemByPersistentID (int highID, int lowID) {
+ Dispatch item = Dispatch.call(object, "ItemByPersistentID", highID, lowID).toDispatch();
+ return new ITTrack(item);
+ }
+
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITTrackKind.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITTrackKind.java
new file mode 100644
index 0000000..ec233a1
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITTrackKind.java
@@ -0,0 +1,15 @@
+package com.dt.iTunesController;
+
+/**
+ * Specifies the track kind.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public enum ITTrackKind {
+ ITTrackKindUnknown,
+ ITTrackKindFile,
+ ITTrackKindCD,
+ ITTrackKindURL,
+ ITTrackKindDevice,
+ ITTrackKindSharedLibrary;
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITURLTrack.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITURLTrack.java
new file mode 100644
index 0000000..9829190
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITURLTrack.java
@@ -0,0 +1,175 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents a URL track.
+ *
+ * A URL track references a network audio stream.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITURLTrack extends ITTrack {
+
+ public ITURLTrack (Dispatch d) {
+ super(d);
+ }
+
+ /**
+ * Returns the URL of the stream represented by this track.
+ * @return The URL of the stream represented by this track.
+ */
+ public String getURL () {
+ return Dispatch.get(object, "URL").getString();
+ }
+
+ /**
+ * Set the URL of the stream represented by this track.
+ * @param url The URL of the stream represented by this track.
+ */
+ public void setURL (String url) {
+ Dispatch.call(object, "URL", url);
+ }
+
+ /**
+ * Returns true if this track is a podcast track. If a podcast track is an
+ * IITURLTrack, the podcast episode has not been downloaded.
+ * @return Returns true if this track is a podcast track.
+ */
+ public boolean isPodcast () {
+ return Dispatch.get(object, "Podcast").getBoolean();
+ }
+
+ /**
+ * Returns the category for the track.
+ * @return Returns the category for the track.
+ */
+ public String getCategory () {
+ return Dispatch.get(object, "Category").getString();
+ }
+
+ /**
+ * Sets the category for the track.
+ * @param category Sets the category for the track.
+ */
+ public void setCategory (String category) {
+ Dispatch.call(object, "Category", category);
+ }
+
+ /**
+ * Returns the description for the track.
+ * @return Returns the description for the track.
+ */
+ public String getDescription () {
+ return Dispatch.get(object, "Description").getString();
+ }
+
+ /**
+ * Sets the description for the track.
+ * @param description The new description for the track.
+ */
+ public void setDescription (String description) {
+ Dispatch.call(object, "Description", description);
+ }
+
+ /**
+ * Returns the long description for the track.
+ * @return Returns the description for the track.
+ */
+ public String getLongDescription () {
+ return Dispatch.get(object, "LongDescription").getString();
+ }
+
+ /**
+ * Sets the long description for the track.
+ * @param longDescription The new long description for the track.
+ */
+ public void setLongDescription (String longDescription) {
+ Dispatch.call(object, "LongDescription", longDescription);
+ }
+
+ /**
+ * Returns the user or computed rating of the album that this track belongs
+ * to (0 to 100). If the album rating has never been set, or has been set to
+ * 0, it will be computed based on the ratings of tracks in the album.
+ * @return Returns the album rating of the album that this track belongs to (0 to 100).
+ */
+ public long getAlbumRating () {
+ return Dispatch.get(object, "AlbumRating").getLong();
+ }
+
+ /**
+ * Set the album rating of the album that this track belongs to (0 to 100).
+ * If the album rating is set to 0, it will be computed based on the ratings
+ * of tracks in the album.
+ * @param albumRating The new album rating of the album that this track
+ * belongs to (0 to 100). If rating is outside this range, it will be
+ * pinned.
+ */
+ public void setAlbumRating (long albumRating) {
+ Dispatch.call(object, "AlbumRating", albumRating);
+ }
+
+ /**
+ * Returns the album rating kind. If the album rating has never been set, or
+ * has been set to 0, the kind is ITRatingKindComputed. Otherwise, the kind
+ * is ITRatingKindUser.
+ * @return Returns the album rating kind.
+ */
+ public ITRatingKind getAlbumRatingKind () {
+ return ITRatingKind.values()[Dispatch.get(object, "AlbumRatingKind").getInt()];
+ }
+
+ /**
+ * Returns the track rating kind. If the track rating has never been set, or
+ * has been set to 0, the kind is ITRatingKindComputed. Otherwise, the kind
+ * is ITRatingKindUser.
+ * @return Returns the track rating kind.
+ */
+ public ITRatingKind getRatingKind () {
+ return ITRatingKind.values()[Dispatch.get(object, "RatingKind").getInt()];
+ }
+
+ /**
+ * Returns a collection of playlists that contain the song that this track
+ * represents.
+ *
+ * This is the same collection of playlists that are shown in the "Show in
+ * Playlist" contextual menu for a track, plus the specific playlist that
+ * contains this track.
+ *
+ * A track represents a song in a single playlist, use
+ * ITTrack.getPlaylist() to get the specific playlist that
+ * contains this track.
+ * @return Collection of ITPlaylist objects.
+ */
+ public ITPlaylistCollection getPlaylists () {
+ Dispatch playlists = Dispatch.get(object, "Playlists").toDispatch();
+ return new ITPlaylistCollection(playlists);
+ }
+
+ /**
+ * Update the podcast feed for this track. This is equivalent to the user
+ * choosing Update Podcast from the contextual menu for the podcast feed
+ * that contains this track.
+ */
+ public void updatePodcastFeed () {
+ Dispatch.call(object, "UpdatePodcastFeed");
+ }
+
+ /**
+ * Start downloading the podcast episode that corresponds to this track.
+ * This is equivalent to the user clicking the Get button next to this
+ * track.
+ */
+ public void downloadPodcastEpisode () {
+ Dispatch.call(object, "DownloadPodcastEpisode");
+ }
+
+ /**
+ * Reveals the track in the main browser window.
+ */
+ public void reveal() {
+ Dispatch.call(object, "Reveal");
+ }
+
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITUserPlaylist.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITUserPlaylist.java
new file mode 100644
index 0000000..b4025cf
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITUserPlaylist.java
@@ -0,0 +1,60 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents a user-defined playlist.
+ *
+ * A user playlist includes both smart and manual user-defined playlists.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITUserPlaylist extends ITPlaylist {
+
+ public ITUserPlaylist(Dispatch d) {
+ super(d);
+ }
+
+ /**
+ * Add a file or files inside a folder to the playlist.
+ * You cannot use this method to add a file that requires conversion to be
+ * added (e.g. a CD track), use iTunes.convertFile() or
+ * iTunes.convertFile2() instead. If you add a folder that
+ * contains files that require conversion, they will be skipped.
+ * @param filePath The full path to the file or folder to add.
+ * @return Returns an ITOperationStatus object corresponding to the
+ * asynchronous operation. If an error occurs, or no files were added, this
+ * will be set to NULL.
+ */
+ public ITOperationStatus addFile (String filePath) {
+ Dispatch status = Dispatch.call(object, "AddFile", filePath).toDispatch();
+ return new ITOperationStatus(status);
+ }
+
+ /**
+ * Add a streaming audio URL to the playlist.
+ * @param url The URL to add. The length of the URL can be 255 characters or
+ * less.
+ * @return Returns an ITURLTrack object corresponding to the new track.
+ */
+ public ITURLTrack addURL (String url) {
+ Dispatch URLTrack = Dispatch.call(object, "AddURL", url).toDispatch();
+ return new ITURLTrack(URLTrack);
+ }
+
+ /**
+ * Add an existing track to the playlist.
+ * You cannot use this method to add a CD track (ITTrackKindCD) to another
+ * playlist, use iTunes.convertTrack() or
+ * iTunes.convertTrack2() instead.
+ * You cannot add a shared library track (ITTrackKindSharedLibrary) to
+ * another playlist.
+ * @param track The track to add.
+ * @return Returns an IITTrack object corresponding to the new track.
+ */
+ public ITTrack addTrack (ITTrack track) {
+ Dispatch trackToAdd = track.fetchDispatch();
+ Dispatch addedTrack = Dispatch.call(object, "AddTrack", trackToAdd).toDispatch();
+ return new ITTrack(addedTrack);
+ }
+
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITVideoKind.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITVideoKind.java
new file mode 100644
index 0000000..d318724
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITVideoKind.java
@@ -0,0 +1,13 @@
+package com.dt.iTunesController;
+
+/**
+ * Specifies the Video kind.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public enum ITVideoKind {
+ ITVideoKindNone,
+ ITVideoKindMovie,
+ ITVideoKindMusicVideo,
+ ITVideoKindTVShow;
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITWindow.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITWindow.java
new file mode 100644
index 0000000..4af825f
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITWindow.java
@@ -0,0 +1,32 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents an iTunes window.
+ */
+
+public class ITWindow {
+
+ protected Dispatch object;
+
+ public ITWindow(Dispatch d) {
+ object = d;
+ }
+
+ /**
+ * Returns the JACOB Dispatch object for this object.
+ * @return Returns the JACOB Dispatch object for this object.
+ */
+ public Dispatch fetchDispatch() {
+ return object;
+ }
+
+ /**
+ * Returns the name of the object.
+ * @return Returns the name of the object.
+ */
+ public String getName() {
+ return Dispatch.get(object, "Name").getString();
+ }
+
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/ITWindowCollection.java b/vendor/iTunesController/0.2/com/dt/iTunesController/ITWindowCollection.java
new file mode 100644
index 0000000..df1f3cf
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/ITWindowCollection.java
@@ -0,0 +1,55 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents a collection of window objects.
+ *
+ * Note that collection indices are always 1-based.
+ *
+ * You can retrieve all the windows using
+ * iTunes.getWindows().
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITWindowCollection {
+
+ protected Dispatch object;
+
+ public ITWindowCollection(Dispatch d) {
+ object = d;
+ }
+
+ // TODO: iTunes.getWindows()
+
+ /**
+ * Returns the number of playlists in the collection.
+ * @return Returns the number of playlists in the collection.
+ */
+ public int getCount() {
+ return Dispatch.get(object, "Count").getInt();
+ }
+
+ /**
+ * Returns an ITWindow object corresponding to the given index (1-based).
+ * @param index Index of the playlist to retrieve, must be less than or
+ * equal to ITWindowCollection.getCount().
+ * @return Returns an ITWindow object corresponding to the given index.
+ * Will be set to NULL if no playlist could be retrieved.
+ */
+ public ITWindow getItem (int index) {
+ Dispatch item = Dispatch.call(object, "Item", index).toDispatch();
+ return new ITWindow(item);
+ }
+ /**
+ * Returns an ITWindow object with the specified name.
+ * @param name The name of the window to retrieve.
+ * @return Returns an ITWindow object corresponding to the given index.
+ * Will be set to NULL if no ITWindow could be retrieved.
+ */
+ public ITWindow ItemByName (String name) {
+ Dispatch item = Dispatch.call(object, "ItemByName", name).toDispatch();
+ return new ITWindow(item);
+ }
+
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/iTunes.java b/vendor/iTunesController/0.2/com/dt/iTunesController/iTunes.java
new file mode 100644
index 0000000..150ae7a
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/iTunes.java
@@ -0,0 +1,488 @@
+package com.dt.iTunesController;
+import com.jacob.activeX.*;
+import com.jacob.com.Dispatch;
+import com.jacob.com.DispatchEvents;
+import com.jacob.com.Variant;
+
+/**
+ * Defines the top-level iTunes application object.
+ *
+ * This interface defines the top-level iTunes application object. All other
+ * iTunes interfaces are accessed through this object.
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class iTunes {
+
+ ActiveXComponent iTunes;
+ iTunesEvents iTunesEvents;
+ DispatchEvents dispatchEvents;
+
+ /**
+ * Initiate iTunes Controller.
+ */
+ public iTunes() {
+ iTunes = new ActiveXComponent("iTunes.Application");
+ }
+
+ /**
+ * Add an event handler to the iTunes controller.
+ * @param itef The class that will handle the iTunes events.
+ */
+ public void addEventHandler(iTunesEventsInterface itef) {
+ iTunesEvents = new iTunesEvents(itef);
+ dispatchEvents = new DispatchEvents(iTunes, iTunesEvents);
+ System.out.println("New event handler added.");
+ }
+
+ /**
+ * Reposition to the beginning of the current track or go to the previous
+ * track if already at start of current track.
+ */
+ public void backTrack() {
+ iTunes.invoke("BackTrack");
+ }
+
+ /**
+ * Skip forward in a playing track.
+ */
+ public void fastForward() {
+ iTunes.invoke("FastForward");
+ }
+
+ /**
+ * Advance to the next track in the current playlist.
+ */
+ public void nextTrack() {
+ iTunes.invoke("NextTrack");
+ }
+
+ /**
+ * Pause playback.
+ */
+ public void pause() {
+ iTunes.invoke("Pause");
+ }
+
+ /**
+ * Play the currently targeted track.
+ */
+ public void play() {
+ Variant s = iTunes.invoke("ASDSDPlay");
+ }
+
+ /**
+ * Play the specified file path, adding it to the library if not already
+ * present.
+ */
+ public void playFile(String filePath) {
+ iTunes.invoke("PlayFile", filePath);
+ }
+
+ /**
+ * Toggle the playing/paused state of the current track.
+ */
+ public void playPause() {
+ iTunes.invoke("PlayPause");
+ }
+
+ /**
+ * Return to the previous track in the current playlist.
+ */
+ public void previousTrack() {
+ iTunes.invoke("PreviousTrack");
+ }
+
+ /**
+ * Disable fast forward/rewind and resume playback, if playing.
+ */
+ public void resume() {
+ iTunes.invoke("Resume");
+ }
+
+ /**
+ * Skip backwards in a playing track.
+ */
+ public void rewind() {
+ iTunes.invoke("Rewind");
+ }
+
+ /**
+ * Stop playback.
+ */
+ public void stop() {
+ iTunes.invoke("Stop");
+ }
+
+ /**
+ * Retrieves the current state of the player buttons in the window
+ * containing the currently targeted track. If there is no currently
+ * targeted track, returns the current state of the player buttons
+ * in the main browser window.
+ */
+ public void getPlayerButtonsState(boolean previousEnabled,
+ String playPause, boolean nextEnabled) {
+
+ }
+
+ /**
+ * Returns true if this version of the iTunes type library is compatible
+ * with the specified version.
+ * @param majorVersion Major version of iTunes interface.
+ * @param minorVersion Minor version of iTunes interface.
+ * @return Returns true if this version is compatible with the indicated
+ * interface version.
+ */
+ public boolean getCheckVersion (int majorVersion, int minorVersion) {
+ return iTunes.invoke("CheckVersion", majorVersion, minorVersion).getBoolean();
+ }
+
+ /**
+ * Returns an IITObject corresponding to the specified IDs.
+ * The object may be a source, playlist, or track.
+ * @param sourceID The ID that identifies the source. Valid for a source,
+ * playlist, or track.
+ * @param playlistID The ID that identifies the playlist. Valid for a
+ * playlist or track. Must be zero for a source.
+ * @param trackID The ID that identifies the track within the playlist.
+ * Valid for a track. Must be zero for a source or playlist.
+ * @param databaseID The ID that identifies the track, independent of its
+ * playlist. Valid for a track. Must be zero for a source or playlist.
+ * @return Returns an IITObject object corresponding to the specified IDs.
+ * Will be set to NULL if no object could be retrieved.
+ */
+ public ITObject getITObjectByID(int sourceID, int playlistID, int trackID, int databaseID) {
+ Dispatch object = Dispatch.call(iTunes, "GetITObjectByID", sourceID, playlistID, trackID, databaseID).toDispatch();
+ return new ITObject(object);
+ }
+
+ /**
+ * Creates a new playlist in the main library.
+ * @param playlistName The name of the new playlist (may be empty).
+ * @return Returns an ITPlaylist object corresponding to the new playlist.
+ */
+ public ITPlaylist createPlaylist(String playlistName) {
+ Dispatch cplaylist = Dispatch.call(iTunes, "CreatePlaylist", playlistName).toDispatch();
+ ITPlaylist playlist = new ITPlaylist(cplaylist);
+ ITPlaylistKind playlistKind = playlist.getKind();
+ if (playlistKind == ITPlaylistKind.ITPlaylistKindCD)
+ return new ITAudioCDPlaylist(cplaylist);
+ else if (playlist.getKind() == ITPlaylistKind.ITPlaylistKindLibrary)
+ return new ITLibraryPlaylist(cplaylist);
+ else if (playlist.getKind() == ITPlaylistKind.ITPlaylistKindUser)
+ return new ITUserPlaylist(cplaylist);
+ else
+ return playlist;
+ }
+
+ /**
+ * Open the specified iTunes Store or streaming audio URL.
+ * @param url The URL to open. The length of the URL cannot exceed 512
+ * characters. iTunes Store URLs start with itms:// or itmss://. Streaming
+ * audio URLs start with http://.
+ */
+ public void openURL (String url) {
+ iTunes.invoke("OpenURL", url);
+ }
+
+ /**
+ * Go to the iTunes Store home page.
+ */
+ public void gotoMusicStoreHomePage() {
+ iTunes.invoke("GoToMusicStoreHomePage");
+ }
+
+ /**
+ * Update the contents of the iPod.
+ */
+ public void updateIPod() {
+ iTunes.invoke("UpdateIPod");
+ }
+
+ /**
+ * Exits the iTunes application.
+ */
+ public void quit() {
+ iTunes.invoke("Quit");
+ }
+
+ /**
+ * Creates a new EQ preset.
+ * The EQ preset will be created "flat", i.e. the preamp and all band levels
+ * will be set to 0.
+ * EQ preset names cannot start with leading spaces. If you specify a name
+ * that starts with leading spaces they will be stripped out.
+ * If eqPresetName is empty, the EQ preset will be created with
+ * a default name.
+ * @param eqPresetName The name of the new EQ Preset (may be empty)
+ * @return Returns an ITEQPreset object corresponding to the new EQ Preset.
+ */
+ public ITEQPreset createEQPreset(String eqPresetName) {
+ Dispatch eqPreset = Dispatch.call(iTunes, "CreateEQPreset", eqPresetName).toDispatch();
+ return new ITEQPreset(eqPreset);
+ }
+
+ /**
+ * Creates a new playlist in an existing source.
+ * You may not be able to create a playlist in every source. For example,
+ * you cannot create a playlist in an audio CD source, or in an iPod source
+ * if it is in auto update mode.
+ * If playlistName is empty, the playlist will be created with
+ * a default name.
+ * @param playlistName The name of the new playlist (may be empty).
+ * @param source The source that will contain the new playlist.
+ * @return Returns an ITPlaylist object corresponding to the new playlist.
+ */
+ public ITPlaylist createPlaylistInSource(String playlistName, ITSource source) {
+ Dispatch cplaylist = Dispatch.call(iTunes, "CreatePlaylistInSource", playlistName, source.fetchDispatch()).toDispatch();
+ ITPlaylist playlist = new ITPlaylist(cplaylist);
+ ITPlaylistKind playlistKind = playlist.getKind();
+ if (playlistKind == ITPlaylistKind.ITPlaylistKindCD)
+ return new ITAudioCDPlaylist(cplaylist);
+ else if (playlist.getKind() == ITPlaylistKind.ITPlaylistKindLibrary)
+ return new ITLibraryPlaylist(cplaylist);
+ else if (playlist.getKind() == ITPlaylistKind.ITPlaylistKindUser)
+ return new ITUserPlaylist(cplaylist);
+ else
+ return playlist;
+ }
+
+ /**
+ * Subscribes to the specified podcast feed URL. Any "unsafe" characters in
+ * the URL should already be converted into their corresponding escape
+ * sequences, iTunes will not do this.
+ * @param url The URL to subscribe to.
+ */
+ public void subscribeToPodcast(String url) {
+ iTunes.invoke("SubscribeToPodcast", url);
+ }
+
+ /**
+ * Updates all podcast feeds. This is equivalent to the user pressing the
+ * Update button when Podcasts is selected in the Source list.
+ */
+ public void updatePodcastFeeds() {
+ iTunes.invoke("UpdatePodcastFeeds");
+ }
+
+ /**
+ * Creates a new folder in the main library.
+ * If folderName is empty, the folder will be created with a
+ * default name.
+ * @param folderName The name of the new folder (may be empty).
+ * @return Returns an ITPlaylist object corresponding to the new folder.
+ */
+ public ITUserPlaylist createFolder(String folderName) {
+ Dispatch folder = Dispatch.call(iTunes, "CreateFolder", folderName).toDispatch();
+ return new ITUserPlaylist(folder);
+ }
+
+ /**
+ * Creates a new folder in an existing source.
+ * You may not be able to create a folder in every source. For example, you
+ * cannot create a folder in an audio CD source, or in an iPod source if it
+ * is in auto update mode.
+ * If folderName is empty, the folder will be created with a
+ * default name.
+ * @param folderName The name of the new folder (may be empty)
+ * @param iSource The source that will contain the new folder.
+ * @return Returns an ITPlaylist object corresponding to the new folder.
+ */
+ public ITUserPlaylist createFolderInSource(String folderName, ITSource iSource) {
+ Dispatch folder = Dispatch.call(iTunes, "CreateFolderInSource", folderName, iSource.fetchDispatch()).toDispatch();
+ return new ITUserPlaylist(folder);
+ }
+
+ /**
+ * Returns a collection of music sources (music library, CD, device, etc.).
+ * @return Collection of ITSource objects.
+ */
+ public ITSourceCollection getSources() {
+ Dispatch sources = Dispatch.call(iTunes, "Sources").toDispatch();
+ return new ITSourceCollection(sources);
+ }
+
+ /**
+ * Sets the sound output volume (0=minimum, 100=maximum).
+ * @param volume New sound output volume
+ */
+ public void setSoundVolume(int volume) {
+ iTunes.setProperty("SoundVolume", volume);
+ }
+
+ /**
+ * Returns the sound output volume (0=minimum, 100=maximum).
+ * @return Current sound output volume
+ */
+ public int getSoundVolume() {
+ return iTunes.getPropertyAsInt("SoundVolume");
+ }
+
+ /**
+ * Sets sound output mute state.
+ * @param shouldMute If true, sound output will be muted.
+ */
+ public void setMute(boolean shouldMute) {
+ iTunes.setProperty("Mute", shouldMute);
+ }
+
+ /**
+ * Returns true if the sound output is muted.
+ * @return True if sound output is muted.
+ */
+ public boolean getMute() {
+ return iTunes.getPropertyAsBoolean("Mute");
+ }
+
+ /**
+ * Returns the current player state.
+ * @return Returns the current player state.
+ */
+ public ITPlayerState getPlayerState() {
+ return ITPlayerState.values()[Dispatch.get(iTunes, "PlayerState").getInt()];
+ }
+
+ /**
+ * Sets the player's position within the currently playing track in
+ * seconds.
+ * If playerPos specifies a position before the beginning of the track,
+ * the position will be set to the beginning. If playerPos specifies a
+ * position after the end of the track, the position will be set to the
+ * end.
+ * @param playerPos The player's position within the currently playing
+ * track in seconds.
+ */
+ public void setPlayerPosition(int playerPos) {
+ iTunes.setProperty("playerPosition", playerPos);
+ }
+
+ /**
+ * Returns the player's position within the currently playing track in
+ * seconds.
+ * @return The player's position within the currently playing track in
+ * seconds.
+ */
+ public int getPlayerPosition() {
+ return iTunes.getPropertyAsInt("playerPosition");
+ }
+
+ /**
+ * Returns the source that represents the main library.
+ * You can also find the main library source by iterating over
+ * iTunes.getSources() and looking for an ITSource
+ * of kind ITSourceKindLibrary.
+ * @return Returns the source that represents the main library.
+ */
+ public ITSource getLibrarySource() {
+ Dispatch lsource = iTunes.getProperty("LibrarySource").toDispatch();
+ return new ITSource(lsource);
+ }
+
+ /**
+ * Returns the main library playlist in the main library source.
+ * @return An IITLibraryPlaylist object corresponding to the main library
+ * playlist.
+ */
+ public ITLibraryPlaylist getLibraryPlaylist() {
+ Dispatch lplaylist = iTunes.getProperty("LibraryPlaylist").toDispatch();
+ return new ITLibraryPlaylist(lplaylist);
+ }
+
+ /**
+ * Returns the currently targetd track.
+ * @return An ITTrack object corresponding to the currently targeted track.
+ * Will be set to NULL if there is no currently targeted track.
+ */
+ public ITTrack getCurrentTrack() {
+ Dispatch item = iTunes.getProperty("CurrentTrack").toDispatch();
+ ITTrack track = new ITTrack(item);
+ if (track.getKind()==ITTrackKind.ITTrackKindFile) {
+ return new ITFileOrCDTrack(item);
+ } else if (track.getKind()==ITTrackKind.ITTrackKindCD) {
+ return new ITFileOrCDTrack(item);
+ } else if (track.getKind()==ITTrackKind.ITTrackKindURL ) {
+ return new ITURLTrack(item);
+ } else {
+ return track;
+ }
+ }
+
+ /**
+ * Returns the playlist containing the currently targeted track.
+ * @return An ITPlaylist object corresponding to the playlist containing the
+ * currently targeted track.
+ * Will be set to NULL if there is no currently targeted playlist.
+ */
+ public ITPlaylist getCurrentPlaylist() {
+ Dispatch cplaylist = iTunes.getProperty("CurrentPlaylist").toDispatch();
+ ITPlaylist playlist = new ITPlaylist(cplaylist);
+ ITPlaylistKind playlistKind = playlist.getKind();
+ if (playlistKind == ITPlaylistKind.ITPlaylistKindCD)
+ return new ITAudioCDPlaylist(cplaylist);
+ else if (playlist.getKind() == ITPlaylistKind.ITPlaylistKindLibrary)
+ return new ITLibraryPlaylist(cplaylist);
+ else if (playlist.getKind() == ITPlaylistKind.ITPlaylistKindUser)
+ return new ITUserPlaylist(cplaylist);
+ else
+ return playlist;
+ }
+
+ /**
+ * Returns a collection containing the currently selected track or tracks.
+ * The frontmost visible window in iTunes must be a browser or playlist
+ * window. If there is no frontmost visible window (e.g. iTunes is minimized
+ * to the system tray), the main browser window is used.
+ * @return Collection of ITrack objects.
+ * Will be set to NULL if there is no current selection.
+ */
+ public ITTrackCollection getSelectedTracks() {
+ Dispatch stracks = iTunes.getProperty("SelectedTracks").toDispatch();
+ return new ITTrackCollection(stracks);
+ }
+
+ /**
+ * Returns the version of the iTunes application.
+ * @return
+ */
+ public String getVersion() {
+ return iTunes.getPropertyAsString("Version");
+ }
+
+ /**
+ * Returns the high 32 bits of the persistent ID of the specified IITObject.
+ * See the documentation on IITObject for more information on persistent
+ * IDs.
+ *
+ * The object may be a source, playlist, or track.
+ * @param iObject The object to fetch the High Persistent ID.
+ * @return The high 32 bits of the 64-bit persistent ID.
+ */
+ public long getITObjectPersistentIDHigh (ITObject iObject) {
+ Dispatch object = iObject.fetchDispatch();
+ return Dispatch.call(object, "GetObjectPersistentIDHigh", object).getLong();
+ }
+
+ /**
+ * Returns the low 32 bits of the persistent ID of the specified IITObject.
+ * See the documentation on IITObject for more information on persistent
+ * IDs.
+ *
+ * The object may be a source, playlist, or track.
+ * @param iObject The object to fetch the Low Persistent ID.
+ * @return The low 32 bits of the 64-bit persistent ID.
+ */
+ public long getITObjectPersistentIDLow (ITObject iObject) {
+ Dispatch object = iObject.fetchDispatch();
+ return Dispatch.call(object, "GetObjectPersistentIDLow", object).getLong();
+ }
+
+ public ITObjectPersistentID getObjectPersistentIDs(ITObject iObject){
+ return new ITObjectPersistentID(getITObjectPersistentIDHigh(iObject),getITObjectPersistentIDLow(iObject));
+ }
+
+ public ITBrowserWindow getBrowserWindow(){
+ Dispatch window = iTunes.getProperty("BrowserWindow").toDispatch();
+ return new ITBrowserWindow(window);
+ }
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/iTunesEvents.java b/vendor/iTunesController/0.2/com/dt/iTunesController/iTunesEvents.java
new file mode 100644
index 0000000..ddbee23
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/iTunesEvents.java
@@ -0,0 +1,62 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+import com.jacob.com.Variant;
+
+/**
+ * This class is used to forward all iTunes COM Events to a class that
+ * implements iTunesEventsInterface. To receive events, create
+ * a class that implements the interface, and then use
+ * iTunes.addEventHandler().
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class iTunesEvents {
+
+ private iTunesEventsInterface eventHandler;
+
+ public iTunesEvents (iTunesEventsInterface itef) {
+ eventHandler = itef;
+ }
+
+ public void OnDatabaseChangedEvent(Variant[] args) {
+ // Not currently implemented
+ }
+
+ public void OnPlayerPlayEvent(Variant[] args) {
+ ITTrack itt = new ITTrack((Dispatch)args[0].getDispatch());
+ eventHandler.onPlayerPlayEvent(itt);
+ }
+
+ public void OnPlayerStopEvent(Variant[] args) {
+ ITTrack itt = new ITTrack((Dispatch)args[0].getDispatch());
+ eventHandler.onPlayerStopEvent(itt);
+ }
+
+ public void OnPlayerPlayingTrackChangedEvent(Variant[] args) {
+ ITTrack itt = new ITTrack((Dispatch)args[0].getDispatch());
+ eventHandler.onPlayerPlayingTrackChangedEvent(itt);
+ }
+
+ public void OnCOMCallsDisabledEvent(Variant[] args) {
+ ITCOMDisabledReason reason = ITCOMDisabledReason.values()[args[0].getInt()];
+ eventHandler.onCOMCallsDisabledEvent(reason);
+ }
+
+ public void OnCOMCallsEnabledEvent(Variant[] args) {
+ eventHandler.onCOMCallsEnabledEvent();
+ }
+
+ public void OnQuittingEvent(Variant[] args) {
+ eventHandler.onQuittingEvent();
+ }
+
+ public void OnAboutToPromptUserToQuitEvent(Variant[] args) {
+ eventHandler.onAboutToPromptUserToQuitEvent();
+ }
+
+ public void OnSoundVolumeChangedEvent(Variant[] args) {
+ eventHandler.onSoundVolumeChangedEvent(args[0].getInt());
+ }
+
+}
diff --git a/vendor/iTunesController/0.2/com/dt/iTunesController/iTunesEventsInterface.java b/vendor/iTunesController/0.2/com/dt/iTunesController/iTunesEventsInterface.java
new file mode 100644
index 0000000..3d8f17e
--- /dev/null
+++ b/vendor/iTunesController/0.2/com/dt/iTunesController/iTunesEventsInterface.java
@@ -0,0 +1,115 @@
+package com.dt.iTunesController;
+
+/**
+ * Interface for receiving iTunes events.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public interface iTunesEventsInterface {
+
+ /**
+ * Not currently implemented.
+ *
+ * The ITEventDatabaseChanged event is fired when the iTunes database is
+ * changed.
+ *
+ * Each parameter is a two-dimensional array of integers. The first
+ * dimension is the number of objects. The second dimension is always 4 and
+ * specifies each of the 4 ITObject IDs, where index 0 is the source ID,
+ * index 1 is the playlist ID, index 2 is the track ID, and index 3 is the
+ * track database ID. For more information on object IDs, see
+ * ITObject.
+ *
+ * Note that you can use iTunes.getITObjectByID() to retrieve
+ * changed ITObject, but not for deleted objects (since they no longer
+ * exist).
+ *
+ * @param deletedObjectIDs
+ * @param changedObjectIDs
+ */
+ public void onDatabaseChangedEvent(int[][] deletedObjectIDs, int[][] changedObjectIDs);
+
+ /**
+ * The ITEventPlayerPlay event is fired when a track begins playing.
+ * @param iTrack An ITTrack object corresponding to the track that has
+ * started playing.
+ */
+ public void onPlayerPlayEvent (ITTrack iTrack);
+
+ /**
+ * The ITEventPlayerStop event is fired when a track stops playing.
+ * @param iTrack An ITTrack object corresponding to the track that has
+ * stopped playing.
+ */
+ public void onPlayerStopEvent (ITTrack iTrack);
+
+ /**
+ * The ITEventPlayerPlayingTrackChanged event is fired when information
+ * about the currently playing track has changed.
+ * This event is fired when the user changes information about the currently
+ * playing track (e.g. the name of the track).
+ * This event is also fired when iTunes plays the next joined CD track in a
+ * CD playlist, since joined CD tracks are treated as a single track.
+ * @param iTrack An ITTrack object corresponding to the track that is now
+ * playing.
+ */
+ public void onPlayerPlayingTrackChangedEvent(ITTrack iTrack);
+
+ /**
+ * The ITEventCOMCallsDisabled event is fired when calls to the iTunes COM
+ * interface will be deferred.
+ * Typically, iTunes will defer COM calls when any modal dialog is being
+ * displayed. When the user dismisses the last modal dialog, COM calls will
+ * be enabled again, and any deferred COM calls will be executed. You can
+ * use this event to avoid making a COM call which will be deferred.
+ * @param reason The reason the COM interface is being disabled. This is
+ * typically ITCOMDisabledReasonDialog.
+ */
+ public void onCOMCallsDisabledEvent(ITCOMDisabledReason reason);
+
+ /**
+ * The ITEventCOMCallsEnabled event is fired when calls to the iTunes COM
+ * interface will no longer be deferred.
+ * Typically, iTunes will defer COM calls when any modal dialog is being
+ * displayed. When the user dismisses the last modal dialog, COM calls will
+ * be enabled again, and any deferred COM calls will be executed.
+ */
+ public void onCOMCallsEnabledEvent();
+
+ /**
+ * The ITEventQuitting event is fired when iTunes is about to quit.
+ * If the user attempts to quit iTunes while a client still has outstanding
+ * iTunes COM objects instantiated, iTunes will display a warning dialog.
+ * The user can still choose to quit iTunes anyway, in which case this event
+ * will be fired. After this event is fired, any existing iTunes COM objects
+ * will no longer be valid.
+ * This event is only used to notify clients that iTunes is quitting,
+ * clients cannot prevent this from happening.
+ */
+ public void onQuittingEvent();
+
+ /**
+ * The ITEventAboutToPromptUserToQuit event is fired when iTunes is about
+ * prompt the user to quit.
+ * This event gives clients the opportunity to prevent the warning dialog
+ * prompt from occurring.
+ * If the user attempts to quit iTunes while a client still has outstanding
+ * iTunes COM objects instantiated, iTunes will display a warning dialog.
+ * This event is fired just before the warning dialog is shown. iTunes will
+ * then wait up to 5 seconds for clients to release any outstanding iTunes
+ * COM objects. If all objects are released during this time, the warning
+ * dialog will not be shown and iTunes will quit immediately.
+ * Otherwise, the warning dialog will be shown. If the user chooses to quit
+ * iTunes anyway, the ITEventQuitting event is fired. See
+ * iTunesEventsInterface.onQuittingEvent() for more details.
+ */
+ public void onAboutToPromptUserToQuitEvent();
+
+ /**
+ * The ITEventSoundVolumeChanged event is fired when the sound output volume
+ * has changed.
+ * @param newVolume The new sound output volume (0 = minimum, 100 = maximum).
+ */
+ public void onSoundVolumeChangedEvent(int newVolume);
+
+}
diff --git a/vendor/jacob/1.15-M4/java/com/jacob/activeX/ActiveXComponent.java b/vendor/jacob/1.15-M4/java/com/jacob/activeX/ActiveXComponent.java
new file mode 100644
index 0000000..4d0096b
--- /dev/null
+++ b/vendor/jacob/1.15-M4/java/com/jacob/activeX/ActiveXComponent.java
@@ -0,0 +1,479 @@
+/*
+ * Copyright (c) 1999-2004 Sourceforge JACOB Project.
+ * All rights reserved. Originator: Dan Adler (http://danadler.com).
+ * Get more information about JACOB at http://sourceforge.net/projects/jacob-project
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package com.jacob.activeX;
+
+import com.jacob.com.Dispatch;
+import com.jacob.com.JacobObject;
+import com.jacob.com.Variant;
+
+/**
+ * This class provides a higher level, more object like, wrapper for top of the
+ * Dispatch object. The Dispatch class's method essentially directly map to
+ * Microsoft C API including the first parameter that is almost always the
+ * target of the message. ActiveXComponent assumes the target of every message
+ * is the MS COM object behind the ActiveXComponent. This removes the need to
+ * pass the Dispatch object into every method.
+ *
+ * new ActiveXComponent("ScriptControl");
+ *
+ *
+ * @param programId
+ */
+ public ActiveXComponent(String programId) {
+ super(programId);
+ }
+
+ /**
+ * Creates an active X component that is built on top of the COM pointers
+ * held in the passed in dispatch. This widens the Dispatch object to pick
+ * up the ActiveXComponent API
+ *
+ * @param dispatchToBeWrapped
+ */
+ public ActiveXComponent(Dispatch dispatchToBeWrapped) {
+ super(dispatchToBeWrapped);
+ }
+
+ /**
+ * only used by the factories
+ *
+ */
+ private ActiveXComponent() {
+ super();
+ }
+
+ /**
+ * Probably was a cover for something else in the past. Should be
+ * deprecated.
+ *
+ * @return Now it actually returns this exact same object.
+ */
+ public Dispatch getObject() {
+ return this;
+ }
+
+ /**
+ * Most code should use the standard ActiveXComponent(String) contructor and
+ * not this factory method. This method exists for applications that need
+ * special behavior. Experimental in release 1.9.2.
+ *
+ * >ActiveXDispatchEvents de =
+ * new ActiveXDispatchEvents(someDispatch,someEventHAndler,
+ * "Excel.Application",
+ * "C:\\Program Files\\Microsoft Office\\OFFICE11\\EXCEL.EXE");
+ *
+ * @param sourceOfEvent Dispatch object who's MS app will generate callbacks
+ * @param eventSink Java object that wants to receive the events
+ * @param progId , mandatory if the typelib is specified
+ * @param typeLib The location of the typelib to use
+ *
+ */
+ public ActiveXDispatchEvents(Dispatch sourceOfEvent, Object eventSink,
+ String progId, String typeLib) {
+ super(sourceOfEvent, eventSink, progId, typeLib);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.jacob.com.DispatchEvents#getInvocationProxy(java.lang.Object)
+ */
+ protected InvocationProxy getInvocationProxy(Object pTargetObject) {
+ InvocationProxy newProxy = new ActiveXInvocationProxy();
+ newProxy.setTarget(pTargetObject);
+ return newProxy;
+ }
+
+}
diff --git a/vendor/jacob/1.15-M4/java/com/jacob/activeX/ActiveXInvocationProxy.java b/vendor/jacob/1.15-M4/java/com/jacob/activeX/ActiveXInvocationProxy.java
new file mode 100644
index 0000000..94c4f31
--- /dev/null
+++ b/vendor/jacob/1.15-M4/java/com/jacob/activeX/ActiveXInvocationProxy.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 1999-2004 Sourceforge JACOB Project.
+ * All rights reserved. Originator: Dan Adler (http://danadler.com).
+ * Get more information about JACOB at http://sourceforge.net/projects/jacob-project
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package com.jacob.activeX;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import com.jacob.com.InvocationProxy;
+import com.jacob.com.NotImplementedException;
+import com.jacob.com.Variant;
+
+/**
+ * RELEASE 1.12 EXPERIMENTAL.
+ * void eventMethodName(Object,Object...) or
+ * Object eventMethodName(Object,Object...)
+ */
+public class ActiveXInvocationProxy extends InvocationProxy {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.jacob.com.InvocationProxy#invoke(java.lang.String,
+ * com.jacob.com.Variant[])
+ */
+ @SuppressWarnings("unchecked")
+ public Variant invoke(String methodName, Variant targetParameters[]) {
+ Variant mVariantToBeReturned = null;
+ if (mTargetObject == null) {
+ // structured programming guidlines say this return should not be up
+ // here
+ return null;
+ }
+ Class targetClass = mTargetObject.getClass();
+ if (methodName == null) {
+ throw new IllegalArgumentException(
+ "InvocationProxy: missing method name");
+ }
+ if (targetParameters == null) {
+ throw new IllegalArgumentException(
+ "InvocationProxy: missing Variant parameters");
+ }
+ try {
+ Method targetMethod;
+ Object parametersAsJavaObjects[] = getParametersAsJavaObjects(targetParameters);
+ Class parametersAsJavaClasses[] = getParametersAsJavaClasses(parametersAsJavaObjects);
+ targetMethod = targetClass.getMethod(methodName,
+ parametersAsJavaClasses);
+ if (targetMethod != null) {
+ // protected classes can't be invoked against even if they
+ // let you grab the method. you could do
+ // targetMethod.setAccessible(true);
+ // but that should be stopped by the security manager
+ Object mReturnedByInvocation = null;
+ mReturnedByInvocation = targetMethod.invoke(mTargetObject,
+ parametersAsJavaObjects);
+ if (mReturnedByInvocation == null) {
+ mVariantToBeReturned = null;
+ } else if (!(mReturnedByInvocation instanceof Variant)) {
+ mVariantToBeReturned = new Variant(mReturnedByInvocation);
+ } else {
+ mVariantToBeReturned = (Variant) mReturnedByInvocation;
+ }
+ }
+ } catch (SecurityException e) {
+ // what causes this exception?
+ e.printStackTrace();
+ } catch (NoSuchMethodException e) {
+ // this happens whenever the listener doesn't implement all the
+ // methods
+ } catch (IllegalArgumentException e) {
+ // we can throw these inside the catch block so need to re-throw it
+ Exception oneWeShouldToss = new IllegalArgumentException(
+ "Unable to map parameters for method " + methodName + ": "
+ + e.toString());
+ oneWeShouldToss.printStackTrace();
+ } catch (IllegalAccessException e) {
+ // can't access the method on the target instance for some reason
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ // invocation of target method failed
+ e.printStackTrace();
+ }
+ return mVariantToBeReturned;
+
+ }
+
+ /**
+ * creates a method signature compatible array of classes from an array of
+ * parameters
+ *
+ * @param parametersAsJavaObjects
+ * @return
+ */
+ @SuppressWarnings("unchecked")
+ private Class[] getParametersAsJavaClasses(Object[] parametersAsJavaObjects) {
+ if (parametersAsJavaObjects == null) {
+ throw new IllegalArgumentException(
+ "This only works with an array of parameters");
+ }
+ int numParameters = parametersAsJavaObjects.length;
+ Class parametersAsJavaClasses[] = new Class[numParameters];
+ for (int parameterIndex = 0; parameterIndex < numParameters; parameterIndex++) {
+ Object oneParameterObject = parametersAsJavaObjects[parameterIndex];
+ if (oneParameterObject == null) {
+ parametersAsJavaClasses[parameterIndex] = null;
+ } else {
+ Class oneParameterClass = oneParameterObject.getClass();
+ parametersAsJavaClasses[parameterIndex] = oneParameterClass;
+ }
+ }
+ return parametersAsJavaClasses;
+ }
+
+ /**
+ * converts an array of Variants to their associated Java types
+ *
+ * @param targetParameters
+ * @return
+ */
+ private Object[] getParametersAsJavaObjects(Variant[] targetParameters) {
+ if (targetParameters == null) {
+ throw new IllegalArgumentException(
+ "This only works with an array of parameters");
+ }
+ int numParameters = targetParameters.length;
+ Object parametersAsJavaObjects[] = new Object[numParameters];
+ for (int parameterIndex = 0; parameterIndex < numParameters; parameterIndex++) {
+ Variant oneParameterObject = targetParameters[parameterIndex];
+ if (oneParameterObject == null) {
+ parametersAsJavaObjects[parameterIndex] = null;
+ } else {
+ try {
+ parametersAsJavaObjects[parameterIndex] = oneParameterObject
+ .toJavaObject();
+ } catch (NotImplementedException nie) {
+ throw new IllegalArgumentException(
+ "Can't convert parameter " + parameterIndex
+ + " type " + oneParameterObject.getvt()
+ + " to java object: " + nie.getMessage());
+ }
+ }
+ }
+ return parametersAsJavaObjects;
+ }
+
+}
diff --git a/vendor/jacob/1.15-M4/java/com/jacob/com/ComException.java b/vendor/jacob/1.15-M4/java/com/jacob/com/ComException.java
new file mode 100644
index 0000000..8632577
--- /dev/null
+++ b/vendor/jacob/1.15-M4/java/com/jacob/com/ComException.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 1999-2004 Sourceforge JACOB Project.
+ * All rights reserved. Originator: Dan Adler (http://danadler.com).
+ * Get more information about JACOB at http://sourceforge.net/projects/jacob-project
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package com.jacob.com;
+
+/**
+ * Standard exception thrown by com jni code when there is a problem
+ */
+public abstract class ComException extends JacobException {
+
+ /**
+ * COM code initializes this filed with an appropriate return code that was
+ * returned by the underlying com code
+ */
+ protected int hr;
+ /**
+ * No documentation is available at this time. Someone should document this
+ * field
+ */
+ protected int m_helpContext;
+ /**
+ * No documentation is available at this time. Someone should document this
+ * field
+ */
+ protected String m_helpFile;
+ /**
+ * No documentation is available at this time. Someone should document this
+ * field
+ */
+ protected String m_source;
+
+ /**
+ * constructor
+ *
+ */
+ public ComException() {
+ super();
+ }
+
+ /**
+ * constructor with error code?
+ *
+ * @param newHr ??
+ */
+ public ComException(int newHr) {
+ super();
+ this.hr = newHr;
+ }
+
+ /**
+ * @param newHr
+ * @param description
+ */
+ public ComException(int newHr, String description) {
+ super(description);
+ this.hr = newHr;
+ }
+
+ /**
+ * @param newHr
+ * @param source
+ * @param helpFile
+ * @param helpContext
+ */
+ public ComException(int newHr, String source, String helpFile,
+ int helpContext) {
+ super();
+ this.hr = newHr;
+ m_source = source;
+ m_helpFile = helpFile;
+ m_helpContext = helpContext;
+ }
+
+ /**
+ * @param newHr
+ * @param description
+ * @param source
+ * @param helpFile
+ * @param helpContext
+ */
+ public ComException(int newHr, String description, String source,
+ String helpFile, int helpContext) {
+ super(description);
+ this.hr = newHr;
+ m_source = source;
+ m_helpFile = helpFile;
+ m_helpContext = helpContext;
+ }
+
+ /**
+ * @param description
+ */
+ public ComException(String description) {
+ super(description);
+ }
+
+ /**
+ * @return int representation of the help context
+ */
+ // Methods
+ public int getHelpContext() {
+ return m_helpContext;
+ }
+
+ /**
+ * @return String ??? help file
+ */
+ public String getHelpFile() {
+ return m_helpFile;
+ }
+
+ /**
+ * @return int hr result ??
+ */
+ public int getHResult() {
+ return hr;
+ }
+
+ /**
+ * @return String source ??
+ */
+ public String getSource() {
+ return m_source;
+ }
+}
\ No newline at end of file
diff --git a/vendor/jacob/1.15-M4/java/com/jacob/com/ComFailException.java b/vendor/jacob/1.15-M4/java/com/jacob/com/ComFailException.java
new file mode 100644
index 0000000..20ce1a8
--- /dev/null
+++ b/vendor/jacob/1.15-M4/java/com/jacob/com/ComFailException.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 1999-2004 Sourceforge JACOB Project.
+ * All rights reserved. Originator: Dan Adler (http://danadler.com).
+ * Get more information about JACOB at http://sourceforge.net/projects/jacob-project
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package com.jacob.com;
+
+/**
+ * COM Fail Exception class raised when there is a problem
+ */
+public class ComFailException extends ComException {
+ /**
+ * eclipse generated to get rid of a wanring
+ */
+ private static final long serialVersionUID = -266047261992987700L;
+
+ /**
+ * Constructor
+ *
+ * @param hrNew
+ */
+ public ComFailException(int hrNew) {
+ super(hrNew);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param hrNew
+ * @param message
+ */
+ public ComFailException(int hrNew, String message) {
+ super(hrNew, message);
+ }
+
+ /**
+ * @param hrNew
+ * @param source
+ * @param helpFile
+ * @param helpContext
+ */
+ public ComFailException(int hrNew, String source, String helpFile,
+ int helpContext) {
+ super(hrNew, source, helpFile, helpContext);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param hrNew
+ * @param description
+ * @param source
+ * @param helpFile
+ * @param helpContext
+ */
+ public ComFailException(int hrNew, String description, String source,
+ String helpFile, int helpContext) {
+ super(hrNew, description, source, helpFile, helpContext);
+ }
+
+ /**
+ * No argument Constructor
+ */
+ public ComFailException() {
+ super();
+ }
+
+ /**
+ * @param message
+ */
+ public ComFailException(String message) {
+ super(message);
+ }
+}
\ No newline at end of file
diff --git a/vendor/jacob/1.15-M4/java/com/jacob/com/ComThread.java b/vendor/jacob/1.15-M4/java/com/jacob/com/ComThread.java
new file mode 100644
index 0000000..aeee598
--- /dev/null
+++ b/vendor/jacob/1.15-M4/java/com/jacob/com/ComThread.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 1999-2004 Sourceforge JACOB Project.
+ * All rights reserved. Originator: Dan Adler (http://danadler.com).
+ * Get more information about JACOB at http://sourceforge.net/projects/jacob-project
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package com.jacob.com;
+
+/**
+ * Represents a COM level thread This is an abstract class because all the
+ * methods are static and no instances are ever created.
+ */
+public abstract class ComThread {
+ private static final int MTA = 0x0;
+
+ private static final int STA = 0x2;
+
+ /**
+ * Comment for haveSTA
+ */
+ public static boolean haveSTA = false;
+
+ /**
+ * Comment for mainSTA
+ */
+ public static MainSTA mainSTA = null;
+
+ /**
+ * Initialize the current java thread to be part of the Multi-threaded COM
+ * Apartment
+ */
+ public static synchronized void InitMTA() {
+ InitMTA(false);
+ }
+
+ /**
+ * Initialize the current java thread to be an STA
+ */
+ public static synchronized void InitSTA() {
+ InitSTA(false);
+ }
+
+ /**
+ * Initialize the current java thread to be part of the Multi-threaded COM
+ * Apartment, if createMainSTA is true, create a separate MainSTA thread
+ * that will house all Apartment Threaded components
+ *
+ * @param createMainSTA
+ */
+ public static synchronized void InitMTA(boolean createMainSTA) {
+ Init(createMainSTA, MTA);
+ }
+
+ /**
+ * Initialize the current java thread to be an STA COM Apartment, if
+ * createMainSTA is true, create a separate MainSTA thread that will house
+ * all Apartment Threaded components
+ *
+ * @param createMainSTA
+ */
+ public static synchronized void InitSTA(boolean createMainSTA) {
+ Init(createMainSTA, STA);
+ }
+
+ /**
+ *
+ */
+ public static synchronized void startMainSTA() {
+ mainSTA = new MainSTA();
+ haveSTA = true;
+ }
+
+ /**
+ *
+ */
+ public static synchronized void quitMainSTA() {
+ if (mainSTA != null)
+ mainSTA.quit();
+ }
+
+ /**
+ * Initialize the current java thread to be part of the MTA/STA COM
+ * Apartment
+ *
+ * @param createMainSTA
+ * @param mode
+ */
+ public static synchronized void Init(boolean createMainSTA, int mode) {
+ if (createMainSTA && !haveSTA) {
+ // if the current thread is going to be in the MTA and there
+ // is no STA thread yet, then create a main STA thread
+ // to avoid COM creating its own
+ startMainSTA();
+ }
+ if (JacobObject.isDebugEnabled()) {
+ JacobObject.debug("ComThread: before Init: " + mode);
+ }
+ doCoInitialize(mode);
+ if (JacobObject.isDebugEnabled()) {
+ JacobObject.debug("ComThread: after Init: " + mode);
+ }
+ ROT.addThread();
+ if (JacobObject.isDebugEnabled()) {
+ JacobObject.debug("ComThread: after ROT.addThread: " + mode);
+ }
+ }
+
+ /**
+ * Call CoUninitialize to release this java thread from COM
+ */
+ public static synchronized void Release() {
+ if (JacobObject.isDebugEnabled()) {
+ JacobObject.debug("ComThread: before clearObjects");
+ }
+ ROT.clearObjects();
+ if (JacobObject.isDebugEnabled()) {
+ JacobObject.debug("ComThread: before UnInit");
+ }
+ doCoUninitialize();
+ if (JacobObject.isDebugEnabled()) {
+ JacobObject.debug("ComThread: after UnInit");
+ }
+ }
+
+ /**
+ * @deprecated the java model leave the responsibility of clearing up
+ * objects to the Garbage Collector. Our programming model
+ * should not require that the user specifically remove object
+ * from the thread.
+ *
+ * This will remove an object from the ROT
+ * @param o
+ */
+ @Deprecated
+ public static synchronized void RemoveObject(JacobObject o) {
+ ROT.removeObject(o);
+ }
+
+ /**
+ * @param threadModel
+ */
+ public static native void doCoInitialize(int threadModel);
+
+ /**
+ *
+ */
+ public static native void doCoUninitialize();
+
+ /**
+ * load the Jacob DLL. We do this in case COMThread is called before any
+ * other reference to one of the JacboObject subclasses is made.
+ */
+ static {
+ LibraryLoader.loadJacobLibrary();
+ }
+}
\ No newline at end of file
diff --git a/vendor/jacob/1.15-M4/java/com/jacob/com/Currency.java b/vendor/jacob/1.15-M4/java/com/jacob/com/Currency.java
new file mode 100644
index 0000000..749506c
--- /dev/null
+++ b/vendor/jacob/1.15-M4/java/com/jacob/com/Currency.java
@@ -0,0 +1,91 @@
+package com.jacob.com;
+
+/**
+ * Most COM bridges use java.lang.Long as their Java data type for COM Currency
+ * data. This is because COM currency is a 64 bit number where the last 4 digits
+ * represent the milli-cents. We wanted to support 64 bit Long values for x64
+ * platforms so that meant we wanted to map Java.LONG to COM.LONG even though it
+ * only works for 64 bit platforms. The end result was we needed a new
+ * representation for Money so we have this.
+ * Date javaDate = new Date(toMilliseconds (vbDate));.
+ *
+ * @param comTime
+ * COM time.
+ * @return Java time.
+ */
+ static public long convertWindowsTimeToMilliseconds(double comTime) {
+ long result = 0;
+
+ // code from jacobgen:
+ comTime = comTime - 25569D;
+ Calendar cal = Calendar.getInstance();
+ result = Math.round(86400000L * comTime)
+ - cal.get(Calendar.ZONE_OFFSET);
+ cal.setTime(new Date(result));
+ result -= cal.get(Calendar.DST_OFFSET);
+
+ return result;
+ }// convertWindowsTimeToMilliseconds()
+
+ /**
+ * converts a java date to a windows time object (is this timezone safe?)
+ *
+ * @param javaDate
+ * the java date to be converted to windows time
+ * @return the double representing the date in a form windows understands
+ */
+ static public double convertDateToWindowsTime(Date javaDate) {
+ if (javaDate == null) {
+ throw new IllegalArgumentException(
+ "cannot convert null to windows time");
+ }
+ return convertMillisecondsToWindowsTime(javaDate.getTime());
+ }
+
+ /**
+ * Convert a Java time to a COM time.
+ *
+ * @param milliseconds
+ * Java time.
+ * @return COM time.
+ */
+ static public double convertMillisecondsToWindowsTime(long milliseconds) {
+ double result = 0.0;
+
+ // code from jacobgen:
+ Calendar cal = Calendar.getInstance();
+ cal.setTimeInMillis(milliseconds);
+ milliseconds += (cal.get(Calendar.ZONE_OFFSET) + cal
+ .get(Calendar.DST_OFFSET)); // add GMT offset
+ result = (milliseconds / 86400000D) + 25569D;
+
+ return result;
+ }// convertMillisecondsToWindowsTime()
+}
diff --git a/vendor/jacob/1.15-M4/java/com/jacob/com/Dispatch.java b/vendor/jacob/1.15-M4/java/com/jacob/com/Dispatch.java
new file mode 100644
index 0000000..4902c46
--- /dev/null
+++ b/vendor/jacob/1.15-M4/java/com/jacob/com/Dispatch.java
@@ -0,0 +1,872 @@
+/*
+ * Copyright (c) 1999-2004 Sourceforge JACOB Project. All rights reserved. Originator: Dan Adler
+ * (http://danadler.com). Get more information about JACOB at
+ * http://sourceforge.net/projects/jacob-project
+ *
+ * This library is free software; you can redistribute it and/or modify it under the terms of the
+ * GNU Lesser General Public License as published by the Free Software Foundation; either version
+ * 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
+ * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with this library;
+ * if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+package com.jacob.com;
+
+/**
+ * Object represents MS level dispatch object. Each instance of this points at
+ * some data structure on the MS windows side.
+ *
+ *
+ *
+ * DispatchEvents de = new DispatchEvents(someDispatch, someEventHAndler,
+ * "Excel.Application",
+ * "C:\\Program Files\\Microsoft Office\\OFFICE11\\EXCEL.EXE");
+ *
+ *
+ * @param sourceOfEvent
+ * Dispatch object who's MS app will generate callbacks
+ * @param eventSink
+ * Java object that wants to receive the events
+ * @param progId ,
+ * mandatory if the typelib is specified
+ * @param typeLib
+ * The location of the typelib to use
+ */
+ public DispatchEvents(Dispatch sourceOfEvent, Object eventSink,
+ String progId, String typeLib) {
+ if (JacobObject.isDebugEnabled()) {
+ System.out.println("DispatchEvents: Registering " + eventSink
+ + "for events ");
+ }
+ if (eventSink instanceof InvocationProxy) {
+ mInvocationProxy = (InvocationProxy) eventSink;
+ } else {
+ mInvocationProxy = getInvocationProxy(eventSink);
+ }
+ if (mInvocationProxy != null) {
+ init3(sourceOfEvent, mInvocationProxy, progId, typeLib);
+ } else {
+ if (JacobObject.isDebugEnabled()) {
+ JacobObject.debug("Cannot register null event sink for events");
+ }
+ throw new IllegalArgumentException(
+ "Cannot register null event sink for events");
+ }
+ }
+
+ /**
+ * Returns an instance of the proxy configured with pTargetObject as its
+ * target
+ *
+ * @param pTargetObject
+ * @return InvocationProxy an instance of the proxy this DispatchEvents will
+ * send to the COM layer
+ */
+ protected InvocationProxy getInvocationProxy(Object pTargetObject) {
+ InvocationProxy newProxy = new InvocationProxyAllVariants();
+ newProxy.setTarget(pTargetObject);
+ return newProxy;
+ }
+
+ /**
+ * hooks up a connection point proxy by progId event methods on the sink
+ * object will be called by name with a signature of m_pStream
+ */
+ public int m_pStream;
+
+ /**
+ * Marshals the passed in dispatch into the stream
+ *
+ * @param localDispatch
+ */
+ public DispatchProxy(Dispatch localDispatch) {
+ MarshalIntoStream(localDispatch);
+ }
+
+ /**
+ *
+ * @return Dispatch the dispatch retrieved from the stream
+ */
+ public Dispatch toDispatch() {
+ return MarshalFromStream();
+ }
+
+ private native void MarshalIntoStream(Dispatch d);
+
+ private native Dispatch MarshalFromStream();
+
+ /**
+ * now private so only this object can access was: call this to explicitly
+ * release the com object before gc
+ *
+ */
+ private native void release();
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#finalize()
+ */
+ public void finalize() {
+ safeRelease();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.jacob.com.JacobObject#safeRelease()
+ */
+ public void safeRelease() {
+ super.safeRelease();
+ if (m_pStream != 0) {
+ release();
+ m_pStream = 0;
+ } else {
+ // looks like a double release
+ if (isDebugEnabled()) {
+ debug(this.getClass().getName() + ":" + this.hashCode()
+ + " double release");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/vendor/jacob/1.15-M4/java/com/jacob/com/EnumVariant.java b/vendor/jacob/1.15-M4/java/com/jacob/com/EnumVariant.java
new file mode 100644
index 0000000..8ff298f
--- /dev/null
+++ b/vendor/jacob/1.15-M4/java/com/jacob/com/EnumVariant.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 1999-2004 Sourceforge JACOB Project.
+ * All rights reserved. Originator: Dan Adler (http://danadler.com).
+ * Get more information about JACOB at http://sourceforge.net/projects/jacob-project
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package com.jacob.com;
+
+/**
+ * An implementation of IEnumVariant based on code submitted by Thomas Hallgren
+ * (mailto:Thomas.Hallgren@eoncompany.com)
+ */
+public class EnumVariant extends JacobObject implements
+ java.util.Enumeration void eventMethodName(Variant[]) or
+ * Variant eventMethodName(Variant[])
+ */
+public class InvocationProxyAllVariants extends InvocationProxy {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.jacob.com.InvocationProxy#invoke(java.lang.String,
+ * com.jacob.com.Variant[])
+ */
+ @SuppressWarnings("unchecked")
+ public Variant invoke(String methodName, Variant targetParameters[]) {
+ Variant mVariantToBeReturned = null;
+ if (mTargetObject == null) {
+ if (JacobObject.isDebugEnabled()) {
+ JacobObject.debug("InvocationProxy: received notification ("
+ + methodName + ") with no target set");
+ }
+ // structured programming guidlines say this return should not be up
+ // here
+ return null;
+ }
+ Class targetClass = mTargetObject.getClass();
+ if (methodName == null) {
+ throw new IllegalArgumentException(
+ "InvocationProxy: missing method name");
+ }
+ if (targetParameters == null) {
+ throw new IllegalArgumentException(
+ "InvocationProxy: missing Variant parameters");
+ }
+ try {
+ if (JacobObject.isDebugEnabled()) {
+ JacobObject.debug("InvocationProxy: trying to invoke "
+ + methodName + " on " + mTargetObject);
+ }
+ Method targetMethod;
+ targetMethod = targetClass.getMethod(methodName,
+ new Class[] { Variant[].class });
+ if (targetMethod != null) {
+ // protected classes can't be invoked against even if they
+ // let you grab the method. you could do
+ // targetMethod.setAccessible(true);
+ // but that should be stopped by the security manager
+ Object mReturnedByInvocation = null;
+ mReturnedByInvocation = targetMethod.invoke(mTargetObject,
+ new Object[] { targetParameters });
+ if (mReturnedByInvocation == null) {
+ mVariantToBeReturned = null;
+ } else if (!(mReturnedByInvocation instanceof Variant)) {
+ // could try and convert to Variant here.
+ throw new IllegalArgumentException(
+ "InvocationProxy: invokation of target method returned "
+ + "non-null non-variant object: "
+ + mReturnedByInvocation);
+ } else {
+ mVariantToBeReturned = (Variant) mReturnedByInvocation;
+ }
+ }
+ } catch (SecurityException e) {
+ // what causes this exception?
+ e.printStackTrace();
+ } catch (NoSuchMethodException e) {
+ // this happens whenever the listener doesn't implement all the
+ // methods
+ if (JacobObject.isDebugEnabled()) {
+ JacobObject.debug("InvocationProxy: listener (" + mTargetObject
+ + ") doesn't implement " + methodName);
+ }
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ // we can throw these inside the catch block so need to re-throw it
+ throw e;
+ } catch (IllegalAccessException e) {
+ // can't access the method on the target instance for some reason
+ if (JacobObject.isDebugEnabled()) {
+ JacobObject
+ .debug("InvocationProxy: probably tried to access public method on non public class"
+ + methodName);
+ }
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ // invocation of target method failed
+ e.printStackTrace();
+ }
+ return mVariantToBeReturned;
+
+ }
+}
diff --git a/vendor/jacob/1.15-M4/java/com/jacob/com/JacobException.java b/vendor/jacob/1.15-M4/java/com/jacob/com/JacobException.java
new file mode 100644
index 0000000..6e2e926
--- /dev/null
+++ b/vendor/jacob/1.15-M4/java/com/jacob/com/JacobException.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1999-2004 Sourceforge JACOB Project.
+ * All rights reserved. Originator: Dan Adler (http://danadler.com).
+ * Get more information about JACOB at http://sourceforge.net/projects/jacob-project
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package com.jacob.com;
+
+/**
+ * The parent class of all Jacob exceptions. They all used to be based off of
+ * RuntimeException or ComException but it was decided to base them all off of
+ * one owned by this project.
+ */
+public class JacobException extends RuntimeException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -1637125318746002715L;
+
+ /**
+ * Default constructor. Calls super with a "No Message Provided" string
+ */
+ public JacobException() {
+ super("No Message Provided");
+ }
+
+ /**
+ * standard constructor
+ *
+ * @param message
+ */
+ public JacobException(String message) {
+ super(message);
+ }
+}
diff --git a/vendor/jacob/1.15-M4/java/com/jacob/com/JacobObject.java b/vendor/jacob/1.15-M4/java/com/jacob/com/JacobObject.java
new file mode 100644
index 0000000..acd346c
--- /dev/null
+++ b/vendor/jacob/1.15-M4/java/com/jacob/com/JacobObject.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 1999-2004 Sourceforge JACOB Project.
+ * All rights reserved. Originator: Dan Adler (http://danadler.com).
+ * Get more information about JACOB at http://sourceforge.net/projects/jacob-project
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+package com.jacob.com;
+
+/**
+ * The superclass of all Jacob objects. It is used to create a standard API
+ * framework and to facilitate memory management for Java and COM memory
+ * elements.
+ *
+ *
+ *
+ * The standard behavior for most applications is that {@code LoadLibrary()}
+ * will be called to load the dll. {@code LoadLibary()} searches directories
+ * specified in the variable {@code java.library.path}. This is why most test
+ * cases specify -Djava.library.path in their command line arguments.
+ *
+ * JACOB_DLL_NAME, JACOB_DLL_NAME_32, JACOB_DLL_NAME_64 submitted sourceforge
+ * ticket 1845039 Added 1.14M7
+ *
+ * @author Scott Dickerson (sjd78)
+ * @author Jason Smith
+ */
+public final class LibraryLoader {
+ /**
+ * Name of system property (currently jacob.dll.path) that may
+ * contain an absolute path to the JNI library.
+ */
+ public static final String JACOB_DLL_PATH = "jacob.dll.path";
+
+ /**
+ * Name of system property (currently jacob.dll.name) that may
+ * contain an alternate name for the JNI library (default is 'jacob').
+ */
+ public static final String JACOB_DLL_NAME = "jacob.dll.name";
+
+ /**
+ * Name of system property (currently jacob.dll.name) that may
+ * contain an alternate name for the JNI library (default is 'jacob'), 32
+ * bit windows.
+ */
+ public static final String JACOB_DLL_NAME_X86 = "jacob.dll.name.x86";
+
+ /**
+ * Name of system property (currently jacob.dll.name) that may
+ * contain an alternate name for the JNI library (default is 'jacob'), 64
+ * bit windows.
+ */
+ public static final String JACOB_DLL_NAME_X64 = "jacob.dll.name.x64";
+
+ /**
+ * Appended to "jacob" when building DLL name This string must EXACTLY match
+ * the string in the build.xml file
+ */
+ public static final String DLL_NAME_MODIFIER_32_BIT = "x86";
+ /**
+ * Appended to "jacob" when building DLL name This string must EXACTLY match
+ * the string in the build.xml file
+ */
+ public static final String DLL_NAME_MODIFIER_64_BIT = "x64";
+
+ /**
+ * Load the jacob dll either from an absolute path or by a library name,
+ * both of which may be defined in various ways.
+ *
+ * @throws UnsatisfiedLinkError
+ * if the library does not exist.
+ */
+ public static void loadJacobLibrary() {
+ // In some cases, a library that uses Jacob won't be able to set system
+ // properties
+ // prior to Jacob being loaded. The resource bundle provides an
+ // alternate way to
+ // override DLL name or path that will be loaded with Jacob regardless
+ // of other
+ // initialization order.
+ ResourceBundle resources = null;
+ Set
+ * This will remove an object from the ROT
+ * This does not need to be synchronized because only the rot
+ * modification related methods need to synchronized. Each
+ * individual map is only modified in a single thread.
+ * @param o
+ */
+ @Deprecated
+ protected static void removeObject(JacobObject o) {
+ Map
+ * new Variant(objectToBeWrapped) is called and the
+ * result is passed into the com layer
+ * @throws IllegalArgumentException
+ * if inVariant = null or if inVariant is a Varint
+ */
+ public void putVariant(Object objectToBeWrapped) {
+ if (objectToBeWrapped == null) {
+ throw new IllegalArgumentException(
+ "Cannot put null in as a variant");
+ } else if (objectToBeWrapped instanceof Variant) {
+ throw new IllegalArgumentException(
+ "Cannot putVariant() only accepts non jacob objects.");
+ } else {
+ Variant inVariant = new Variant(objectToBeWrapped);
+ putVariantVariant(inVariant);
+ // This could be done in Variant.cpp
+ if (JacobObject.isDebugEnabled()) {
+ JacobObject
+ .debug("Zeroing out enclosed Variant's ref to windows memory");
+ }
+ inVariant.m_pVariant = 0;
+ }
+ }
+
+ /**
+ * @deprecated superseded by SafeArray
+ * @param in
+ * doesn't matter because this method does nothing
+ * @throws com.jacob.com.NotImplementedException
+ */
+ @Deprecated
+ public void putVariantArray(Variant[] in) {
+ throw new NotImplementedException("Not implemented");
+ }
+
+ /**
+ * @param in
+ * the thing that would be come an array if this method was
+ * implemented
+ * @deprecated superseded by SafeArray
+ * @throws com.jacob.com.NotImplementedException
+ */
+ @Deprecated
+ public void putVariantArrayRef(Variant[] in) {
+ throw new NotImplementedException("Not implemented");
+ }
+
+ /**
+ * puts a boolean into the variant and sets it's type
+ *
+ * @param in
+ * the new value
+ */
+ private native void putVariantBoolean(boolean in);
+
+ /**
+ * puts a boolean into the variant and sets it's type
+ *
+ * @param in
+ * the new value
+ */
+ private native void putVariantBooleanRef(boolean in);
+
+ /**
+ * puts a byte into the variant and sets it's type
+ *
+ * @param in
+ * the new value
+ */
+ private native void putVariantByte(byte in);
+
+ /**
+ * puts a byte into the variant and sets it's type
+ *
+ * @param in
+ * the new value
+ */
+ private native void putVariantByteRef(byte in);
+
+ /**
+ * puts a Currency into the variant and sets it's type
+ *
+ * @param in
+ * the new value
+ */
+ private native void putVariantCurrency(long in);
+
+ /**
+ * puts a Currency into the variant and sets it's type
+ *
+ * @param in
+ * the new value
+ */
+ private native void putVariantCurrencyRef(long in);
+
+ /**
+ * set the value of this variant
+ *
+ * @param in
+ */
+ private native void putVariantDate(double in);
+
+ /**
+ * set the content of this variant to a date (VT_DATE|VT_BYREF)
+ *
+ * @param in
+ */
+ private native void putVariantDateRef(double in);
+
+ /**
+ * private JNI method called by putDecimal
+ *
+ * @param signum
+ * sign
+ * @param scale
+ * BigDecimal's scale
+ * @param lo
+ * low 32 bits
+ * @param mid
+ * middle 32 bits
+ * @param hi
+ * high 32 bits
+ */
+ private native void putVariantDec(int signum, byte scale, int lo, int mid,
+ int hi);
+
+ /**
+ * private JNI method called by putDecimalRef
+ *
+ * @param signum
+ * sign
+ * @param scale
+ * BigDecimal's scale
+ * @param lo
+ * low 32 bits
+ * @param mid
+ * middle 32 bits
+ * @param hi
+ * high 32 bits
+ */
+ private native void putVariantDecRef(int signum, byte scale, int lo,
+ int mid, int hi);
+
+ /**
+ * the JNI implementation for putDispatch() so that we can screen the
+ * incoming dispatches in putDispatch() before this is invoked
+ *
+ * @param in
+ * should be a dispatch object
+ */
+ private native void putVariantDispatch(Object in);
+
+ private native void putVariantDouble(double in);
+
+ /**
+ * set the content of this variant to a double (VT_R8|VT_BYREF)
+ *
+ * @param in
+ */
+ private native void putVariantDoubleRef(double in);
+
+ /**
+ * Sets the type to VariantEmpty. No values needed
+ */
+ private native void putVariantEmpty();
+
+ private native void putVariantError(int in);
+
+ private native void putVariantErrorRef(int in);
+
+ /**
+ * fills the Variant with a float and sets the type to float
+ *
+ * @param in
+ */
+ private native void putVariantFloat(float in);
+
+ private native void putVariantFloatRef(float in);
+
+ /**
+ * set the value of this variant and set the type
+ *
+ * @param in
+ */
+ private native void putVariantInt(int in);
+
+ /**
+ * set the content of this variant to an int (VT_I4|VT_BYREF)
+ *
+ * @param in
+ */
+ private native void putVariantIntRef(int in);
+
+ private native void putVariantLong(long in);
+
+ private native void putVariantLongRef(long in);
+
+ /**
+ * sets the type to VT_ERROR and the error message to DISP_E_PARAMNOTFOIUND
+ */
+ private native void putVariantNoParam();
+
+ /**
+ * Sets the type to VariantDispatch and sets the value to null Equivalent to
+ * VB's nothing
+ */
+ private native void putVariantNothing();
+
+ /**
+ * Set this Variant's type to VT_NULL (the VB equivalent of NULL)
+ */
+ private native void putVariantNull();
+
+ private native void putVariantSafeArray(SafeArray in);
+
+ private native void putVariantSafeArrayRef(SafeArray in);
+
+ /**
+ * set the content of this variant to a short (VT_I2)
+ *
+ * @param in
+ */
+ private native void putVariantShort(short in);
+
+ /**
+ * set the content of this variant to a short (VT_I2|VT_BYREF)
+ *
+ * @param in
+ */
+ private native void putVariantShortRef(short in);
+
+ private native void putVariantString(String in);
+
+ /**
+ * set the content of this variant to a string (VT_BSTR|VT_BYREF)
+ *
+ * @param in
+ */
+ private native void putVariantStringRef(String in);
+
+ /**
+ * All VariantVariant type variants are BYREF.
+ *
+ * Set the content of this variant to a string (VT_VARIANT|VT_BYREF).
+ *
+ * Added 1.12 pre 6 - VT_VARIANT support is at an alpha level
+ *
+ * @param in
+ * variant to be wrapped
+ *
+ */
+ private native void putVariantVariant(Variant in);
+
+ /**
+ * now private so only this object can access was: call this to explicitly
+ * release the com object before gc
+ *
+ */
+ private native void release();
+
+ /**
+ * This will release the "C" memory for the Variant unless this Variant is
+ * one of the constants in which case we don't want to release the memory.
+ *
+ *
+ */
+ protected void initLine() throws LineUnavailableException
+ {
+ log.info("initLine()");
+ if (m_line == null) createLine();
+ if (!m_line.isOpen())
+ {
+ openLine();
+ }
+ else
+ {
+ AudioFormat lineAudioFormat = m_line.getFormat();
+ AudioFormat audioInputStreamFormat = m_audioInputStream == null ? null : m_audioInputStream.getFormat();
+ if (!lineAudioFormat.equals(audioInputStreamFormat))
+ {
+ m_line.close();
+ openLine();
+ }
+ }
+ }
+
+ /**
+ * Inits a DateLine.
+ *
+ * We check if the line supports Gain and Pan controls.
+ *
+ * From the AudioInputStream, i.e. from the sound file, we
+ * fetch information about the format of the audio data. These
+ * information include the sampling frequency, the number of
+ * channels and the size of the samples. There information
+ * are needed to ask JavaSound for a suitable output line
+ * for this audio file.
+ * Furthermore, we have to give JavaSound a hint about how
+ * big the internal buffer for the line should be. Here,
+ * we say AudioSystem.NOT_SPECIFIED, signaling that we don't
+ * care about the exact size. JavaSound will use some default
+ * value for the buffer size.
+ */
+ protected void createLine() throws LineUnavailableException
+ {
+ log.info("Create Line");
+ if (m_line == null)
+ {
+ AudioFormat sourceFormat = m_audioInputStream.getFormat();
+ log.info("Create Line : Source format : " + sourceFormat.toString());
+ int nSampleSizeInBits = sourceFormat.getSampleSizeInBits();
+ if (nSampleSizeInBits <= 0) nSampleSizeInBits = 16;
+ if ((sourceFormat.getEncoding() == AudioFormat.Encoding.ULAW) || (sourceFormat.getEncoding() == AudioFormat.Encoding.ALAW)) nSampleSizeInBits = 16;
+ if (nSampleSizeInBits != 8) nSampleSizeInBits = 16;
+ AudioFormat targetFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, sourceFormat.getSampleRate(), nSampleSizeInBits, sourceFormat.getChannels(), sourceFormat.getChannels() * (nSampleSizeInBits / 8), sourceFormat.getSampleRate(), false);
+ log.info("Create Line : Target format: " + targetFormat);
+ // Keep a reference on encoded stream to progress notification.
+ m_encodedaudioInputStream = m_audioInputStream;
+ try
+ {
+ // Get total length in bytes of the encoded stream.
+ encodedLength = m_encodedaudioInputStream.available();
+ }
+ catch (IOException e)
+ {
+ log.error("Cannot get m_encodedaudioInputStream.available()", e);
+ }
+ // Create decoded stream.
+ m_audioInputStream = AudioSystem.getAudioInputStream(targetFormat, m_audioInputStream);
+ AudioFormat audioFormat = m_audioInputStream.getFormat();
+ DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat, AudioSystem.NOT_SPECIFIED);
+ Mixer mixer = getMixer(m_mixerName);
+ if (mixer != null)
+ {
+ log.info("Mixer : "+mixer.getMixerInfo().toString());
+ m_line = (SourceDataLine) mixer.getLine(info);
+ }
+ else
+ {
+ m_line = (SourceDataLine) AudioSystem.getLine(info);
+ m_mixerName = null;
+ }
+ log.info("Line : " + m_line.toString());
+ log.debug("Line Info : " + m_line.getLineInfo().toString());
+ log.debug("Line AudioFormat: " + m_line.getFormat().toString());
+ }
+ }
+
+ /**
+ * Opens the line.
+ */
+ protected void openLine() throws LineUnavailableException
+ {
+ if (m_line != null)
+ {
+ AudioFormat audioFormat = m_audioInputStream.getFormat();
+ int buffersize = lineBufferSize;
+ if (buffersize <= 0) buffersize = m_line.getBufferSize();
+ m_lineCurrentBufferSize = buffersize;
+ m_line.open(audioFormat, buffersize);
+ log.info("Open Line : BufferSize=" + buffersize);
+ /*-- Display supported controls --*/
+ Control[] c = m_line.getControls();
+ for (int p = 0; p < c.length; p++)
+ {
+ log.debug("Controls : " + c[p].toString());
+ }
+ /*-- Is Gain Control supported ? --*/
+ if (m_line.isControlSupported(FloatControl.Type.MASTER_GAIN))
+ {
+ m_gainControl = (FloatControl) m_line.getControl(FloatControl.Type.MASTER_GAIN);
+ log.info("Master Gain Control : [" + m_gainControl.getMinimum() + "," + m_gainControl.getMaximum() + "] " + m_gainControl.getPrecision());
+ }
+ /*-- Is Pan control supported ? --*/
+ if (m_line.isControlSupported(FloatControl.Type.PAN))
+ {
+ m_panControl = (FloatControl) m_line.getControl(FloatControl.Type.PAN);
+ log.info("Pan Control : [" + m_panControl.getMinimum() + "," + m_panControl.getMaximum() + "] " + m_panControl.getPrecision());
+ }
+ }
+ }
+
+ /**
+ * Stops the playback.
+ *
+ * Player Status = STOPPED.
+ * Thread should free Audio ressources.
+ */
+ protected void stopPlayback()
+ {
+ if ((m_status == PLAYING) || (m_status == PAUSED))
+ {
+ if (m_line != null)
+ {
+ m_line.flush();
+ m_line.stop();
+ }
+ m_status = STOPPED;
+ notifyEvent(BasicPlayerEvent.STOPPED, getEncodedStreamPosition(), -1, null);
+ synchronized (m_audioInputStream)
+ {
+ closeStream();
+ }
+ log.info("stopPlayback() completed");
+ }
+ }
+
+ /**
+ * Pauses the playback.
+ *
+ * Player Status = PAUSED.
+ */
+ protected void pausePlayback()
+ {
+ if (m_line != null)
+ {
+ if (m_status == PLAYING)
+ {
+ m_line.flush();
+ m_line.stop();
+ m_status = PAUSED;
+ log.info("pausePlayback() completed");
+ notifyEvent(BasicPlayerEvent.PAUSED, getEncodedStreamPosition(), -1, null);
+ }
+ }
+ }
+
+ /**
+ * Resumes the playback.
+ *
+ * Player Status = PLAYING.
+ */
+ protected void resumePlayback()
+ {
+ if (m_line != null)
+ {
+ if (m_status == PAUSED)
+ {
+ m_line.start();
+ m_status = PLAYING;
+ log.info("resumePlayback() completed");
+ notifyEvent(BasicPlayerEvent.RESUMED, getEncodedStreamPosition(), -1, null);
+ }
+ }
+ }
+
+ /**
+ * Starts playback.
+ */
+ protected void startPlayback() throws BasicPlayerException
+ {
+ if (m_status == STOPPED) initAudioInputStream();
+ if (m_status == OPENED)
+ {
+ log.info("startPlayback called");
+ if (!(m_thread == null || !m_thread.isAlive()))
+ {
+ log.info("WARNING: old thread still running!!");
+ int cnt = 0;
+ while (m_status != OPENED)
+ {
+ try
+ {
+ if (m_thread != null)
+ {
+ log.info("Waiting ... " + cnt);
+ cnt++;
+ Thread.sleep(1000);
+ if (cnt > 2)
+ {
+ m_thread.interrupt();
+ }
+ }
+ }
+ catch (InterruptedException e)
+ {
+ throw new BasicPlayerException(BasicPlayerException.WAITERROR, e);
+ }
+ }
+ }
+ // Open SourceDataLine.
+ try
+ {
+ initLine();
+ }
+ catch (LineUnavailableException e)
+ {
+ throw new BasicPlayerException(BasicPlayerException.CANNOTINITLINE, e);
+ }
+ log.info("Creating new thread");
+ m_thread = new Thread(this, "BasicPlayer");
+ m_thread.start();
+ if (m_line != null)
+ {
+ m_line.start();
+ m_status = PLAYING;
+ notifyEvent(BasicPlayerEvent.PLAYING, getEncodedStreamPosition(), -1, null);
+ }
+ }
+ }
+
+ /**
+ * Main loop.
+ *
+ * Player Status == STOPPED || SEEKING => End of Thread + Freeing Audio Ressources.
+ * Player Status == PLAYING => Audio stream data sent to Audio line.
+ * Player Status == PAUSED => Waiting for another status.
+ */
+ public void run()
+ {
+ log.info("Thread Running");
+ int nBytesRead = 1;
+ byte[] abData = new byte[EXTERNAL_BUFFER_SIZE];
+ // Lock stream while playing.
+ synchronized (m_audioInputStream)
+ {
+ // Main play/pause loop.
+ while ((nBytesRead != -1) && (m_status != STOPPED) && (m_status != SEEKING) && (m_status != UNKNOWN))
+ {
+ if (m_status == PLAYING)
+ {
+ // Play.
+ try
+ {
+ nBytesRead = m_audioInputStream.read(abData, 0, abData.length);
+ if (nBytesRead >= 0)
+ {
+ byte[] pcm = new byte[nBytesRead];
+ System.arraycopy(abData, 0, pcm, 0, nBytesRead);
+ if (m_line.available() >= m_line.getBufferSize()) log.debug("Underrun : "+m_line.available()+"/"+m_line.getBufferSize());
+ int nBytesWritten = m_line.write(abData, 0, nBytesRead);
+ // Compute position in bytes in encoded stream.
+ int nEncodedBytes = getEncodedStreamPosition();
+ // Notify listeners
+ Iterator it = m_listeners.iterator();
+ while (it.hasNext())
+ {
+ BasicPlayerListener bpl = (BasicPlayerListener) it.next();
+ if (m_audioInputStream instanceof PropertiesContainer)
+ {
+ // Pass audio parameters such as instant bitrate, ...
+ Map properties = ((PropertiesContainer) m_audioInputStream).properties();
+ bpl.progress(nEncodedBytes, m_line.getMicrosecondPosition(), pcm, properties);
+ }
+ else bpl.progress(nEncodedBytes, m_line.getMicrosecondPosition(), pcm, empty_map);
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ log.error("Thread cannot run()", e);
+ m_status = STOPPED;
+ notifyEvent(BasicPlayerEvent.STOPPED, getEncodedStreamPosition(), -1, null);
+ }
+ // Nice CPU usage.
+ if (threadSleep > 0)
+ {
+ try
+ {
+ Thread.sleep(threadSleep);
+ }
+ catch (InterruptedException e)
+ {
+ log.error("Thread cannot sleep(" + threadSleep + ")", e);
+ }
+ }
+ }
+ else
+ {
+ // Pause
+ try
+ {
+ Thread.sleep(1000);
+ }
+ catch (InterruptedException e)
+ {
+ log.error("Thread cannot sleep(1000)", e);
+ }
+ }
+ }
+ // Free audio resources.
+ if (m_line != null)
+ {
+ m_line.drain();
+ m_line.stop();
+ m_line.close();
+ m_line = null;
+ }
+ // Notification of "End Of Media"
+ if (nBytesRead == -1)
+ {
+ notifyEvent(BasicPlayerEvent.EOM, getEncodedStreamPosition(), -1, null);
+ }
+ // Close stream.
+ closeStream();
+ }
+ m_status = STOPPED;
+ notifyEvent(BasicPlayerEvent.STOPPED, getEncodedStreamPosition(), -1, null);
+ log.info("Thread completed");
+ }
+
+ /**
+ * Skip bytes in the File inputstream.
+ * It will skip N frames matching to bytes, so it will never skip given bytes length exactly.
+ * @param bytes
+ * @return value>0 for File and value=0 for URL and InputStream
+ * @throws BasicPlayerException
+ */
+ protected long skipBytes(long bytes) throws BasicPlayerException
+ {
+ long totalSkipped = 0;
+ if (m_dataSource instanceof File)
+ {
+ log.info("Bytes to skip : " + bytes);
+ int previousStatus = m_status;
+ m_status = SEEKING;
+ long skipped = 0;
+ try
+ {
+ synchronized (m_audioInputStream)
+ {
+ notifyEvent(BasicPlayerEvent.SEEKING, getEncodedStreamPosition(), -1, null);
+ initAudioInputStream();
+ if (m_audioInputStream != null)
+ {
+ // Loop until bytes are really skipped.
+ while (totalSkipped < (bytes - SKIP_INACCURACY_SIZE))
+ {
+ skipped = m_audioInputStream.skip(bytes - totalSkipped);
+ if (skipped == 0) break;
+ totalSkipped = totalSkipped + skipped;
+ log.info("Skipped : " + totalSkipped + "/" + bytes);
+ if (totalSkipped == -1) throw new BasicPlayerException(BasicPlayerException.SKIPNOTSUPPORTED);
+ }
+ }
+ }
+ notifyEvent(BasicPlayerEvent.SEEKED, getEncodedStreamPosition(), -1, null);
+ m_status = OPENED;
+ if (previousStatus == PLAYING) startPlayback();
+ else if (previousStatus == PAUSED)
+ {
+ startPlayback();
+ pausePlayback();
+ }
+ }
+ catch (IOException e)
+ {
+ throw new BasicPlayerException(e);
+ }
+ }
+ return totalSkipped;
+ }
+
+ /**
+ * Notify listeners about a BasicPlayerEvent.
+ * @param code event code.
+ * @param position in the stream when the event occurs.
+ */
+ protected void notifyEvent(int code, int position, double value, Object description)
+ {
+ BasicPlayerEventLauncher trigger = new BasicPlayerEventLauncher(code, position, value, description, new ArrayList(m_listeners), this);
+ trigger.start();
+ }
+
+ protected int getEncodedStreamPosition()
+ {
+ int nEncodedBytes = -1;
+ if (m_dataSource instanceof File)
+ {
+ try
+ {
+ if (m_encodedaudioInputStream != null)
+ {
+ nEncodedBytes = encodedLength - m_encodedaudioInputStream.available();
+ }
+ }
+ catch (IOException e)
+ {
+ //log.debug("Cannot get m_encodedaudioInputStream.available()",e);
+ }
+ }
+ return nEncodedBytes;
+ }
+
+ protected void closeStream()
+ {
+ // Close stream.
+ try
+ {
+ if (m_audioInputStream != null)
+ {
+ m_audioInputStream.close();
+ log.info("Stream closed");
+ }
+ }
+ catch (IOException e)
+ {
+ log.info("Cannot close stream", e);
+ }
+ }
+
+ /**
+ * Returns true if Gain control is supported.
+ */
+ public boolean hasGainControl()
+ {
+ if (m_gainControl == null)
+ {
+ // Try to get Gain control again (to support J2SE 1.5)
+ if ( (m_line != null) && (m_line.isControlSupported(FloatControl.Type.MASTER_GAIN))) m_gainControl = (FloatControl) m_line.getControl(FloatControl.Type.MASTER_GAIN);
+ }
+ return m_gainControl != null;
+ }
+
+ /**
+ * Returns Gain value.
+ */
+ public float getGainValue()
+ {
+ if (hasGainControl())
+ {
+ return m_gainControl.getValue();
+ }
+ else
+ {
+ return 0.0F;
+ }
+ }
+
+ /**
+ * Gets max Gain value.
+ */
+ public float getMaximumGain()
+ {
+ if (hasGainControl())
+ {
+ return m_gainControl.getMaximum();
+ }
+ else
+ {
+ return 0.0F;
+ }
+ }
+
+ /**
+ * Gets min Gain value.
+ */
+ public float getMinimumGain()
+ {
+ if (hasGainControl())
+ {
+ return m_gainControl.getMinimum();
+ }
+ else
+ {
+ return 0.0F;
+ }
+ }
+
+ /**
+ * Returns true if Pan control is supported.
+ */
+ public boolean hasPanControl()
+ {
+ if (m_panControl == null)
+ {
+ // Try to get Pan control again (to support J2SE 1.5)
+ if ((m_line != null)&& (m_line.isControlSupported(FloatControl.Type.PAN))) m_panControl = (FloatControl) m_line.getControl(FloatControl.Type.PAN);
+ }
+ return m_panControl != null;
+ }
+
+ /**
+ * Returns Pan precision.
+ */
+ public float getPrecision()
+ {
+ if (hasPanControl())
+ {
+ return m_panControl.getPrecision();
+ }
+ else
+ {
+ return 0.0F;
+ }
+ }
+
+ /**
+ * Returns Pan value.
+ */
+ public float getPan()
+ {
+ if (hasPanControl())
+ {
+ return m_panControl.getValue();
+ }
+ else
+ {
+ return 0.0F;
+ }
+ }
+
+ /**
+ * Deep copy of a Map.
+ * @param src
+ * @return
+ */
+ protected Map deepCopy(Map src)
+ {
+ HashMap map = new HashMap();
+ if (src != null)
+ {
+ Iterator it = src.keySet().iterator();
+ while (it.hasNext())
+ {
+ Object key = it.next();
+ Object value = src.get(key);
+ map.put(key, value);
+ }
+ }
+ return map;
+ }
+
+ /**
+ * @see javazoom.jlgui.basicplayer.BasicController#seek(long)
+ */
+ public long seek(long bytes) throws BasicPlayerException
+ {
+ return skipBytes(bytes);
+ }
+
+ /**
+ * @see javazoom.jlgui.basicplayer.BasicController#play()
+ */
+ public void play() throws BasicPlayerException
+ {
+ startPlayback();
+ }
+
+ /**
+ * @see javazoom.jlgui.basicplayer.BasicController#stop()
+ */
+ public void stop() throws BasicPlayerException
+ {
+ stopPlayback();
+ }
+
+ /**
+ * @see javazoom.jlgui.basicplayer.BasicController#pause()
+ */
+ public void pause() throws BasicPlayerException
+ {
+ pausePlayback();
+ }
+
+ /**
+ * @see javazoom.jlgui.basicplayer.BasicController#resume()
+ */
+ public void resume() throws BasicPlayerException
+ {
+ resumePlayback();
+ }
+
+ /**
+ * Sets Pan value.
+ * Line should be opened before calling this method.
+ * Linear scale : -1.0 <--> +1.0
+ */
+ public void setPan(double fPan) throws BasicPlayerException
+ {
+ if (hasPanControl())
+ {
+ log.debug("Pan : " + fPan);
+ m_panControl.setValue((float) fPan);
+ notifyEvent(BasicPlayerEvent.PAN, getEncodedStreamPosition(), fPan, null);
+ }
+ else throw new BasicPlayerException(BasicPlayerException.PANCONTROLNOTSUPPORTED);
+ }
+
+ /**
+ * Sets Gain value.
+ * Line should be opened before calling this method.
+ * Linear scale 0.0 <--> 1.0
+ * Threshold Coef. : 1/2 to avoid saturation.
+ */
+ public void setGain(double fGain) throws BasicPlayerException
+ {
+ if (hasGainControl())
+ {
+ double minGainDB = getMinimumGain();
+ double ampGainDB = ((10.0f / 20.0f) * getMaximumGain()) - getMinimumGain();
+ double cste = Math.log(10.0) / 20;
+ double valueDB = minGainDB + (1 / cste) * Math.log(1 + (Math.exp(cste * ampGainDB) - 1) * fGain);
+ log.debug("Gain : " + valueDB);
+ m_gainControl.setValue((float) valueDB);
+ notifyEvent(BasicPlayerEvent.GAIN, getEncodedStreamPosition(), fGain, null);
+ }
+ else throw new BasicPlayerException(BasicPlayerException.GAINCONTROLNOTSUPPORTED);
+ }
+
+ public List getMixers()
+ {
+ ArrayList mixers = new ArrayList();
+ Mixer.Info[] mInfos = AudioSystem.getMixerInfo();
+ if (mInfos != null)
+ {
+ for (int i = 0; i < mInfos.length; i++)
+ {
+ Line.Info lineInfo = new Line.Info(SourceDataLine.class);
+ Mixer mixer = AudioSystem.getMixer(mInfos[i]);
+ if (mixer.isLineSupported(lineInfo))
+ {
+ mixers.add(mInfos[i].getName());
+ }
+ }
+ }
+ return mixers;
+ }
+
+ public Mixer getMixer(String name)
+ {
+ Mixer mixer = null;
+ if (name != null)
+ {
+ Mixer.Info[] mInfos = AudioSystem.getMixerInfo();
+ if (mInfos != null)
+ {
+ for (int i = 0; i < mInfos.length; i++)
+ {
+ if (mInfos[i].getName().equals(name))
+ {
+ mixer = AudioSystem.getMixer(mInfos[i]);
+ break;
+ }
+ }
+ }
+ }
+ return mixer;
+ }
+
+ public String getMixerName()
+ {
+ return m_mixerName;
+ }
+
+ public void setMixerName(String name)
+ {
+ m_mixerName = name;
+ }
+}
diff --git a/vendor/jlgui/3.0/src/javazoom/jlgui/basicplayer/BasicPlayerEvent.java b/vendor/jlgui/3.0/src/javazoom/jlgui/basicplayer/BasicPlayerEvent.java
new file mode 100644
index 0000000..c2c93bd
--- /dev/null
+++ b/vendor/jlgui/3.0/src/javazoom/jlgui/basicplayer/BasicPlayerEvent.java
@@ -0,0 +1,121 @@
+/*
+ * BasicPlayerEvent.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.basicplayer;
+
+/**
+ * This class implements player events.
+ */
+public class BasicPlayerEvent
+{
+ public static final int UNKNOWN = -1;
+ public static final int OPENING = 0;
+ public static final int OPENED = 1;
+ public static final int PLAYING = 2;
+ public static final int STOPPED = 3;
+ public static final int PAUSED = 4;
+ public static final int RESUMED = 5;
+ public static final int SEEKING = 6;
+ public static final int SEEKED = 7;
+ public static final int EOM = 8;
+ public static final int PAN = 9;
+ public static final int GAIN = 10;
+ private int code = UNKNOWN;
+ private int position = -1;
+ private double value = -1.0;
+ private Object source = null;
+ private Object description = null;
+
+ /**
+ * Constructor
+ * @param source of the event
+ * @param code of the envent
+ * @param position optional stream position
+ * @param value opitional control value
+ * @param desc optional description
+ */
+ public BasicPlayerEvent(Object source, int code, int position, double value, Object desc)
+ {
+ this.value = value;
+ this.position = position;
+ this.source = source;
+ this.code = code;
+ this.description = desc;
+ }
+
+ /**
+ * Return code of the event triggered.
+ * @return
+ */
+ public int getCode()
+ {
+ return code;
+ }
+
+ /**
+ * Return position in the stream when event occured.
+ * @return
+ */
+ public int getPosition()
+ {
+ return position;
+ }
+
+ /**
+ * Return value related to event triggered.
+ * @return
+ */
+ public double getValue()
+ {
+ return value;
+ }
+
+ /**
+ * Return description.
+ * @return
+ */
+ public Object getDescription()
+ {
+ return description;
+ }
+
+ public Object getSource()
+ {
+ return source;
+ }
+
+ public String toString()
+ {
+ if (code == OPENED) return "OPENED:" + position;
+ else if (code == OPENING) return "OPENING:" + position + ":" + description;
+ else if (code == PLAYING) return "PLAYING:" + position;
+ else if (code == STOPPED) return "STOPPED:" + position;
+ else if (code == PAUSED) return "PAUSED:" + position;
+ else if (code == RESUMED) return "RESUMED:" + position;
+ else if (code == SEEKING) return "SEEKING:" + position;
+ else if (code == SEEKED) return "SEEKED:" + position;
+ else if (code == EOM) return "EOM:" + position;
+ else if (code == PAN) return "PAN:" + value;
+ else if (code == GAIN) return "GAIN:" + value;
+ else return "UNKNOWN:" + position;
+ }
+}
diff --git a/vendor/jlgui/3.0/src/javazoom/jlgui/basicplayer/BasicPlayerEventLauncher.java b/vendor/jlgui/3.0/src/javazoom/jlgui/basicplayer/BasicPlayerEventLauncher.java
new file mode 100644
index 0000000..5c3a136
--- /dev/null
+++ b/vendor/jlgui/3.0/src/javazoom/jlgui/basicplayer/BasicPlayerEventLauncher.java
@@ -0,0 +1,73 @@
+/*
+ * BasicPlayerEventLauncher.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.basicplayer;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * This class implements a threaded events launcher.
+ */
+public class BasicPlayerEventLauncher extends Thread
+{
+ private int code = -1;
+ private int position = -1;
+ private double value = 0.0;
+ private Object description = null;
+ private Collection listeners = null;
+ private Object source = null;
+
+ /**
+ * Contructor.
+ * @param code
+ * @param position
+ * @param value
+ * @param description
+ * @param listeners
+ * @param source
+ */
+ public BasicPlayerEventLauncher(int code, int position, double value, Object description, Collection listeners, Object source)
+ {
+ super();
+ this.code = code;
+ this.position = position;
+ this.value = value;
+ this.description = description;
+ this.listeners = listeners;
+ this.source = source;
+ }
+
+ public void run()
+ {
+ if (listeners != null)
+ {
+ Iterator it = listeners.iterator();
+ while (it.hasNext())
+ {
+ BasicPlayerListener bpl = (BasicPlayerListener) it.next();
+ BasicPlayerEvent event = new BasicPlayerEvent(source, code, position, value, description);
+ bpl.stateUpdated(event);
+ }
+ }
+ }
+}
diff --git a/vendor/jlgui/3.0/src/javazoom/jlgui/basicplayer/BasicPlayerException.java b/vendor/jlgui/3.0/src/javazoom/jlgui/basicplayer/BasicPlayerException.java
new file mode 100644
index 0000000..df6e4b4
--- /dev/null
+++ b/vendor/jlgui/3.0/src/javazoom/jlgui/basicplayer/BasicPlayerException.java
@@ -0,0 +1,107 @@
+/*
+ * BasicPlayerException.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.basicplayer;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+/**
+ * This class implements custom exception for basicplayer.
+ */
+public class BasicPlayerException extends Exception
+{
+ public static final String GAINCONTROLNOTSUPPORTED = "Gain control not supported";
+ public static final String PANCONTROLNOTSUPPORTED = "Pan control not supported";
+ public static final String WAITERROR = "Wait error";
+ public static final String CANNOTINITLINE = "Cannot init line";
+ public static final String SKIPNOTSUPPORTED = "Skip not supported";
+ private Throwable cause = null;
+
+ public BasicPlayerException()
+ {
+ super();
+ }
+
+ public BasicPlayerException(String msg)
+ {
+ super(msg);
+ }
+
+ public BasicPlayerException(Throwable cause)
+ {
+ super();
+ this.cause = cause;
+ }
+
+ public BasicPlayerException(String msg, Throwable cause)
+ {
+ super(msg);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+
+ /**
+ * Returns the detail message string of this throwable. If it was
+ * created with a null message, returns the following:
+ * (cause==null ? null : cause.toString()).
+ */
+ public String getMessage()
+ {
+ if (super.getMessage() != null)
+ {
+ return super.getMessage();
+ }
+ else if (cause != null)
+ {
+ return cause.toString();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public void printStackTrace()
+ {
+ printStackTrace(System.err);
+ }
+
+ public void printStackTrace(PrintStream out)
+ {
+ synchronized (out)
+ {
+ PrintWriter pw = new PrintWriter(out, false);
+ printStackTrace(pw);
+ pw.flush();
+ }
+ }
+
+ public void printStackTrace(PrintWriter out)
+ {
+ if (cause != null) cause.printStackTrace(out);
+ }
+}
diff --git a/vendor/jlgui/3.0/src/javazoom/jlgui/basicplayer/BasicPlayerListener.java b/vendor/jlgui/3.0/src/javazoom/jlgui/basicplayer/BasicPlayerListener.java
new file mode 100644
index 0000000..1157ab2
--- /dev/null
+++ b/vendor/jlgui/3.0/src/javazoom/jlgui/basicplayer/BasicPlayerListener.java
@@ -0,0 +1,72 @@
+/*
+ * BasicPlayerListener.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.basicplayer;
+
+import java.util.Map;
+
+/**
+ * This interface defines callbacks methods that will be notified
+ * for all registered BasicPlayerListener of BasicPlayer.
+ */
+public interface BasicPlayerListener
+{
+ /**
+ * Open callback, stream is ready to play.
+ *
+ * properties map includes audio format dependant features such as
+ * bitrate, duration, frequency, channels, number of frames, vbr flag,
+ * id3v2/id3v1 (for MP3 only), comments (for Ogg Vorbis), ...
+ *
+ * @param stream could be File, URL or InputStream
+ * @param properties audio stream properties.
+ */
+ public void opened(Object stream, Map properties);
+
+ /**
+ * Progress callback while playing.
+ *
+ * This method is called severals time per seconds while playing.
+ * properties map includes audio format features such as
+ * instant bitrate, microseconds position, current frame number, ...
+ *
+ * @param bytesread from encoded stream.
+ * @param microseconds elapsed (reseted after a seek !).
+ * @param pcmdata PCM samples.
+ * @param properties audio stream parameters.
+ */
+ public void progress(int bytesread, long microseconds, byte[] pcmdata, Map properties);
+
+ /**
+ * Notification callback for basicplayer events such as opened, eom ...
+ *
+ * @param event
+ */
+ public void stateUpdated(BasicPlayerEvent event);
+
+ /**
+ * A handle to the BasicPlayer, plugins may control the player through
+ * the controller (play, stop, ...)
+ * @param controller : a handle to the player
+ */
+ public void setController(BasicController controller);
+}
diff --git a/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/Loader.java b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/Loader.java
new file mode 100644
index 0000000..52b5b07
--- /dev/null
+++ b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/Loader.java
@@ -0,0 +1,40 @@
+/*
+ * Loader.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp;
+
+import java.awt.Point;
+
+public interface Loader
+{
+ public void loaded();
+
+ public void close();
+
+ public void minimize();
+
+ public Point getLocation();
+
+ public void togglePlaylist(boolean enabled);
+
+ public void toggleEqualizer(boolean enabled);
+}
diff --git a/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/PlayerActionEvent.java b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/PlayerActionEvent.java
new file mode 100644
index 0000000..8c9da95
--- /dev/null
+++ b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/PlayerActionEvent.java
@@ -0,0 +1,99 @@
+/*
+ * PlayerActionEvent.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp;
+
+import java.awt.event.ActionEvent;
+
+public class PlayerActionEvent extends ActionEvent
+{
+ public static final String ACPREVIOUS = "Previous";
+ public static final String ACPLAY = "Play";
+ public static final String ACPAUSE = "Pause";
+ public static final String ACSTOP = "Stop";
+ public static final String ACNEXT = "Next";
+ public static final String ACEJECT = "Eject";
+ public static final String ACEQUALIZER = "EqualizerUI";
+ public static final String ACPLAYLIST = "Playlist";
+ public static final String ACSHUFFLE = "Shuffle";
+ public static final String ACREPEAT = "Repeat";
+ public static final String ACVOLUME = "Volume";
+ public static final String ACBALANCE = "Balance";
+ public static final String ACTITLEBAR = "TitleBar";
+ public static final String ACEXIT = "Exit";
+ public static final String ACMINIMIZE = "Minimize";
+ public static final String ACPOSBAR = "Seek";
+ public static final String MIPLAYFILE = "PlayFileMI";
+ public static final String MIPLAYLOCATION = "PlayLocationMI";
+ public static final String MIPLAYLIST = "PlaylistMI";
+ public static final String MIEQUALIZER = "EqualizerMI";
+ public static final String MIPREFERENCES = "PreferencesMI";
+ public static final String MISKINBROWSER = "SkinBrowserMI";
+ public static final String MILOADSKIN = "LoadSkinMI";
+ public static final String MIJUMPFILE = "JumpFileMI";
+ public static final String MISTOP = "StopMI";
+ public static final String EQSLIDER = "SliderEQ";
+ public static final String ACEQPRESETS = "PresetsEQ";
+ public static final String ACEQONOFF = "OnOffEQ";
+ public static final String ACEQAUTO = "AutoEQ";
+ public static final String ACPLUP = "ScrollUpPL";
+ public static final String ACPLDOWN = "ScrollDownPL";
+ public static final String ACPLINFO = "InfoPL";
+ public static final String ACPLPLAY = "PlayPL";
+ public static final String ACPLREMOVE = "RemovePL";
+ public static final String ACPLADDPOPUP = "AddPopupPL";
+ public static final String ACPLADDFILE = "AddFilePL";
+ public static final String ACPLADDDIR = "AddDirPL";
+ public static final String ACPLADDURL = "AddURLPL";
+ public static final String ACPLREMOVEPOPUP = "RemovePopupPL";
+ public static final String ACPLREMOVEMISC = "RemoveMiscPL";
+ public static final String ACPLREMOVESEL = "RemoveSelPL";
+ public static final String ACPLREMOVEALL = "RemoveAllPL";
+ public static final String ACPLREMOVECROP = "RemoveCropPL";
+ public static final String ACPLSELPOPUP = "SelectPopupPL";
+ public static final String ACPLSELALL = "SelectAllPL";
+ public static final String ACPLSELZERO = "SelectZeroPL";
+ public static final String ACPLSELINV = "SelectInvPL";
+ public static final String ACPLMISCPOPUP = "MiscPopupPL";
+ public static final String ACPLMISCOPTS = "MiscOptsPL";
+ public static final String ACPLMISCFILE = "MiscFilePL";
+ public static final String ACPLMISCSORT = "MiscSortPL";
+ public static final String ACPLLISTPOPUP = "ListPopupPL";
+ public static final String ACPLLISTLOAD = "ListLoadPL";
+ public static final String ACPLLISTSAVE = "ListSavePL";
+ public static final String ACPLLISTNEW = "ListNewPL";
+
+ public PlayerActionEvent(Object source, int id, String command)
+ {
+ super(source, id, command);
+ }
+
+ public PlayerActionEvent(Object source, int id, String command, int modifiers)
+ {
+ super(source, id, command, modifiers);
+ }
+
+ public PlayerActionEvent(Object source, int id, String command, long when, int modifiers)
+ {
+ super(source, id, command, when, modifiers);
+ }
+}
diff --git a/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/PlayerUI.java b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/PlayerUI.java
new file mode 100644
index 0000000..47abd20
--- /dev/null
+++ b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/PlayerUI.java
@@ -0,0 +1,1827 @@
+/*
+ * PlayerUI.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp;
+
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DropTarget;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.io.File;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.StringTokenizer;
+import javax.sound.sampled.SourceDataLine;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.KeyStroke;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javazoom.jlgui.basicplayer.BasicController;
+import javazoom.jlgui.basicplayer.BasicPlayer;
+import javazoom.jlgui.basicplayer.BasicPlayerEvent;
+import javazoom.jlgui.basicplayer.BasicPlayerException;
+import javazoom.jlgui.basicplayer.BasicPlayerListener;
+import javazoom.jlgui.player.amp.equalizer.ui.EqualizerUI;
+import javazoom.jlgui.player.amp.playlist.Playlist;
+import javazoom.jlgui.player.amp.playlist.PlaylistFactory;
+import javazoom.jlgui.player.amp.playlist.PlaylistItem;
+import javazoom.jlgui.player.amp.playlist.ui.PlaylistUI;
+import javazoom.jlgui.player.amp.skin.AbsoluteLayout;
+import javazoom.jlgui.player.amp.skin.DropTargetAdapter;
+import javazoom.jlgui.player.amp.skin.ImageBorder;
+import javazoom.jlgui.player.amp.skin.PopupAdapter;
+import javazoom.jlgui.player.amp.skin.Skin;
+import javazoom.jlgui.player.amp.skin.UrlDialog;
+import javazoom.jlgui.player.amp.tag.ui.TagSearch;
+import javazoom.jlgui.player.amp.util.Config;
+import javazoom.jlgui.player.amp.util.FileSelector;
+import javazoom.jlgui.player.amp.util.ui.Preferences;
+import javazoom.jlgui.player.amp.visual.ui.SpectrumTimeAnalyzer;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class PlayerUI extends JPanel implements ActionListener, ChangeListener, BasicPlayerListener
+{
+ private static Log log = LogFactory.getLog(PlayerUI.class);
+ public static final int INIT = 0;
+ public static final int OPEN = 1;
+ public static final int PLAY = 2;
+ public static final int PAUSE = 3;
+ public static final int STOP = 4;
+ public static final int TEXT_LENGTH_MAX = 30;
+ public static final long SCROLL_PERIOD = 250;
+ private Skin ui = null;
+ private Loader loader = null;
+ private Config config = null;
+ /*-- Pop up menus --*/
+ private JPopupMenu mainpopup = null;
+ private JPopupMenu ejectpopup = null;
+ private JCheckBoxMenuItem miPlaylist = null;
+ private JCheckBoxMenuItem miEqualizer = null;
+ private JMenuItem miPlayFile = null;
+ private JMenuItem miPlayLocation = null;
+ private PopupAdapter popupAdapter = null;
+ private PopupAdapter ejectpopupAdapter = null;
+ /*-- Sound player --*/
+ private BasicController theSoundPlayer = null;
+ private Map audioInfo = null;
+ private int playerState = INIT;
+ /*-- Title text --*/
+ private String titleText = Skin.TITLETEXT.toUpperCase();
+ private String currentTitle = Skin.TITLETEXT.toUpperCase();
+ private String[] titleScrollLabel = null;
+ private int scrollIndex = 0;
+ private long lastScrollTime = 0L;
+ private boolean scrollRight = true;
+ private long secondsAmount = 0;
+ /*-- Playlist --*/
+ private Playlist playlist = null;
+ private PlaylistUI playlistUI = null;
+ private String currentFileOrURL = null;
+ private String currentSongName = null;
+ private PlaylistItem currentPlaylistItem = null;
+ private boolean currentIsFile;
+ /*-- PosBar members --*/
+ private boolean posValueJump = false;
+ private boolean posDragging = false;
+ private double posValue = 0.0;
+ /*-- EqualizerUI --*/
+ private EqualizerUI equalizerUI = null;
+
+ public PlayerUI()
+ {
+ super();
+ setDoubleBuffered(true);
+ ui = new Skin();
+ }
+
+ public void setEqualizerUI(EqualizerUI eq)
+ {
+ equalizerUI = eq;
+ }
+
+ public EqualizerUI getEqualizerUI()
+ {
+ return equalizerUI;
+ }
+
+ public PlaylistUI getPlaylistUI()
+ {
+ return playlistUI;
+ }
+
+ public void setPlaylistUI(PlaylistUI playlistUI)
+ {
+ this.playlistUI = playlistUI;
+ }
+
+ public Playlist getPlaylist()
+ {
+ return playlist;
+ }
+
+ /**
+ * Return config.
+ * @return
+ */
+ public Config getConfig()
+ {
+ return config;
+ }
+
+ /**
+ * Return skin.
+ * @return
+ */
+ public Skin getSkin()
+ {
+ return ui;
+ }
+
+ /**
+ * Return parent loader.
+ * @return
+ */
+ public Loader getLoader()
+ {
+ return loader;
+ }
+
+ /**
+ * A handle to the BasicPlayer, plugins may control the player through
+ * the controller (play, stop, ...)
+ * @param controller
+ */
+ public void setController(BasicController controller)
+ {
+ theSoundPlayer = controller;
+ }
+
+ /**
+ * Return player controller.
+ * @return
+ */
+ public BasicController getController()
+ {
+ return theSoundPlayer;
+ }
+
+ /**
+ * Load main player.
+ * @param loader
+ */
+ public void loadUI(Loader loader)
+ {
+ this.loader = loader;
+ setLayout(new AbsoluteLayout());
+ config = Config.getInstance();
+ ui.setConfig(config);
+ playlistUI = new PlaylistUI();
+ playlistUI.setSkin(ui);
+ playlistUI.setPlayer(this);
+ equalizerUI = new EqualizerUI();
+ equalizerUI.setSkin(ui);
+ loadSkin();
+ // DnD support.
+ DropTargetAdapter dnd = new DropTargetAdapter()
+ {
+ public void processDrop(Object data)
+ {
+ processDnD(data);
+ }
+ };
+ DropTarget dt = new DropTarget(this, DnDConstants.ACTION_COPY, dnd, true);
+ }
+
+ public void loadSkin()
+ {
+ log.info("Load PlayerUI (EDT=" + SwingUtilities.isEventDispatchThread() + ")");
+ removeAll();
+ // Load skin specified in args
+ if (ui.getPath() != null)
+ {
+ log.info("Load default skin from " + ui.getPath());
+ ui.loadSkin(ui.getPath());
+ config.setDefaultSkin(ui.getPath());
+ }
+ // Load skin specified in jlgui.ini
+ else if ((config.getDefaultSkin() != null) && (!config.getDefaultSkin().trim().equals("")))
+ {
+ log.info("Load default skin from " + config.getDefaultSkin());
+ ui.loadSkin(config.getDefaultSkin());
+ }
+ // Default included skin
+ else
+ {
+ ClassLoader cl = getClass().getClassLoader();
+ InputStream sis = cl.getResourceAsStream("javazoom/jlgui/player/amp/metrix.wsz");
+ log.info("Load default skin for JAR");
+ ui.loadSkin(sis);
+ }
+ // Background
+ ImageBorder border = new ImageBorder();
+ border.setImage(ui.getMainImage());
+ setBorder(border);
+ // Buttons
+ add(ui.getAcPrevious(), ui.getAcPrevious().getConstraints());
+ ui.getAcPrevious().removeActionListener(this);
+ ui.getAcPrevious().addActionListener(this);
+ add(ui.getAcPlay(), ui.getAcPlay().getConstraints());
+ ui.getAcPlay().removeActionListener(this);
+ ui.getAcPlay().addActionListener(this);
+ add(ui.getAcPause(), ui.getAcPause().getConstraints());
+ ui.getAcPause().removeActionListener(this);
+ ui.getAcPause().addActionListener(this);
+ add(ui.getAcStop(), ui.getAcStop().getConstraints());
+ ui.getAcStop().removeActionListener(this);
+ ui.getAcStop().addActionListener(this);
+ add(ui.getAcNext(), ui.getAcNext().getConstraints());
+ ui.getAcNext().removeActionListener(this);
+ ui.getAcNext().addActionListener(this);
+ add(ui.getAcEject(), ui.getAcEject().getConstraints());
+ ui.getAcEject().removeActionListener(this);
+ ui.getAcEject().addActionListener(this);
+ // EqualizerUI toggle
+ add(ui.getAcEqualizer(), ui.getAcEqualizer().getConstraints());
+ ui.getAcEqualizer().removeActionListener(this);
+ ui.getAcEqualizer().addActionListener(this);
+ // Playlist toggle
+ add(ui.getAcPlaylist(), ui.getAcPlaylist().getConstraints());
+ ui.getAcPlaylist().removeActionListener(this);
+ ui.getAcPlaylist().addActionListener(this);
+ // Shuffle toggle
+ add(ui.getAcShuffle(), ui.getAcShuffle().getConstraints());
+ ui.getAcShuffle().removeActionListener(this);
+ ui.getAcShuffle().addActionListener(this);
+ // Repeat toggle
+ add(ui.getAcRepeat(), ui.getAcRepeat().getConstraints());
+ ui.getAcRepeat().removeActionListener(this);
+ ui.getAcRepeat().addActionListener(this);
+ // Volume
+ add(ui.getAcVolume(), ui.getAcVolume().getConstraints());
+ ui.getAcVolume().removeChangeListener(this);
+ ui.getAcVolume().addChangeListener(this);
+ // Balance
+ add(ui.getAcBalance(), ui.getAcBalance().getConstraints());
+ ui.getAcBalance().removeChangeListener(this);
+ ui.getAcBalance().addChangeListener(this);
+ // Seek bar
+ add(ui.getAcPosBar(), ui.getAcPosBar().getConstraints());
+ ui.getAcPosBar().removeChangeListener(this);
+ ui.getAcPosBar().addChangeListener(this);
+ // Mono
+ add(ui.getAcMonoIcon(), ui.getAcMonoIcon().getConstraints());
+ // Stereo
+ add(ui.getAcStereoIcon(), ui.getAcStereoIcon().getConstraints());
+ // Title label
+ add(ui.getAcTitleLabel(), ui.getAcTitleLabel().getConstraints());
+ // Sample rate label
+ add(ui.getAcSampleRateLabel(), ui.getAcSampleRateLabel().getConstraints());
+ // Bit rate label
+ add(ui.getAcBitRateLabel(), ui.getAcBitRateLabel().getConstraints());
+ // Play icon
+ add(ui.getAcPlayIcon(), ui.getAcPlayIcon().getConstraints());
+ // Time icon
+ add(ui.getAcTimeIcon(), ui.getAcTimeIcon().getConstraints());
+ // MinuteH number
+ add(ui.getAcMinuteH(), ui.getAcMinuteH().getConstraints());
+ // MinuteL number
+ add(ui.getAcMinuteL(), ui.getAcMinuteL().getConstraints());
+ // SecondH number
+ add(ui.getAcSecondH(), ui.getAcSecondH().getConstraints());
+ // SecondL number
+ add(ui.getAcSecondL(), ui.getAcSecondL().getConstraints());
+ // TitleBar
+ add(ui.getAcTitleBar(), ui.getAcTitleBar().getConstraints());
+ add(ui.getAcMinimize(), ui.getAcMinimize().getConstraints());
+ ui.getAcMinimize().removeActionListener(this);
+ ui.getAcMinimize().addActionListener(this);
+ add(ui.getAcExit(), ui.getAcExit().getConstraints());
+ ui.getAcExit().removeActionListener(this);
+ ui.getAcExit().addActionListener(this);
+ // DSP
+ if (ui.getAcAnalyzer() != null)
+ {
+ add(ui.getAcAnalyzer(), ui.getAcAnalyzer().getConstraints());
+ }
+ // Popup menu
+ mainpopup = new JPopupMenu(ui.getResource("popup.title"));
+ JMenuItem mi = new JMenuItem(Skin.TITLETEXT + "- JavaZOOM");
+ //mi.removeActionListener(this);
+ //mi.addActionListener(this);
+ mainpopup.add(mi);
+ mainpopup.addSeparator();
+ JMenu playSubMenu = new JMenu(ui.getResource("popup.play"));
+ miPlayFile = new JMenuItem(ui.getResource("popup.play.file"));
+ miPlayFile.setActionCommand(PlayerActionEvent.MIPLAYFILE);
+ miPlayFile.removeActionListener(this);
+ miPlayFile.addActionListener(this);
+ miPlayLocation = new JMenuItem(ui.getResource("popup.play.location"));
+ miPlayLocation.setActionCommand(PlayerActionEvent.MIPLAYLOCATION);
+ miPlayLocation.removeActionListener(this);
+ miPlayLocation.addActionListener(this);
+ playSubMenu.add(miPlayFile);
+ playSubMenu.add(miPlayLocation);
+ mainpopup.add(playSubMenu);
+ mainpopup.addSeparator();
+ miPlaylist = new JCheckBoxMenuItem(ui.getResource("popup.playlist"));
+ miPlaylist.setActionCommand(PlayerActionEvent.MIPLAYLIST);
+ if (config.isPlaylistEnabled()) miPlaylist.setState(true);
+ miPlaylist.removeActionListener(this);
+ miPlaylist.addActionListener(this);
+ mainpopup.add(miPlaylist);
+ miEqualizer = new JCheckBoxMenuItem(ui.getResource("popup.equalizer"));
+ miEqualizer.setActionCommand(PlayerActionEvent.MIEQUALIZER);
+ if (config.isEqualizerEnabled()) miEqualizer.setState(true);
+ miEqualizer.removeActionListener(this);
+ miEqualizer.addActionListener(this);
+ mainpopup.add(miEqualizer);
+ mainpopup.addSeparator();
+ mi = new JMenuItem(ui.getResource("popup.preferences"));
+ mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, ActionEvent.CTRL_MASK, false));
+ mi.setActionCommand(PlayerActionEvent.MIPREFERENCES);
+ mi.removeActionListener(this);
+ mi.addActionListener(this);
+ mainpopup.add(mi);
+ JMenu skinsSubMenu = new JMenu(ui.getResource("popup.skins"));
+ mi = new JMenuItem(ui.getResource("popup.skins.browser"));
+ mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.ALT_MASK, false));
+ mi.setActionCommand(PlayerActionEvent.MISKINBROWSER);
+ mi.removeActionListener(this);
+ mi.addActionListener(this);
+ skinsSubMenu.add(mi);
+ mi = new JMenuItem(ui.getResource("popup.skins.load"));
+ mi.setActionCommand(PlayerActionEvent.MILOADSKIN);
+ mi.removeActionListener(this);
+ mi.addActionListener(this);
+ skinsSubMenu.add(mi);
+ mainpopup.add(skinsSubMenu);
+ JMenu playbackSubMenu = new JMenu(ui.getResource("popup.playback"));
+ mi = new JMenuItem(ui.getResource("popup.playback.jump"));
+ mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_J, 0, false));
+ mi.setActionCommand(PlayerActionEvent.MIJUMPFILE);
+ mi.removeActionListener(this);
+ mi.addActionListener(this);
+ playbackSubMenu.add(mi);
+ mi = new JMenuItem(ui.getResource("popup.playback.stop"));
+ mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, 0, false));
+ mi.setActionCommand(PlayerActionEvent.MISTOP);
+ mi.removeActionListener(this);
+ mi.addActionListener(this);
+ playbackSubMenu.add(mi);
+ mainpopup.add(playbackSubMenu);
+ mainpopup.addSeparator();
+ mi = new JMenuItem(ui.getResource("popup.exit"));
+ mi.setActionCommand(PlayerActionEvent.ACEXIT);
+ mi.removeActionListener(this);
+ mi.addActionListener(this);
+ mainpopup.add(mi);
+ // Popup menu on TitleBar
+ ui.getAcTitleBar().removeMouseListener(popupAdapter);
+ popupAdapter = new PopupAdapter(mainpopup);
+ ui.getAcTitleBar().addMouseListener(popupAdapter);
+ // Popup menu on Eject button
+ ejectpopup = new JPopupMenu();
+ mi = new JMenuItem(ui.getResource("popup.eject.openfile"));
+ mi.setActionCommand(PlayerActionEvent.MIPLAYFILE);
+ mi.removeActionListener(this);
+ mi.addActionListener(this);
+ ejectpopup.add(mi);
+ mi = new JMenuItem(ui.getResource("popup.eject.openlocation"));
+ mi.setActionCommand(PlayerActionEvent.MIPLAYLOCATION);
+ mi.removeActionListener(this);
+ mi.addActionListener(this);
+ ejectpopup.add(mi);
+ ui.getAcEject().removeMouseListener(ejectpopupAdapter);
+ ejectpopupAdapter = new PopupAdapter(ejectpopup);
+ ui.getAcEject().addMouseListener(ejectpopupAdapter);
+ // EqualizerUI
+ if (equalizerUI != null) equalizerUI.loadUI();
+ if (playlistUI != null) playlistUI.loadUI();
+ validate();
+ loader.loaded();
+ }
+
+ /**
+ * Load playlist.
+ * @param playlistName
+ * @return
+ */
+ public boolean loadPlaylist(String playlistName)
+ {
+ boolean loaded = false;
+ PlaylistFactory plf = PlaylistFactory.getInstance();
+ playlist = plf.getPlaylist();
+ if (playlist == null)
+ {
+ config.setPlaylistClassName("javazoom.jlgui.player.amp.playlist.BasePlaylist");
+ playlist = plf.getPlaylist();
+ }
+ playlistUI.setPlaylist(playlist);
+ if ((playlistName != null) && (!playlistName.equals("")))
+ {
+ // M3U file or URL.
+ if ((playlistName.toLowerCase().endsWith(ui.getResource("playlist.extension.m3u"))) || (playlistName.toLowerCase().endsWith(ui.getResource("playlist.extension.pls")))) loaded = playlist.load(playlistName);
+ // Simple song.
+ else
+ {
+ String name = playlistName;
+ if (!Config.startWithProtocol(playlistName))
+ {
+ int indn = playlistName.lastIndexOf(java.io.File.separatorChar);
+ if (indn != -1) name = playlistName.substring(indn + 1);
+ PlaylistItem pli = new PlaylistItem(name, playlistName, -1, true);
+ playlist.appendItem(pli);
+ loaded = true;
+ }
+ else
+ {
+ PlaylistItem pli = new PlaylistItem(name, playlistName, -1, false);
+ playlist.appendItem(pli);
+ loaded = true;
+ }
+ }
+ }
+ return loaded;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent)
+ */
+ public void stateChanged(ChangeEvent e)
+ {
+ Object src = e.getSource();
+ //log.debug("State (EDT=" + SwingUtilities.isEventDispatchThread() + ")");
+ // Volume
+ if (src == ui.getAcVolume())
+ {
+ Object[] args = { String.valueOf(ui.getAcVolume().getValue()) };
+ String volumeText = MessageFormat.format(ui.getResource("slider.volume.text"), args);
+ ui.getAcTitleLabel().setAcText(volumeText);
+ try
+ {
+ int gainValue = ui.getAcVolume().getValue();
+ int maxGain = ui.getAcVolume().getMaximum();
+ if (gainValue == 0) theSoundPlayer.setGain(0);
+ else theSoundPlayer.setGain(((double) gainValue / (double) maxGain));
+ config.setVolume(gainValue);
+ }
+ catch (BasicPlayerException ex)
+ {
+ log.debug("Cannot set gain", ex);
+ }
+ }
+ // Balance
+ else if (src == ui.getAcBalance())
+ {
+ Object[] args = { String.valueOf(Math.abs(ui.getAcBalance().getValue() * 100 / Skin.BALANCEMAX)) };
+ String balanceText = null;
+ if (ui.getAcBalance().getValue() > 0)
+ {
+ balanceText = MessageFormat.format(ui.getResource("slider.balance.text.right"), args);
+ }
+ else if (ui.getAcBalance().getValue() < 0)
+ {
+ balanceText = MessageFormat.format(ui.getResource("slider.balance.text.left"), args);
+ }
+ else
+ {
+ balanceText = MessageFormat.format(ui.getResource("slider.balance.text.center"), args);
+ }
+ ui.getAcTitleLabel().setAcText(balanceText);
+ try
+ {
+ float balanceValue = ui.getAcBalance().getValue() * 1.0f / Skin.BALANCEMAX;
+ theSoundPlayer.setPan(balanceValue);
+ }
+ catch (BasicPlayerException ex)
+ {
+ log.debug("Cannot set pan", ex);
+ }
+ }
+ else if (src == ui.getAcPosBar())
+ {
+ if (ui.getAcPosBar().getValueIsAdjusting() == false)
+ {
+ if (posDragging == true)
+ {
+ posDragging = false;
+ posValue = ui.getAcPosBar().getValue() * 1.0 / Skin.POSBARMAX;
+ processSeek(posValue);
+ }
+ }
+ else
+ {
+ posDragging = true;
+ posValueJump = true;
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+ */
+ public void actionPerformed(ActionEvent e)
+ {
+ final ActionEvent evt = e;
+ if (e.getActionCommand().equals(PlayerActionEvent.ACPAUSE))
+ {
+ processActionEvent(e);
+ }
+ else if ((e.getActionCommand().equals(PlayerActionEvent.ACPLAY)) && (playerState == PAUSE))
+ {
+ processActionEvent(e);
+ }
+ else
+ {
+ new Thread("PlayerUIActionEvent")
+ {
+ public void run()
+ {
+ processActionEvent(evt);
+ }
+ }.start();
+ }
+ }
+
+ /**
+ * Process action event.
+ * @param e
+ */
+ public void processActionEvent(ActionEvent e)
+ {
+ String cmd = e.getActionCommand();
+ log.debug("Action=" + cmd + " (EDT=" + SwingUtilities.isEventDispatchThread() + ")");
+ // Preferences.
+ if (cmd.equalsIgnoreCase(PlayerActionEvent.MIPREFERENCES))
+ {
+ processPreferences(e.getModifiers());
+ }
+ // Skin browser
+ else if (cmd.equals(PlayerActionEvent.MISKINBROWSER))
+ {
+ processSkinBrowser(e.getModifiers());
+ }
+ // Jump to file
+ else if (cmd.equals(PlayerActionEvent.MIJUMPFILE))
+ {
+ processJumpToFile(e.getModifiers());
+ }
+ // Stop
+ else if (cmd.equals(PlayerActionEvent.MISTOP))
+ {
+ processStop(MouseEvent.BUTTON1_MASK);
+ }
+ // Load skin
+ else if (e.getActionCommand().equals(PlayerActionEvent.MILOADSKIN))
+ {
+ File[] file = FileSelector.selectFile(loader, FileSelector.OPEN, false, ui.getResource("skin.extension"), ui.getResource("loadskin.dialog.filtername"), new File(config.getLastDir()));
+ if (FileSelector.getInstance().getDirectory() != null) config.setLastDir(FileSelector.getInstance().getDirectory().getPath());
+ if (file != null)
+ {
+ String fsFile = file[0].getName();
+ ui.setPath(config.getLastDir() + fsFile);
+ loadSkin();
+ config.setDefaultSkin(ui.getPath());
+ }
+ }
+ // Shuffle
+ else if (cmd.equals(PlayerActionEvent.ACSHUFFLE))
+ {
+ if (ui.getAcShuffle().isSelected())
+ {
+ config.setShuffleEnabled(true);
+ if (playlist != null)
+ {
+ playlist.shuffle();
+ playlistUI.initPlayList();
+ // Play from the top
+ PlaylistItem pli = playlist.getCursor();
+ setCurrentSong(pli);
+ }
+ }
+ else
+ {
+ config.setShuffleEnabled(false);
+ }
+ }
+ // Repeat
+ else if (cmd.equals(PlayerActionEvent.ACREPEAT))
+ {
+ if (ui.getAcRepeat().isSelected())
+ {
+ config.setRepeatEnabled(true);
+ }
+ else
+ {
+ config.setRepeatEnabled(false);
+ }
+ }
+ // Play file
+ else if (cmd.equals(PlayerActionEvent.MIPLAYFILE))
+ {
+ processEject(MouseEvent.BUTTON1_MASK);
+ }
+ // Play URL
+ else if (cmd.equals(PlayerActionEvent.MIPLAYLOCATION))
+ {
+ processEject(MouseEvent.BUTTON3_MASK);
+ }
+ // Playlist menu item
+ else if (cmd.equals(PlayerActionEvent.MIPLAYLIST))
+ {
+ ui.getAcPlaylist().setSelected(miPlaylist.getState());
+ togglePlaylist();
+ }
+ // Playlist toggle button
+ else if (cmd.equals(PlayerActionEvent.ACPLAYLIST))
+ {
+ togglePlaylist();
+ }
+ // EqualizerUI menu item
+ else if (cmd.equals(PlayerActionEvent.MIEQUALIZER))
+ {
+ ui.getAcEqualizer().setSelected(miEqualizer.getState());
+ toggleEqualizer();
+ }
+ // EqualizerUI
+ else if (cmd.equals(PlayerActionEvent.ACEQUALIZER))
+ {
+ toggleEqualizer();
+ }
+ // Exit player
+ else if (cmd.equals(PlayerActionEvent.ACEXIT))
+ {
+ closePlayer();
+ }
+ // Minimize
+ else if (cmd.equals(PlayerActionEvent.ACMINIMIZE))
+ {
+ loader.minimize();
+ }
+ // Eject
+ else if (cmd.equals(PlayerActionEvent.ACEJECT))
+ {
+ processEject(e.getModifiers());
+ }
+ // Play
+ else if (cmd.equals(PlayerActionEvent.ACPLAY))
+ {
+ processPlay(e.getModifiers());
+ }
+ // Pause
+ else if (cmd.equals(PlayerActionEvent.ACPAUSE))
+ {
+ processPause(e.getModifiers());
+ }
+ // Stop
+ else if (cmd.equals(PlayerActionEvent.ACSTOP))
+ {
+ processStop(e.getModifiers());
+ }
+ // Next
+ else if (cmd.equals(PlayerActionEvent.ACNEXT))
+ {
+ processNext(e.getModifiers());
+ }
+ // Previous
+ else if (cmd.equals(PlayerActionEvent.ACPREVIOUS))
+ {
+ processPrevious(e.getModifiers());
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see javazoom.jlgui.basicplayer.BasicPlayerListener#opened(java.lang.Object, java.util.Map)
+ */
+ public void opened(Object stream, Map properties)
+ {
+ // Not in EDT.
+ audioInfo = properties;
+ log.debug(properties.toString());
+ }
+
+ /* (non-Javadoc)
+ * @see javazoom.jlgui.basicplayer.BasicPlayerListener#stateUpdated(javazoom.jlgui.basicplayer.BasicPlayerEvent)
+ */
+ public void stateUpdated(final BasicPlayerEvent event)
+ {
+ // Not in EDT.
+ processStateUpdated(event);
+ }
+
+ /* (non-Javadoc)
+ * @see javazoom.jlgui.basicplayer.BasicPlayerListener#progress(int, long, byte[], java.util.Map)
+ */
+ public void progress(int bytesread, long microseconds, byte[] pcmdata, Map properties)
+ {
+ // Not in EDT.
+ processProgress(bytesread, microseconds, pcmdata, properties);
+ }
+
+ /**
+ * Process PREFERENCES event.
+ * @param modifiers
+ */
+ protected void processPreferences(int modifiers)
+ {
+ Preferences preferences = Preferences.getInstance(this);
+ preferences.setLocation(loader.getLocation().x, loader.getLocation().y);
+ preferences.setSize(512, 350);
+ preferences.setVisible(true);
+ }
+
+ /**
+ * Process SKINS BROWSER event.
+ * @param modifiers
+ */
+ protected void processSkinBrowser(int modifiers)
+ {
+ Preferences preferences = Preferences.getInstance(this);
+ preferences.selectSkinBrowserPane();
+ preferences.setLocation(loader.getLocation().x, loader.getLocation().y);
+ preferences.setSize(512, 350);
+ preferences.setVisible(true);
+ }
+
+ /**
+ * Process JUMP FILE event.
+ * @param modifiers
+ */
+ protected void processJumpToFile(int modifiers)
+ {
+ TagSearch ts = new TagSearch(this);
+ ts.setIconImage(config.getIconParent().getImage());
+ ts.setSize(400, 300);
+ ts.setLocation(loader.getLocation());
+ ts.display();
+ }
+
+ /**
+ * Process EJECT event.
+ * @param modifiers
+ */
+ protected void processEject(int modifiers)
+ {
+ if ((playerState == PLAY) || (playerState == PAUSE))
+ {
+ try
+ {
+ if (theSoundPlayer != null)
+ {
+ theSoundPlayer.stop();
+ }
+ }
+ catch (BasicPlayerException e)
+ {
+ log.info("Cannot stop", e);
+ }
+ playerState = STOP;
+ }
+ if ((playerState == INIT) || (playerState == STOP) || (playerState == OPEN))
+ {
+ PlaylistItem pli = null;
+ // Local File.
+ if (modifiers == MouseEvent.BUTTON1_MASK)
+ {
+ File[] file = FileSelector.selectFile(loader, FileSelector.OPEN, false, config.getExtensions(), ui.getResource("button.eject.filedialog.filtername"), new File(config.getLastDir()));
+ if (FileSelector.getInstance().getDirectory() != null) config.setLastDir(FileSelector.getInstance().getDirectory().getPath());
+ if (file != null)
+ {
+ String fsFile = file[0].getName();
+ if (fsFile != null)
+ {
+ // Loads a new playlist.
+ if ((fsFile.toLowerCase().endsWith(ui.getResource("playlist.extension.m3u"))) || (fsFile.toLowerCase().endsWith(ui.getResource("playlist.extension.pls"))))
+ {
+ if (loadPlaylist(config.getLastDir() + fsFile))
+ {
+ config.setPlaylistFilename(config.getLastDir() + fsFile);
+ playlist.begin();
+ playlistUI.initPlayList();
+ setCurrentSong(playlist.getCursor());
+ playlistUI.repaint();
+ }
+ }
+ else if (fsFile.toLowerCase().endsWith(ui.getResource("skin.extension")))
+ {
+ ui.setPath(config.getLastDir() + fsFile);
+ loadSkin();
+ config.setDefaultSkin(ui.getPath());
+ }
+ else pli = new PlaylistItem(fsFile, config.getLastDir() + fsFile, -1, true);
+ }
+ }
+ }
+ // Remote File.
+ else if (modifiers == MouseEvent.BUTTON3_MASK)
+ {
+ UrlDialog UD = new UrlDialog(config.getTopParent(), ui.getResource("button.eject.urldialog.title"), loader.getLocation().x, loader.getLocation().y + 10, config.getLastURL());
+ UD.show();
+ if (UD.getFile() != null)
+ {
+ showTitle(ui.getResource("title.loading"));
+ // Remote playlist ?
+ if ((UD.getURL().toLowerCase().endsWith(ui.getResource("playlist.extension.m3u"))) || (UD.getURL().toLowerCase().endsWith(ui.getResource("playlist.extension.pls"))))
+ {
+ if (loadPlaylist(UD.getURL()))
+ {
+ config.setPlaylistFilename(UD.getURL());
+ playlist.begin();
+ playlistUI.initPlayList();
+ setCurrentSong(playlist.getCursor());
+ playlistUI.repaint();
+ }
+ }
+ // Remote file or stream.
+ else
+ {
+ pli = new PlaylistItem(UD.getFile(), UD.getURL(), -1, false);
+ }
+ config.setLastURL(UD.getURL());
+ }
+ }
+ if ((pli != null) && (playlist != null))
+ {
+ playlist.removeAllItems();
+ playlist.appendItem(pli);
+ playlist.nextCursor();
+ playlistUI.initPlayList();
+ setCurrentSong(pli);
+ playlistUI.repaint();
+ }
+ }
+ // Display play/time icons.
+ ui.getAcPlayIcon().setIcon(2);
+ ui.getAcTimeIcon().setIcon(1);
+ }
+
+ /**
+ * Process PLAY event.
+ * @param modifiers
+ */
+ protected void processPlay(int modifiers)
+ {
+ if (playlist.isModified()) // playlist has been modified since we were last there, must update our cursor pos etc.
+ {
+ PlaylistItem pli = playlist.getCursor();
+ if (pli == null)
+ {
+ playlist.begin();
+ pli = playlist.getCursor();
+ }
+ setCurrentSong(pli);
+ playlist.setModified(false);
+ playlistUI.repaint();
+ }
+ // Resume is paused.
+ if (playerState == PAUSE)
+ {
+ try
+ {
+ theSoundPlayer.resume();
+ }
+ catch (BasicPlayerException e)
+ {
+ log.error("Cannot resume", e);
+ }
+ playerState = PLAY;
+ ui.getAcPlayIcon().setIcon(0);
+ ui.getAcTimeIcon().setIcon(0);
+ }
+ // Stop if playing.
+ else if (playerState == PLAY)
+ {
+ try
+ {
+ theSoundPlayer.stop();
+ }
+ catch (BasicPlayerException e)
+ {
+ log.error("Cannot stop", e);
+ }
+ playerState = PLAY;
+ secondsAmount = 0;
+ ui.getAcMinuteH().setAcText("0");
+ ui.getAcMinuteL().setAcText("0");
+ ui.getAcSecondH().setAcText("0");
+ ui.getAcSecondL().setAcText("0");
+ if (currentFileOrURL != null)
+ {
+ try
+ {
+ if (currentIsFile == true) theSoundPlayer.open(openFile(currentFileOrURL));
+ else
+ {
+ theSoundPlayer.open(new URL(currentFileOrURL));
+ }
+ theSoundPlayer.play();
+ }
+ catch (Exception ex)
+ {
+ log.error("Cannot read file : " + currentFileOrURL, ex);
+ showMessage(ui.getResource("title.invalidfile"));
+ }
+ }
+ }
+ else if ((playerState == STOP) || (playerState == OPEN))
+ {
+ try
+ {
+ theSoundPlayer.stop();
+ }
+ catch (BasicPlayerException e)
+ {
+ log.error("Stop failed", e);
+ }
+ if (currentFileOrURL != null)
+ {
+ try
+ {
+ if (currentIsFile == true) theSoundPlayer.open(openFile(currentFileOrURL));
+ else theSoundPlayer.open(new URL(currentFileOrURL));
+ theSoundPlayer.play();
+ titleText = currentSongName.toUpperCase();
+ // Get bitrate, samplingrate, channels, time in the following order :
+ // PlaylistItem, BasicPlayer (JavaSound SPI), Manual computation.
+ int bitRate = -1;
+ if (currentPlaylistItem != null) bitRate = currentPlaylistItem.getBitrate();
+ if ((bitRate <= 0) && (audioInfo.containsKey("bitrate"))) bitRate = ((Integer) audioInfo.get("bitrate")).intValue();
+ if ((bitRate <= 0) && (audioInfo.containsKey("audio.framerate.fps")) && (audioInfo.containsKey("audio.framesize.bytes")))
+ {
+ float FR = ((Float) audioInfo.get("audio.framerate.fps")).floatValue();
+ int FS = ((Integer) audioInfo.get("audio.framesize.bytes")).intValue();
+ bitRate = Math.round(FS * FR * 8);
+ }
+ int channels = -1;
+ if (currentPlaylistItem != null) channels = currentPlaylistItem.getChannels();
+ if ((channels <= 0) && (audioInfo.containsKey("audio.channels"))) channels = ((Integer) audioInfo.get("audio.channels")).intValue();
+ float sampleRate = -1.0f;
+ if (currentPlaylistItem != null) sampleRate = currentPlaylistItem.getSamplerate();
+ if ((sampleRate <= 0) && (audioInfo.containsKey("audio.samplerate.hz"))) sampleRate = ((Float) audioInfo.get("audio.samplerate.hz")).floatValue();
+ long lenghtInSecond = -1L;
+ if (currentPlaylistItem != null) lenghtInSecond = currentPlaylistItem.getLength();
+ if ((lenghtInSecond <= 0) && (audioInfo.containsKey("duration"))) lenghtInSecond = ((Long) audioInfo.get("duration")).longValue() / 1000000;
+ if ((lenghtInSecond <= 0) && (audioInfo.containsKey("audio.length.bytes")))
+ {
+ // Try to compute time length.
+ lenghtInSecond = (long) Math.round(getTimeLengthEstimation(audioInfo) / 1000);
+ if (lenghtInSecond > 0)
+ {
+ int minutes = (int) Math.floor(lenghtInSecond / 60);
+ int hours = (int) Math.floor(minutes / 60);
+ minutes = minutes - hours * 60;
+ int seconds = (int) (lenghtInSecond - minutes * 60 - hours * 3600);
+ if (seconds >= 10) titleText = "(" + minutes + ":" + seconds + ") " + titleText;
+ else titleText = "(" + minutes + ":0" + seconds + ") " + titleText;
+ }
+ }
+ bitRate = Math.round((bitRate / 1000));
+ ui.getAcSampleRateLabel().setAcText(String.valueOf(Math.round((sampleRate / 1000))));
+ if (bitRate > 999)
+ {
+ bitRate = (int) (bitRate / 100);
+ ui.getAcBitRateLabel().setAcText(bitRate + "H");
+ }
+ else
+ {
+ ui.getAcBitRateLabel().setAcText(String.valueOf(bitRate));
+ }
+ if (channels == 2)
+ {
+ ui.getAcStereoIcon().setIcon(1);
+ ui.getAcMonoIcon().setIcon(0);
+ }
+ else if (channels == 1)
+ {
+ ui.getAcStereoIcon().setIcon(0);
+ ui.getAcMonoIcon().setIcon(1);
+ }
+ showTitle(titleText);
+ ui.getAcMinuteH().setAcText("0");
+ ui.getAcMinuteL().setAcText("0");
+ ui.getAcSecondH().setAcText("0");
+ ui.getAcSecondL().setAcText("0");
+ ui.getAcPlayIcon().setIcon(0);
+ ui.getAcTimeIcon().setIcon(0);
+ }
+ catch (BasicPlayerException bpe)
+ {
+ log.info("Stream error :" + currentFileOrURL, bpe);
+ showMessage(ui.getResource("title.invalidfile"));
+ }
+ catch (MalformedURLException mue)
+ {
+ log.info("Stream error :" + currentFileOrURL, mue);
+ showMessage(ui.getResource("title.invalidfile"));
+ }
+ // Set pan/gain.
+ try
+ {
+ theSoundPlayer.setGain(((double) ui.getAcVolume().getValue() / (double) ui.getAcVolume().getMaximum()));
+ theSoundPlayer.setPan((float) ui.getAcBalance().getValue() / 10.0f);
+ }
+ catch (BasicPlayerException e)
+ {
+ log.info("Cannot set control", e);
+ }
+ playerState = PLAY;
+ log.info(titleText);
+ }
+ }
+ }
+
+ /**
+ * Process PAUSE event.
+ * @param modifiers
+ */
+ public void processPause(int modifiers)
+ {
+ if (playerState == PLAY)
+ {
+ try
+ {
+ theSoundPlayer.pause();
+ }
+ catch (BasicPlayerException e)
+ {
+ log.error("Cannot pause", e);
+ }
+ playerState = PAUSE;
+ ui.getAcPlayIcon().setIcon(1);
+ ui.getAcTimeIcon().setIcon(1);
+ }
+ else if (playerState == PAUSE)
+ {
+ try
+ {
+ theSoundPlayer.resume();
+ }
+ catch (BasicPlayerException e)
+ {
+ log.info("Cannot resume", e);
+ }
+ playerState = PLAY;
+ ui.getAcPlayIcon().setIcon(0);
+ ui.getAcTimeIcon().setIcon(0);
+ }
+ }
+
+ /**
+ * Process STOP event.
+ * @param modifiers
+ */
+ public void processStop(int modifiers)
+ {
+ if ((playerState == PAUSE) || (playerState == PLAY))
+ {
+ try
+ {
+ theSoundPlayer.stop();
+ }
+ catch (BasicPlayerException e)
+ {
+ log.info("Cannot stop", e);
+ }
+ playerState = STOP;
+ secondsAmount = 0;
+ ui.getAcPosBar().setValue(0);
+ ui.getAcPlayIcon().setIcon(2);
+ ui.getAcTimeIcon().setIcon(1);
+ }
+ }
+
+ /**
+ * Process NEXT event.
+ * @param modifiers
+ */
+ public void processNext(int modifiers)
+ {
+ // Try to get next song from the playlist
+ playlist.nextCursor();
+ playlistUI.nextCursor();
+ PlaylistItem pli = playlist.getCursor();
+ setCurrentSong(pli);
+ }
+
+ /**
+ * Process PREVIOUS event.
+ * @param modifiers
+ */
+ public void processPrevious(int modifiers)
+ {
+ // Try to get previous song from the playlist
+ playlist.previousCursor();
+ playlistUI.nextCursor();
+ PlaylistItem pli = playlist.getCursor();
+ setCurrentSong(pli);
+ }
+
+ /**
+ * Process STATEUPDATED event.
+ * @param event
+ */
+ public void processStateUpdated(BasicPlayerEvent event)
+ {
+ log.debug("Player:" + event + " (EDT=" + SwingUtilities.isEventDispatchThread() + ")");
+ /*-- End Of Media reached --*/
+ int state = event.getCode();
+ Object obj = event.getDescription();
+ if (state == BasicPlayerEvent.EOM)
+ {
+ if ((playerState == PAUSE) || (playerState == PLAY))
+ {
+ playlist.nextCursor();
+ playlistUI.nextCursor();
+ PlaylistItem pli = playlist.getCursor();
+ setCurrentSong(pli);
+ }
+ }
+ else if (state == BasicPlayerEvent.PLAYING)
+ {
+ lastScrollTime = System.currentTimeMillis();
+ posValueJump = false;
+ if (audioInfo.containsKey("basicplayer.sourcedataline"))
+ {
+ if (ui.getAcAnalyzer() != null)
+ {
+ ui.getAcAnalyzer().setupDSP((SourceDataLine) audioInfo.get("basicplayer.sourcedataline"));
+ ui.getAcAnalyzer().startDSP((SourceDataLine) audioInfo.get("basicplayer.sourcedataline"));
+ }
+ }
+ }
+ else if (state == BasicPlayerEvent.SEEKING)
+ {
+ posValueJump = true;
+ }
+ else if (state == BasicPlayerEvent.SEEKED)
+ {
+ try
+ {
+ theSoundPlayer.setGain(((double) ui.getAcVolume().getValue() / (double) ui.getAcVolume().getMaximum()));
+ theSoundPlayer.setPan((float) ui.getAcBalance().getValue() / 10.0f);
+ }
+ catch (BasicPlayerException e)
+ {
+ log.debug(e);
+ }
+ }
+ else if (state == BasicPlayerEvent.OPENING)
+ {
+ if ((obj instanceof URL) || (obj instanceof InputStream))
+ {
+ showTitle(ui.getResource("title.buffering"));
+ }
+ }
+ else if (state == BasicPlayerEvent.STOPPED)
+ {
+ if (ui.getAcAnalyzer() != null)
+ {
+ ui.getAcAnalyzer().stopDSP();
+ ui.getAcAnalyzer().repaint();
+ }
+ }
+ }
+
+ /**
+ * Process PROGRESS event.
+ * @param bytesread
+ * @param microseconds
+ * @param pcmdata
+ * @param properties
+ */
+ public void processProgress(int bytesread, long microseconds, byte[] pcmdata, Map properties)
+ {
+ //log.debug("Player: Progress (EDT="+SwingUtilities.isEventDispatchThread()+")");
+ int byteslength = -1;
+ long total = -1;
+ // Try to get time from playlist item.
+ if (currentPlaylistItem != null) total = currentPlaylistItem.getLength();
+ // If it fails then try again with JavaSound SPI.
+ if (total <= 0) total = (long) Math.round(getTimeLengthEstimation(audioInfo) / 1000);
+ // If it fails again then it might be stream => Total = -1
+ if (total <= 0) total = -1;
+ if (audioInfo.containsKey("basicplayer.sourcedataline"))
+ {
+ // Spectrum/time analyzer
+ if (ui.getAcAnalyzer() != null) ui.getAcAnalyzer().writeDSP(pcmdata);
+ }
+ if (audioInfo.containsKey("audio.length.bytes"))
+ {
+ byteslength = ((Integer) audioInfo.get("audio.length.bytes")).intValue();
+ }
+ float progress = -1.0f;
+ if ((bytesread > 0) && ((byteslength > 0))) progress = bytesread * 1.0f / byteslength * 1.0f;
+ if (audioInfo.containsKey("audio.type"))
+ {
+ String audioformat = (String) audioInfo.get("audio.type");
+ if (audioformat.equalsIgnoreCase("mp3"))
+ {
+ //if (properties.containsKey("mp3.position.microseconds")) secondsAmount = (long) Math.round(((Long) properties.get("mp3.position.microseconds")).longValue()/1000000);
+ // Shoutcast stream title.
+ if (properties.containsKey("mp3.shoutcast.metadata.StreamTitle"))
+ {
+ String shoutTitle = ((String) properties.get("mp3.shoutcast.metadata.StreamTitle")).trim();
+ if (shoutTitle.length() > 0)
+ {
+ if (currentPlaylistItem != null)
+ {
+ String sTitle = " (" + currentPlaylistItem.getFormattedDisplayName() + ")";
+ if (!currentPlaylistItem.getFormattedName().equals(shoutTitle + sTitle))
+ {
+ currentPlaylistItem.setFormattedDisplayName(shoutTitle + sTitle);
+ showTitle((shoutTitle + sTitle).toUpperCase());
+ playlistUI.paintList();
+ }
+ }
+ }
+ }
+ // EqualizerUI
+ if (properties.containsKey("mp3.equalizer")) equalizerUI.setBands((float[]) properties.get("mp3.equalizer"));
+ if (total > 0) secondsAmount = (long) (total * progress);
+ else secondsAmount = -1;
+ }
+ else if (audioformat.equalsIgnoreCase("wave"))
+ {
+ secondsAmount = (long) (total * progress);
+ }
+ else
+ {
+ secondsAmount = (long) Math.round(microseconds / 1000000);
+ equalizerUI.setBands(null);
+ }
+ }
+ else
+ {
+ secondsAmount = (long) Math.round(microseconds / 1000000);
+ equalizerUI.setBands(null);
+ }
+ if (secondsAmount < 0) secondsAmount = (long) Math.round(microseconds / 1000000);
+ /*-- Display elapsed time --*/
+ int secondD = 0, second = 0, minuteD = 0, minute = 0;
+ int seconds = (int) secondsAmount;
+ int minutes = (int) Math.floor(seconds / 60);
+ int hours = (int) Math.floor(minutes / 60);
+ minutes = minutes - hours * 60;
+ seconds = seconds - minutes * 60 - hours * 3600;
+ if (seconds < 10)
+ {
+ secondD = 0;
+ second = seconds;
+ }
+ else
+ {
+ secondD = ((int) seconds / 10);
+ second = ((int) (seconds - (((int) seconds / 10)) * 10));
+ }
+ if (minutes < 10)
+ {
+ minuteD = 0;
+ minute = minutes;
+ }
+ else
+ {
+ minuteD = ((int) minutes / 10);
+ minute = ((int) (minutes - (((int) minutes / 10)) * 10));
+ }
+ ui.getAcMinuteH().setAcText(String.valueOf(minuteD));
+ ui.getAcMinuteL().setAcText(String.valueOf(minute));
+ ui.getAcSecondH().setAcText(String.valueOf(secondD));
+ ui.getAcSecondL().setAcText(String.valueOf(second));
+ // Update PosBar location.
+ if (total != 0)
+ {
+ if (posValueJump == false)
+ {
+ int posValue = ((int) Math.round(secondsAmount * Skin.POSBARMAX / total));
+ ui.getAcPosBar().setValue(posValue);
+ }
+ }
+ else ui.getAcPosBar().setValue(0);
+ long ctime = System.currentTimeMillis();
+ long lctime = lastScrollTime;
+ // Scroll title ?
+ if ((titleScrollLabel != null) && (titleScrollLabel.length > 0))
+ {
+ if (ctime - lctime > SCROLL_PERIOD)
+ {
+ lastScrollTime = ctime;
+ if (scrollRight == true)
+ {
+ scrollIndex++;
+ if (scrollIndex >= titleScrollLabel.length)
+ {
+ scrollIndex--;
+ scrollRight = false;
+ }
+ }
+ else
+ {
+ scrollIndex--;
+ if (scrollIndex <= 0)
+ {
+ scrollRight = true;
+ }
+ }
+ // TODO : Improve
+ ui.getAcTitleLabel().setAcText(titleScrollLabel[scrollIndex]);
+ }
+ }
+ }
+
+ /**
+ * Process seek feature.
+ * @param rate
+ */
+ protected void processSeek(double rate)
+ {
+ try
+ {
+ if ((audioInfo != null) && (audioInfo.containsKey("audio.type")))
+ {
+ String type = (String) audioInfo.get("audio.type");
+ // Seek support for MP3.
+ if ((type.equalsIgnoreCase("mp3")) && (audioInfo.containsKey("audio.length.bytes")))
+ {
+ long skipBytes = (long) Math.round(((Integer) audioInfo.get("audio.length.bytes")).intValue() * rate);
+ log.debug("Seek value (MP3) : " + skipBytes);
+ theSoundPlayer.seek(skipBytes);
+ }
+ // Seek support for WAV.
+ else if ((type.equalsIgnoreCase("wave")) && (audioInfo.containsKey("audio.length.bytes")))
+ {
+ long skipBytes = (long) Math.round(((Integer) audioInfo.get("audio.length.bytes")).intValue() * rate);
+ log.debug("Seek value (WAVE) : " + skipBytes);
+ theSoundPlayer.seek(skipBytes);
+ }
+ else posValueJump = false;
+ }
+ else posValueJump = false;
+ }
+ catch (BasicPlayerException ioe)
+ {
+ log.error("Cannot skip", ioe);
+ posValueJump = false;
+ }
+ }
+
+ /**
+ * Process Drag&Drop
+ * @param data
+ */
+ public void processDnD(Object data)
+ {
+ log.debug("Player DnD");
+ // Looking for files to drop.
+ if (data instanceof List)
+ {
+ List al = (List) data;
+ if ((al != null) && (al.size() > 0))
+ {
+ ArrayList fileList = new ArrayList();
+ ArrayList folderList = new ArrayList();
+ ListIterator li = al.listIterator();
+ while (li.hasNext())
+ {
+ File f = (File) li.next();
+ if ((f.exists()) && (f.canRead()))
+ {
+ if (f.isFile()) fileList.add(f);
+ else if (f.isDirectory()) folderList.add(f);
+ }
+ }
+ playFiles(fileList);
+ // TODO : Add dir support
+ }
+ }
+ else if (data instanceof String)
+ {
+ String files = (String) data;
+ if ((files.length() > 0))
+ {
+ ArrayList fileList = new ArrayList();
+ ArrayList folderList = new ArrayList();
+ StringTokenizer st = new StringTokenizer(files, System.getProperty("line.separator"));
+ // Transfer files dropped.
+ while (st.hasMoreTokens())
+ {
+ String path = st.nextToken();
+ if (path.startsWith("file://"))
+ {
+ path = path.substring(7, path.length());
+ if (path.endsWith("\r")) path = path.substring(0, (path.length() - 1));
+ }
+ File f = new File(path);
+ if ((f.exists()) && (f.canRead()))
+ {
+ if (f.isFile()) fileList.add(f);
+ else if (f.isDirectory()) folderList.add(f);
+ }
+ }
+ playFiles(fileList);
+ // TODO : Add dir support
+ }
+ }
+ else
+ {
+ log.info("Unknown dropped objects");
+ }
+ }
+
+ /**
+ * Play files from a list.
+ * @param files
+ */
+ protected void playFiles(List files)
+ {
+ if (files.size() > 0)
+ {
+ // Clean the playlist.
+ playlist.removeAllItems();
+ // Add all dropped files to playlist.
+ ListIterator li = files.listIterator();
+ while (li.hasNext())
+ {
+ File file = (File) li.next();
+ PlaylistItem pli = null;
+ if (file != null)
+ {
+ pli = new PlaylistItem(file.getName(), file.getAbsolutePath(), -1, true);
+ if (pli != null) playlist.appendItem(pli);
+ }
+ }
+ // Start the playlist from the top.
+ playlist.nextCursor();
+ playlistUI.initPlayList();
+ setCurrentSong(playlist.getCursor());
+ }
+ }
+
+ /**
+ * Sets the current song to play and start playing if needed.
+ * @param pli
+ */
+ public void setCurrentSong(PlaylistItem pli)
+ {
+ int playerStateMem = playerState;
+ if ((playerState == PAUSE) || (playerState == PLAY))
+ {
+ try
+ {
+ theSoundPlayer.stop();
+ }
+ catch (BasicPlayerException e)
+ {
+ log.error("Cannot stop", e);
+ }
+ playerState = STOP;
+ secondsAmount = 0;
+ // Display play/time icons.
+ ui.getAcPlayIcon().setIcon(2);
+ ui.getAcTimeIcon().setIcon(0);
+ }
+ playerState = OPEN;
+ if (pli != null)
+ {
+ // Read tag info.
+ pli.getTagInfo();
+ currentSongName = pli.getFormattedName();
+ currentFileOrURL = pli.getLocation();
+ currentIsFile = pli.isFile();
+ currentPlaylistItem = pli;
+ }
+ // Playlist ended.
+ else
+ {
+ // Try to repeat ?
+ if (config.isRepeatEnabled())
+ {
+ if (playlist != null)
+ {
+ // PlaylistItems available ?
+ if (playlist.getPlaylistSize() > 0)
+ {
+ playlist.begin();
+ PlaylistItem rpli = playlist.getCursor();
+ if (rpli != null)
+ {
+ // OK, Repeat the playlist.
+ rpli.getTagInfo();
+ currentSongName = rpli.getFormattedName();
+ currentFileOrURL = rpli.getLocation();
+ currentIsFile = rpli.isFile();
+ currentPlaylistItem = rpli;
+ }
+ }
+ // No, so display Title.
+ else
+ {
+ currentSongName = Skin.TITLETEXT;
+ currentFileOrURL = null;
+ currentIsFile = false;
+ currentPlaylistItem = null;
+ }
+ }
+ }
+ // No, so display Title.
+ else
+ {
+ currentSongName = Skin.TITLETEXT;
+ currentFileOrURL = null;
+ currentIsFile = false;
+ currentPlaylistItem = null;
+ }
+ }
+ if (currentIsFile == true)
+ {
+ ui.getAcPosBar().setEnabled(true);
+ ui.getAcPosBar().setHideThumb(false);
+ }
+ else
+ {
+ config.setLastURL(currentFileOrURL);
+ ui.getAcPosBar().setEnabled(false);
+ ui.getAcPosBar().setHideThumb(true);
+ }
+ titleText = currentSongName.toUpperCase();
+ showMessage(titleText);
+ // Start playing if needed.
+ if ((playerStateMem == PLAY) || (playerStateMem == PAUSE))
+ {
+ processPlay(MouseEvent.BUTTON1_MASK);
+ }
+ }
+
+ /**
+ * Display text in title area.
+ * @param str
+ */
+ public void showTitle(String str)
+ {
+ if (str != null)
+ {
+ currentTitle = str;
+ titleScrollLabel = null;
+ scrollIndex = 0;
+ scrollRight = true;
+ if (str.length() > TEXT_LENGTH_MAX)
+ {
+ int a = ((str.length()) - (TEXT_LENGTH_MAX)) + 1;
+ titleScrollLabel = new String[a];
+ for (int k = 0; k < a; k++)
+ {
+ String sText = str.substring(k, TEXT_LENGTH_MAX + k);
+ titleScrollLabel[k] = sText;
+ }
+ str = str.substring(0, TEXT_LENGTH_MAX);
+ }
+ ui.getAcTitleLabel().setAcText(str);
+ }
+ }
+
+ /**
+ * Shows message in title an updates bitRate,sampleRate, Mono/Stereo,time features.
+ * @param txt
+ */
+ public void showMessage(String txt)
+ {
+ showTitle(txt);
+ ui.getAcSampleRateLabel().setAcText(" ");
+ ui.getAcBitRateLabel().setAcText(" ");
+ ui.getAcStereoIcon().setIcon(0);
+ ui.getAcMonoIcon().setIcon(0);
+ ui.getAcMinuteH().setAcText("0");
+ ui.getAcMinuteL().setAcText("0");
+ ui.getAcSecondH().setAcText("0");
+ ui.getAcSecondL().setAcText("0");
+ }
+
+ /**
+ * Toggle playlistUI.
+ */
+ protected void togglePlaylist()
+ {
+ if (ui.getAcPlaylist().isSelected())
+ {
+ miPlaylist.setState(true);
+ config.setPlaylistEnabled(true);
+ loader.togglePlaylist(true);
+ }
+ else
+ {
+ miPlaylist.setState(false);
+ config.setPlaylistEnabled(false);
+ loader.togglePlaylist(false);
+ }
+ }
+
+ /**
+ * Toggle equalizerUI.
+ */
+ protected void toggleEqualizer()
+ {
+ if (ui.getAcEqualizer().isSelected())
+ {
+ miEqualizer.setState(true);
+ config.setEqualizerEnabled(true);
+ loader.toggleEqualizer(true);
+ }
+ else
+ {
+ miEqualizer.setState(false);
+ config.setEqualizerEnabled(false);
+ loader.toggleEqualizer(false);
+ }
+ }
+
+ /**
+ * Returns a File from a filename.
+ * @param file
+ * @return
+ */
+ protected File openFile(String file)
+ {
+ return new File(file);
+ }
+
+ /**
+ * Free resources and close the player.
+ */
+ protected void closePlayer()
+ {
+ if ((playerState == PAUSE) || (playerState == PLAY))
+ {
+ try
+ {
+ if (theSoundPlayer != null)
+ {
+ theSoundPlayer.stop();
+ }
+ }
+ catch (BasicPlayerException e)
+ {
+ log.error("Cannot stop", e);
+ }
+ }
+ if (theSoundPlayer != null)
+ {
+ config.setAudioDevice(((BasicPlayer) theSoundPlayer).getMixerName());
+ }
+ if (ui.getAcAnalyzer() != null)
+ {
+ if (ui.getAcAnalyzer().getDisplayMode() == SpectrumTimeAnalyzer.DISPLAY_MODE_OFF) config.setVisualMode("off");
+ else if (ui.getAcAnalyzer().getDisplayMode() == SpectrumTimeAnalyzer.DISPLAY_MODE_SCOPE) config.setVisualMode("oscillo");
+ else config.setVisualMode("spectrum");
+ }
+ if (playlist != null)
+ {
+ playlist.save("default.m3u");
+ config.setPlaylistFilename("default.m3u");
+ }
+ loader.close();
+ }
+
+ /**
+ * Return current title in player.
+ * @return
+ */
+ public String getCurrentTitle()
+ {
+ return currentTitle;
+ }
+
+ /**
+ * Try to compute time length in milliseconds.
+ * @param properties
+ * @return
+ */
+ public long getTimeLengthEstimation(Map properties)
+ {
+ long milliseconds = -1;
+ int byteslength = -1;
+ if (properties != null)
+ {
+ if (properties.containsKey("audio.length.bytes"))
+ {
+ byteslength = ((Integer) properties.get("audio.length.bytes")).intValue();
+ }
+ if (properties.containsKey("duration"))
+ {
+ milliseconds = (int) (((Long) properties.get("duration")).longValue()) / 1000;
+ }
+ else
+ {
+ // Try to compute duration
+ int bitspersample = -1;
+ int channels = -1;
+ float samplerate = -1.0f;
+ int framesize = -1;
+ if (properties.containsKey("audio.samplesize.bits"))
+ {
+ bitspersample = ((Integer) properties.get("audio.samplesize.bits")).intValue();
+ }
+ if (properties.containsKey("audio.channels"))
+ {
+ channels = ((Integer) properties.get("audio.channels")).intValue();
+ }
+ if (properties.containsKey("audio.samplerate.hz"))
+ {
+ samplerate = ((Float) properties.get("audio.samplerate.hz")).floatValue();
+ }
+ if (properties.containsKey("audio.framesize.bytes"))
+ {
+ framesize = ((Integer) properties.get("audio.framesize.bytes")).intValue();
+ }
+ if (bitspersample > 0)
+ {
+ milliseconds = (int) (1000.0f * byteslength / (samplerate * channels * (bitspersample / 8)));
+ }
+ else
+ {
+ milliseconds = (int) (1000.0f * byteslength / (samplerate * framesize));
+ }
+ }
+ }
+ return milliseconds;
+ }
+
+ /**
+ * Simulates "Play" selection.
+ */
+ public void pressStart()
+ {
+ ui.getAcPlay().doClick();
+ }
+
+ /**
+ * Simulates "Pause" selection.
+ */
+ public void pressPause()
+ {
+ ui.getAcPause().doClick();
+ }
+
+ /**
+ * Simulates "Stop" selection.
+ */
+ public void pressStop()
+ {
+ ui.getAcStop().doClick();
+ }
+
+ /**
+ * Simulates "Next" selection.
+ */
+ public void pressNext()
+ {
+ ui.getAcNext().doClick();
+ }
+
+ /**
+ * Simulates "Previous" selection.
+ */
+ public void pressPrevious()
+ {
+ ui.getAcPrevious().doClick();
+ }
+
+ /**
+ * Simulates "Eject" selection.
+ */
+ public void pressEject()
+ {
+ ui.getAcEject().doClick();
+ }
+}
diff --git a/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/StandalonePlayer.java b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/StandalonePlayer.java
new file mode 100644
index 0000000..ec249d2
--- /dev/null
+++ b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/StandalonePlayer.java
@@ -0,0 +1,500 @@
+/*
+ * StandalonePlayer.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp;
+
+import java.awt.Dimension;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.List;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ImageIcon;
+import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JWindow;
+import javax.swing.KeyStroke;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javazoom.jlgui.basicplayer.BasicPlayer;
+import javazoom.jlgui.player.amp.skin.DragAdapter;
+import javazoom.jlgui.player.amp.skin.Skin;
+import javazoom.jlgui.player.amp.util.Config;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class StandalonePlayer extends JFrame implements Loader
+{
+ private static Log log = LogFactory.getLog(StandalonePlayer.class);
+ /*-- Run parameters --*/
+ private String initConfig = "jlgui.ini";
+ private String initSong = null;
+ private String showPlaylist = null;
+ private String showEqualizer = null;
+ private String showDsp = null;
+ private String skinPath = null;
+ private String skinVersion = "1"; // 1, 2, for different Volume.bmp
+ private boolean autoRun = false;
+ /*-- Front-end --*/
+ private PlayerUI mp = null;
+ private JWindow eqWin = null;
+ private JWindow plWin = null;
+ private int eqFactor = 2;
+ private Config config = null;
+ private boolean playlistfound = false;
+
+ public StandalonePlayer()
+ {
+ super();
+ }
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args)
+ {
+ final StandalonePlayer player = new StandalonePlayer();
+ player.parseParameters(args);
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ player.loadUI();
+ player.loadJS();
+ player.loadPlaylist();
+ player.boot();
+ }
+ });
+ }
+
+ /**
+ * Initialize the player front-end.
+ * @param args
+ */
+ private void parseParameters(String[] args)
+ {
+ String currentArg = null;
+ String currentValue = null;
+ for (int i = 0; i < args.length; i++)
+ {
+ currentArg = args[i];
+ if (currentArg.startsWith("-"))
+ {
+ if (currentArg.toLowerCase().equals("-init"))
+ {
+ i++;
+ if (i >= args.length) usage("init value missing");
+ currentValue = args[i];
+ if (Config.startWithProtocol(currentValue)) initConfig = currentValue;
+ else initConfig = currentValue.replace('\\', '/').replace('/', java.io.File.separatorChar);
+ }
+ else if (currentArg.toLowerCase().equals("-song"))
+ {
+ i++;
+ if (i >= args.length) usage("song value missing");
+ currentValue = args[i];
+ if (Config.startWithProtocol(currentValue)) initSong = currentValue;
+ else initSong = currentValue.replace('\\', '/').replace('/', java.io.File.separatorChar);
+ }
+ else if (currentArg.toLowerCase().equals("-start"))
+ {
+ autoRun = true;
+ }
+ else if (currentArg.toLowerCase().equals("-showplaylist"))
+ {
+ showPlaylist = "true";
+ }
+ else if (currentArg.toLowerCase().equals("-showequalizer"))
+ {
+ showEqualizer = "true";
+ }
+ else if (currentArg.toLowerCase().equals("-disabledsp"))
+ {
+ showDsp = "false";
+ }
+ else if (currentArg.toLowerCase().equals("-skin"))
+ {
+ i++;
+ if (i >= args.length) usage("skin value missing");
+ currentValue = args[i];
+ if (Config.startWithProtocol(currentValue)) skinPath = currentValue;
+ else skinPath = currentValue.replace('\\', '/').replace('/', java.io.File.separatorChar);
+ }
+ else if (currentArg.toLowerCase().equals("-v"))
+ {
+ i++;
+ if (i >= args.length) usage("skin version value missing");
+ skinVersion = args[i];
+ }
+ else usage("Unknown parameter : " + currentArg);
+ }
+ else
+ {
+ usage("Invalid parameter :" + currentArg);
+ }
+ }
+ }
+
+ private void boot()
+ {
+ // Go to playlist begining if needed.
+ /*if ((playlist != null) && (playlistfound == true))
+ {
+ if (playlist.getPlaylistSize() > 0) mp.pressNext();
+ } */
+ // Start playing if needed.
+ if (autoRun == true)
+ {
+ mp.pressStart();
+ }
+ }
+
+ /**
+ * Instantiate low-level player.
+ */
+ public void loadJS()
+ {
+ BasicPlayer bplayer = new BasicPlayer();
+ List mixers = bplayer.getMixers();
+ if (mixers != null)
+ {
+ Iterator it = mixers.iterator();
+ String mixer = config.getAudioDevice();
+ boolean mixerFound = false;
+ if ((mixer != null) && (mixer.length() > 0))
+ {
+ // Check if mixer is valid.
+ while (it.hasNext())
+ {
+ if (((String) it.next()).equals(mixer))
+ {
+ bplayer.setMixerName(mixer);
+ mixerFound = true;
+ break;
+ }
+ }
+ }
+ if (mixerFound == false)
+ {
+ // Use first mixer available.
+ it = mixers.iterator();
+ if (it.hasNext())
+ {
+ mixer = (String) it.next();
+ bplayer.setMixerName(mixer);
+ }
+ }
+ }
+ // Register the front-end to low-level player events.
+ bplayer.addBasicPlayerListener(mp);
+ // Adds controls for front-end to low-level player.
+ mp.setController(bplayer);
+ }
+
+ /**
+ * Load playlist.
+ */
+ public void loadPlaylist()
+ {
+ if ((initSong != null) && (!initSong.equals(""))) playlistfound = mp.loadPlaylist(initSong);
+ else playlistfound = mp.loadPlaylist(config.getPlaylistFilename());
+ }
+
+ /**
+ * Load player front-end.
+ */
+ public void loadUI()
+ {
+ try
+ {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ }
+ catch (Exception ex)
+ {
+ log.debug(ex);
+ }
+ config = Config.getInstance();
+ config.load(initConfig);
+ config.setTopParent(this);
+ if (showPlaylist != null)
+ {
+ if (showPlaylist.equalsIgnoreCase("true"))
+ {
+ config.setPlaylistEnabled(true);
+ }
+ else
+ {
+ config.setPlaylistEnabled(false);
+ }
+ }
+ if (showEqualizer != null)
+ {
+ if (showEqualizer.equalsIgnoreCase("true"))
+ {
+ config.setEqualizerEnabled(true);
+ }
+ else
+ {
+ config.setEqualizerEnabled(false);
+ }
+ }
+ if (config.isPlaylistEnabled()) eqFactor = 2;
+ else eqFactor = 1;
+ setTitle(Skin.TITLETEXT);
+ ClassLoader cl = this.getClass().getClassLoader();
+ URL iconURL = cl.getResource("javazoom/jlgui/player/amp/jlguiicon.gif");
+ if (iconURL != null)
+ {
+ ImageIcon jlguiIcon = new ImageIcon(iconURL);
+ setIconImage(jlguiIcon.getImage());
+ config.setIconParent(jlguiIcon);
+ }
+ setUndecorated(true);
+ mp = new PlayerUI();
+ if ((showDsp != null) && (showDsp.equalsIgnoreCase("false")))
+ {
+ mp.getSkin().setDspEnabled(false);
+ }
+ if (skinPath != null)
+ {
+ mp.getSkin().setPath(skinPath);
+ }
+ mp.getSkin().setSkinVersion(skinVersion);
+ mp.loadUI(this);
+ setContentPane(mp);
+ setSize(new Dimension(mp.getSkin().getMainWidth(), mp.getSkin().getMainHeight()));
+ eqWin = new JWindow(this);
+ eqWin.setContentPane(mp.getEqualizerUI());
+ eqWin.setSize(new Dimension(mp.getSkin().getMainWidth(), mp.getSkin().getMainHeight()));
+ eqWin.setVisible(false);
+ plWin = new JWindow(this);
+ plWin.setContentPane(mp.getPlaylistUI());
+ plWin.setSize(new Dimension(mp.getSkin().getMainWidth(), mp.getSkin().getMainHeight()));
+ plWin.setVisible(false);
+ // Window listener
+ addWindowListener(new WindowAdapter()
+ {
+ public void windowClosing(WindowEvent e)
+ {
+ // Closing window (Alt+F4 under Win32)
+ close();
+ }
+ });
+ // Keyboard shortcut
+ setKeyBoardShortcut();
+ // Display front-end
+ setLocation(config.getXLocation(), config.getYLocation());
+ setVisible(true);
+ if (config.isPlaylistEnabled()) plWin.setVisible(true);
+ if (config.isEqualizerEnabled()) eqWin.setVisible(true);
+ }
+
+ /**
+ * Install keyboard shortcuts.
+ */
+ public void setKeyBoardShortcut()
+ {
+ KeyStroke jKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_J, 0, false);
+ KeyStroke ctrlPKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_P, KeyEvent.CTRL_MASK, false);
+ KeyStroke altSKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.ALT_MASK, false);
+ KeyStroke vKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_V, 0, false);
+ String searchID = "TAGSEARCH";
+ String preferenceID = "PREFERENCES";
+ String skinbrowserID = "SKINBROWSER";
+ String stopplayerID = "STOPPLAYER";
+ Action searchAction = new AbstractAction()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ if (mp != null) mp.processJumpToFile(e.getModifiers());
+ }
+ };
+ Action preferencesAction = new AbstractAction()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ if (mp != null) mp.processPreferences(e.getModifiers());
+ }
+ };
+ Action skinbrowserAction = new AbstractAction()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ if (mp != null) mp.processSkinBrowser(e.getModifiers());
+ }
+ };
+ Action stopplayerAction = new AbstractAction()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ if (mp != null) mp.processStop(MouseEvent.BUTTON1_MASK);
+ }
+ };
+ setKeyboardAction(searchID, jKeyStroke, searchAction);
+ setKeyboardAction(preferenceID, ctrlPKeyStroke, preferencesAction);
+ setKeyboardAction(skinbrowserID, altSKeyStroke, skinbrowserAction);
+ setKeyboardAction(stopplayerID, vKeyStroke, stopplayerAction);
+ }
+
+ /**
+ * Set keyboard key shortcut for the whole player.
+ * @param id
+ * @param key
+ * @param action
+ */
+ public void setKeyboardAction(String id, KeyStroke key, Action action)
+ {
+ mp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(key, id);
+ mp.getActionMap().put(id, action);
+ mp.getPlaylistUI().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(key, id);
+ mp.getPlaylistUI().getActionMap().put(id, action);
+ mp.getEqualizerUI().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(key, id);
+ mp.getEqualizerUI().getActionMap().put(id, action);
+ }
+
+ public void loaded()
+ {
+ DragAdapter dragAdapter = new DragAdapter(this);
+ mp.getSkin().getAcTitleBar().addMouseListener(dragAdapter);
+ mp.getSkin().getAcTitleBar().addMouseMotionListener(dragAdapter);
+ }
+
+ public void close()
+ {
+ log.info("Close player");
+ config.setLocation(getLocation().x, getLocation().y);
+ config.save();
+ dispose();
+ exit(0);
+ }
+
+ /* (non-Javadoc)
+ * @see javazoom.jlgui.player.amp.skin.Loader#togglePlaylist(boolean)
+ */
+ public void togglePlaylist(boolean enabled)
+ {
+ if (plWin != null)
+ {
+ if (enabled)
+ {
+ if (config.isEqualizerEnabled())
+ {
+ eqFactor = 2;
+ eqWin.setLocation(getLocation().x, getLocation().y + mp.getSkin().getMainHeight() * eqFactor);
+ }
+ plWin.setVisible(true);
+ }
+ else
+ {
+ plWin.setVisible(false);
+ if (config.isEqualizerEnabled())
+ {
+ eqFactor = 1;
+ eqWin.setLocation(getLocation().x, getLocation().y + mp.getSkin().getMainHeight() * eqFactor);
+ }
+ }
+ }
+ }
+
+ public void toggleEqualizer(boolean enabled)
+ {
+ if (eqWin != null)
+ {
+ if (enabled)
+ {
+ if (config.isPlaylistEnabled()) eqFactor = 2;
+ else eqFactor = 1;
+ eqWin.setLocation(getLocation().x, getLocation().y + mp.getSkin().getMainHeight() * eqFactor);
+ eqWin.setVisible(true);
+ }
+ else
+ {
+ eqWin.setVisible(false);
+ }
+ }
+ }
+
+ public void minimize()
+ {
+ setState(JFrame.ICONIFIED);
+ }
+
+ public void setLocation(int x, int y)
+ {
+ super.setLocation(x, y);
+ if (plWin != null)
+ {
+ plWin.setLocation(getLocation().x, getLocation().y + getHeight());
+ }
+ if (eqWin != null)
+ {
+ eqWin.setLocation(getLocation().x, getLocation().y + eqFactor * getHeight());
+ }
+ }
+
+ public Point getLocation()
+ {
+ return super.getLocation();
+ }
+
+ /**
+ * Kills the player.
+ * @param status
+ */
+ public void exit(int status)
+ {
+ System.exit(status);
+ }
+
+ /**
+ * Displays usage.
+ * @param msg
+ */
+ protected static void usage(String msg)
+ {
+ System.out.println(Skin.TITLETEXT + " : " + msg);
+ System.out.println("");
+ System.out.println(Skin.TITLETEXT + " : Usage");
+ System.out.println(" java javazoom.jlgui.player.amp.Player [-skin skinFilename] [-song audioFilename] [-start] [-showplaylist] [-showequalizer] [-disabledsp] [-init configFilename] [-v skinversion]");
+ System.out.println("");
+ System.out.println(" skinFilename : Filename or URL to a Winamp Skin2.x");
+ System.out.println(" audioFilename : Filename or URL to initial song or playlist");
+ System.out.println(" start : Starts playing song (from the playlist)");
+ System.out.println(" showplaylist : Show playlist");
+ System.out.println(" showequalizer : Show equalizer");
+ System.out.println(" disabledsp : Disable spectrum/time visual");
+ System.out.println("");
+ System.out.println(" Advanced parameters :");
+ System.out.println(" skinversion : 1 or 2 (default 1)");
+ System.out.println(" configFilename : Filename or URL to jlGui initial configuration (playlist,skin,parameters ...)");
+ System.out.println(" Initial configuration won't be overriden by -skin and -song arguments");
+ System.out.println("");
+ System.out.println("Homepage : http://www.javazoom.net");
+ System.exit(0);
+ }
+}
diff --git a/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/equalizer/ui/ControlCurve.java b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/equalizer/ui/ControlCurve.java
new file mode 100644
index 0000000..43b768e
--- /dev/null
+++ b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/equalizer/ui/ControlCurve.java
@@ -0,0 +1,139 @@
+/*
+ * ControlCurve.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.equalizer.ui;
+
+import java.awt.Polygon;
+
+public abstract class ControlCurve
+{
+ static final int EPSILON = 36; /* square of distance for picking */
+ protected Polygon pts;
+ protected int selection = -1;
+ int maxHeight = -1;
+ int minHeight = -1;
+
+ public ControlCurve()
+ {
+ pts = new Polygon();
+ }
+
+ public int boundY(int y)
+ {
+ int ny = y;
+ if ((minHeight >= 0) && (y < minHeight))
+ {
+ ny = 0;
+ }
+ if ((maxHeight >= 0) && (y >= maxHeight))
+ {
+ ny = maxHeight - 1;
+ }
+ return ny;
+ }
+
+ public void setMaxHeight(int h)
+ {
+ maxHeight = h;
+ }
+
+ public void setMinHeight(int h)
+ {
+ minHeight = h;
+ }
+
+ /**
+ * Return index of control point near to (x,y) or -1 if nothing near.
+ * @param x
+ * @param y
+ * @return
+ */
+ public int selectPoint(int x, int y)
+ {
+ int mind = Integer.MAX_VALUE;
+ selection = -1;
+ for (int i = 0; i < pts.npoints; i++)
+ {
+ int d = sqr(pts.xpoints[i] - x) + sqr(pts.ypoints[i] - y);
+ if (d < mind && d < EPSILON)
+ {
+ mind = d;
+ selection = i;
+ }
+ }
+ return selection;
+ }
+
+ /**
+ * Square of an int.
+ * @param x
+ * @return
+ */
+ static int sqr(int x)
+ {
+ return x * x;
+ }
+
+ /**
+ * Add a control point, return index of new control point.
+ * @param x
+ * @param y
+ * @return
+ */
+ public int addPoint(int x, int y)
+ {
+ pts.addPoint(x, y);
+ return selection = pts.npoints - 1;
+ }
+
+ /**
+ * Set selected control point.
+ * @param x
+ * @param y
+ */
+ public void setPoint(int x, int y)
+ {
+ if (selection >= 0)
+ {
+ pts.xpoints[selection] = x;
+ pts.ypoints[selection] = y;
+ }
+ }
+
+ /**
+ * Remove selected control point.
+ */
+ public void removePoint()
+ {
+ if (selection >= 0)
+ {
+ pts.npoints--;
+ for (int i = selection; i < pts.npoints; i++)
+ {
+ pts.xpoints[i] = pts.xpoints[i + 1];
+ pts.ypoints[i] = pts.ypoints[i + 1];
+ }
+ }
+ }
+
+ public abstract Polygon getPolyline();
+}
diff --git a/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/equalizer/ui/Cubic.java b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/equalizer/ui/Cubic.java
new file mode 100644
index 0000000..a1c91ea
--- /dev/null
+++ b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/equalizer/ui/Cubic.java
@@ -0,0 +1,46 @@
+/*
+ * Cubic.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.equalizer.ui;
+
+public class Cubic
+{
+ float a, b, c, d; /* a + b*u + c*u^2 +d*u^3 */
+
+ public Cubic(float a, float b, float c, float d)
+ {
+ this.a = a;
+ this.b = b;
+ this.c = c;
+ this.d = d;
+ }
+
+ /**
+ * Evaluate cubic.
+ * @param u
+ * @return
+ */
+ public float eval(float u)
+ {
+ return (((d * u) + c) * u + b) * u + a;
+ }
+}
diff --git a/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/equalizer/ui/EqualizerUI.java b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/equalizer/ui/EqualizerUI.java
new file mode 100644
index 0000000..e63e631
--- /dev/null
+++ b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/equalizer/ui/EqualizerUI.java
@@ -0,0 +1,441 @@
+/*
+ * EqualizerUI.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.equalizer.ui;
+
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DropTarget;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javazoom.jlgui.player.amp.PlayerActionEvent;
+import javazoom.jlgui.player.amp.PlayerUI;
+import javazoom.jlgui.player.amp.skin.AbsoluteLayout;
+import javazoom.jlgui.player.amp.skin.DropTargetAdapter;
+import javazoom.jlgui.player.amp.skin.ImageBorder;
+import javazoom.jlgui.player.amp.skin.Skin;
+import javazoom.jlgui.player.amp.util.Config;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * This class implements an equalizer UI.
+ *
+ * A playlist provides a collection of item to play and a cursor to know
+ * which item is playing.
+ */
+public interface Playlist
+{
+ // Next methods will be called by the Playlist UI.
+ /**
+ * Loads playlist.
+ */
+ public boolean load(String filename);
+
+ /**
+ * Saves playlist.
+ */
+ public boolean save(String filename);
+
+ /**
+ * Adds item at a given position in the playlist.
+ */
+ public void addItemAt(PlaylistItem pli, int pos);
+
+ /**
+ * Searchs and removes item from the playlist.
+ */
+ public void removeItem(PlaylistItem pli);
+
+ /**
+ * Removes item at a given position from the playlist.
+ */
+ public void removeItemAt(int pos);
+
+ /**
+ * Removes all items in the playlist.
+ */
+ public void removeAllItems();
+
+ /**
+ * Append item at the end of the playlist.
+ */
+ public void appendItem(PlaylistItem pli);
+
+ /**
+ * Sorts items of the playlist.
+ */
+ public void sortItems(int sortmode);
+
+ /**
+ * Returns item at a given position from the playlist.
+ */
+ public PlaylistItem getItemAt(int pos);
+
+ /**
+ * Returns a collection of playlist items.
+ */
+ public Collection getAllItems();
+
+ /**
+ * Returns then number of items in the playlist.
+ */
+ public int getPlaylistSize();
+
+ // Next methods will be used by the Player
+ /**
+ * Randomly re-arranges the playlist.
+ */
+ public void shuffle();
+
+ /**
+ * Returns item matching to the cursor.
+ */
+ public PlaylistItem getCursor();
+
+ /**
+ * Moves the cursor at the begining of the Playlist.
+ */
+ public void begin();
+
+ /**
+ * Returns item matching to the cursor.
+ */
+ public int getSelectedIndex();
+
+ /**
+ * Returns index of playlist item.
+ */
+ public int getIndex(PlaylistItem pli);
+
+ /**
+ * Computes cursor position (next).
+ */
+ public void nextCursor();
+
+ /**
+ * Computes cursor position (previous).
+ */
+ public void previousCursor();
+
+ /**
+ * Set the modification flag for the playlist
+ */
+ boolean setModified(boolean set);
+
+ /**
+ * Checks the modification flag
+ */
+ public boolean isModified();
+
+ void setCursor(int index);
+}
diff --git a/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/playlist/PlaylistFactory.java b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/playlist/PlaylistFactory.java
new file mode 100644
index 0000000..a854f7c
--- /dev/null
+++ b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/playlist/PlaylistFactory.java
@@ -0,0 +1,107 @@
+/*
+ * PlaylistFactory.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.playlist;
+
+import java.lang.reflect.Constructor;
+import javazoom.jlgui.player.amp.util.Config;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * PlaylistFactory.
+ */
+public class PlaylistFactory
+{
+ private static PlaylistFactory _instance = null;
+ private Playlist _playlistInstance = null;
+ private Config _config = null;
+ private static Log log = LogFactory.getLog(PlaylistFactory.class);
+
+ /**
+ * Constructor.
+ */
+ private PlaylistFactory()
+ {
+ _config = Config.getInstance();
+ }
+
+ /**
+ * Returns instance of PlaylistFactory.
+ */
+ public synchronized static PlaylistFactory getInstance()
+ {
+ if (_instance == null)
+ {
+ _instance = new PlaylistFactory();
+ }
+ return _instance;
+ }
+
+ /**
+ * Returns Playlist instantied from full qualified class name.
+ */
+ public Playlist getPlaylist()
+ {
+ if (_playlistInstance == null)
+ {
+ String classname = _config.getPlaylistClassName();
+ boolean interfaceFound = false;
+ try
+ {
+ Class aClass = Class.forName(classname);
+ Class superClass = aClass;
+ // Looking for Playlist interface implementation.
+ while (superClass != null)
+ {
+ Class[] interfaces = superClass.getInterfaces();
+ for (int i = 0; i < interfaces.length; i++)
+ {
+ if ((interfaces[i].getName()).equals("javazoom.jlgui.player.amp.playlist.Playlist"))
+ {
+ interfaceFound = true;
+ break;
+ }
+ }
+ if (interfaceFound == true) break;
+ superClass = superClass.getSuperclass();
+ }
+ if (interfaceFound == false)
+ {
+ log.error("Error : Playlist implementation not found in " + classname + " hierarchy");
+ }
+ else
+ {
+ Class[] argsClass = new Class[] {};
+ Constructor c = aClass.getConstructor(argsClass);
+ _playlistInstance = (Playlist) (c.newInstance(null));
+ log.info(classname + " loaded");
+ }
+ }
+ catch (Exception e)
+ {
+ log.error("Error : " + classname + " : " + e.getMessage());
+ }
+ }
+ return _playlistInstance;
+ }
+}
\ No newline at end of file
diff --git a/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/playlist/PlaylistItem.java b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/playlist/PlaylistItem.java
new file mode 100644
index 0000000..2ff3b6c
--- /dev/null
+++ b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/playlist/PlaylistItem.java
@@ -0,0 +1,302 @@
+/*
+ * PlaylistItem.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ *
+ */
+package javazoom.jlgui.player.amp.playlist;
+
+import javazoom.jlgui.player.amp.tag.TagInfo;
+import javazoom.jlgui.player.amp.tag.TagInfoFactory;
+import javazoom.jlgui.player.amp.util.Config;
+import javazoom.jlgui.player.amp.util.FileUtil;
+
+/**
+ * This class implements item for playlist.
+ */
+public class PlaylistItem
+{
+ protected String _name = null;
+ protected String _displayName = null;
+ protected String _location = null;
+ protected boolean _isFile = true;
+ protected long _seconds = -1;
+ protected boolean _isSelected = false; // add by JOHN YANG
+ protected TagInfo _taginfo = null;
+
+ protected PlaylistItem()
+ {
+ }
+
+ /**
+ * Contructor for playlist item.
+ *
+ * @param name Song name to be displayed
+ * @param location File or URL
+ * @param seconds Time length
+ * @param isFile true for File instance
+ */
+ public PlaylistItem(String name, String location, long seconds, boolean isFile)
+ {
+ _name = name;
+ _seconds = seconds;
+ _isFile = isFile;
+ Config config = Config.getInstance();
+ if (config.getTaginfoPolicy().equals(Config.TAGINFO_POLICY_ALL))
+ {
+ // Read tag info for any File or URL. It could take time.
+ setLocation(location, true);
+ }
+ else if (config.getTaginfoPolicy().equals(Config.TAGINFO_POLICY_FILE))
+ {
+ // Read tag info for any File only not for URL.
+ if (_isFile) setLocation(location, true);
+ else setLocation(location, false);
+ }
+ else
+ {
+ // Do not read tag info.
+ setLocation(location, false);
+ }
+ }
+
+ /**
+ * Returns item name such as (hh:mm:ss) Title - Artist if available.
+ *
+ * @return
+ */
+ public String getFormattedName()
+ {
+ if (_displayName == null)
+ {
+ if (_seconds > 0)
+ {
+ String length = getFormattedLength();
+ return "(" + length + ") " + _name;
+ }
+ else return _name;
+ }
+ // Name extracted from TagInfo or stream title.
+ else return _displayName;
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ public String getLocation()
+ {
+ return _location;
+ }
+
+ /**
+ * Returns true if item to play is coming for a file.
+ *
+ * @return
+ */
+ public boolean isFile()
+ {
+ return _isFile;
+ }
+
+ /**
+ * Set File flag for playslit item.
+ *
+ * @param b
+ */
+ public void setFile(boolean b)
+ {
+ _isFile = b;
+ }
+
+ /**
+ * Returns playtime in seconds. If tag info is available then its playtime will be returned.
+ *
+ * @return playtime
+ */
+ public long getLength()
+ {
+ if ((_taginfo != null) && (_taginfo.getPlayTime() > 0)) return _taginfo.getPlayTime();
+ else return _seconds;
+ }
+
+ public int getBitrate()
+ {
+ if (_taginfo != null) return _taginfo.getBitRate();
+ else return -1;
+ }
+
+ public int getSamplerate()
+ {
+ if (_taginfo != null) return _taginfo.getSamplingRate();
+ else return -1;
+ }
+
+ public int getChannels()
+ {
+ if (_taginfo != null) return _taginfo.getChannels();
+ else return -1;
+ }
+
+ public void setSelected(boolean mode)
+ {
+ _isSelected = mode;
+ }
+
+ public boolean isSelected()
+ {
+ return _isSelected;
+ }
+
+ /**
+ * Reads file comments/tags.
+ *
+ * @param l
+ */
+ public void setLocation(String l)
+ {
+ setLocation(l, false);
+ }
+
+ /**
+ * Reads (or not) file comments/tags.
+ *
+ * @param l input location
+ * @param readInfo
+ */
+ public void setLocation(String l, boolean readInfo)
+ {
+ _location = l;
+ if (readInfo == true)
+ {
+ // Read Audio Format and read tags/comments.
+ if ((_location != null) && (!_location.equals("")))
+ {
+ TagInfoFactory factory = TagInfoFactory.getInstance();
+ _taginfo = factory.getTagInfo(l);
+ }
+ }
+ _displayName = getFormattedDisplayName();
+ }
+
+ /**
+ * Returns item lenght such as hh:mm:ss
+ *
+ * @return formatted String.
+ */
+ public String getFormattedLength()
+ {
+ long time = getLength();
+ String length = "";
+ if (time > -1)
+ {
+ int minutes = (int) Math.floor(time / 60);
+ int hours = (int) Math.floor(minutes / 60);
+ minutes = minutes - hours * 60;
+ int seconds = (int) (time - minutes * 60 - hours * 3600);
+ // Hours.
+ if (hours > 0)
+ {
+ length = length + FileUtil.rightPadString(hours + "", '0', 2) + ":";
+ }
+ length = length + FileUtil.rightPadString(minutes + "", '0', 2) + ":" + FileUtil.rightPadString(seconds + "", '0', 2);
+ }
+ else length = "" + time;
+ return length;
+ }
+
+ /**
+ * Returns item name such as (hh:mm:ss) Title - Artist
+ *
+ * @return formatted String.
+ */
+ public String getFormattedDisplayName()
+ {
+ if (_taginfo == null) return null;
+ else
+ {
+ String length = getFormattedLength();
+ if ((_taginfo.getTitle() != null) && (!_taginfo.getTitle().equals("")) && (_taginfo.getArtist() != null) && (!_taginfo.getArtist().equals("")))
+ {
+ if (getLength() > 0) return ("(" + length + ") " + _taginfo.getTitle() + " - " + _taginfo.getArtist());
+ else return (_taginfo.getTitle() + " - " + _taginfo.getArtist());
+ }
+ else if ((_taginfo.getTitle() != null) && (!_taginfo.getTitle().equals("")))
+ {
+ if (getLength() > 0) return ("(" + length + ") " + _taginfo.getTitle());
+ else return (_taginfo.getTitle());
+ }
+ else
+ {
+ if (getLength() > 0) return ("(" + length + ") " + _name);
+ else return (_name);
+ }
+ }
+ }
+
+ public void setFormattedDisplayName(String fname)
+ {
+ _displayName = fname;
+ }
+
+ /**
+ * Return item name such as hh:mm:ss,Title,Artist
+ *
+ * @return formatted String.
+ */
+ public String getM3UExtInf()
+ {
+ if (_taginfo == null)
+ {
+ return (_seconds + "," + _name);
+ }
+ else
+ {
+ if ((_taginfo.getTitle() != null) && (_taginfo.getArtist() != null))
+ {
+ return (getLength() + "," + _taginfo.getTitle() + " - " + _taginfo.getArtist());
+ }
+ else if (_taginfo.getTitle() != null)
+ {
+ return (getLength() + "," + _taginfo.getTitle());
+ }
+ else
+ {
+ return (_seconds + "," + _name);
+ }
+ }
+ }
+
+ /**
+ * Return TagInfo.
+ *
+ * @return
+ */
+ public TagInfo getTagInfo()
+ {
+ if (_taginfo == null)
+ {
+ // Inspect location
+ setLocation(_location, true);
+ }
+ return _taginfo;
+ }
+}
diff --git a/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/playlist/ui/PlaylistUI.java b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/playlist/ui/PlaylistUI.java
new file mode 100644
index 0000000..f460ee3
--- /dev/null
+++ b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/playlist/ui/PlaylistUI.java
@@ -0,0 +1,882 @@
+/*
+ * PlaylistUI.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.playlist.ui;
+
+import java.awt.Graphics;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DropTarget;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javazoom.jlgui.player.amp.PlayerActionEvent;
+import javazoom.jlgui.player.amp.PlayerUI;
+import javazoom.jlgui.player.amp.playlist.Playlist;
+import javazoom.jlgui.player.amp.playlist.PlaylistItem;
+import javazoom.jlgui.player.amp.skin.AbsoluteLayout;
+import javazoom.jlgui.player.amp.skin.ActiveJButton;
+import javazoom.jlgui.player.amp.skin.DropTargetAdapter;
+import javazoom.jlgui.player.amp.skin.Skin;
+import javazoom.jlgui.player.amp.skin.UrlDialog;
+import javazoom.jlgui.player.amp.tag.TagInfo;
+import javazoom.jlgui.player.amp.tag.TagInfoFactory;
+import javazoom.jlgui.player.amp.tag.ui.TagInfoDialog;
+import javazoom.jlgui.player.amp.util.Config;
+import javazoom.jlgui.player.amp.util.FileSelector;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class PlaylistUI extends JPanel implements ActionListener, ChangeListener
+{
+ private static Log log = LogFactory.getLog(PlaylistUI.class);
+ public static int MAXDEPTH = 4;
+ private Config config = null;
+ private Skin ui = null;
+ private Playlist playlist = null;
+ private PlayerUI player = null;
+ private int topIndex = 0;
+ private int currentSelection = -1;
+ private Vector exts = null;
+ private boolean isSearching = false;
+ private JPopupMenu fipopup = null;
+
+ public PlaylistUI()
+ {
+ super();
+ setDoubleBuffered(true);
+ setLayout(new AbsoluteLayout());
+ config = Config.getInstance();
+ addMouseListener(new MouseAdapter()
+ {
+ public void mousePressed(MouseEvent e)
+ {
+ handleMouseClick(e);
+ }
+ });
+ // DnD support.
+ DropTargetAdapter dnd = new DropTargetAdapter()
+ {
+ public void processDrop(Object data)
+ {
+ processDnD(data);
+ }
+ };
+ DropTarget dt = new DropTarget(this, DnDConstants.ACTION_COPY, dnd, true);
+ }
+
+ public void setPlayer(PlayerUI mp)
+ {
+ player = mp;
+ }
+
+ public void setSkin(Skin skin)
+ {
+ ui = skin;
+ }
+
+ public Skin getSkin()
+ {
+ return ui;
+ }
+
+ public Playlist getPlaylist()
+ {
+ return playlist;
+ }
+
+ public void setPlaylist(Playlist playlist)
+ {
+ this.playlist = playlist;
+ }
+
+ public int getTopIndex()
+ {
+ return topIndex;
+ }
+
+ public void loadUI()
+ {
+ removeAll();
+ ui.getPlaylistPanel().setParent(this);
+ add(ui.getAcPlSlider(), ui.getAcPlSlider().getConstraints());
+ ui.getAcPlSlider().setValue(100);
+ ui.getAcPlSlider().removeChangeListener(this);
+ ui.getAcPlSlider().addChangeListener(this);
+ add(ui.getAcPlUp(), ui.getAcPlUp().getConstraints());
+ ui.getAcPlUp().removeActionListener(this);
+ ui.getAcPlUp().addActionListener(this);
+ add(ui.getAcPlDown(), ui.getAcPlDown().getConstraints());
+ ui.getAcPlDown().removeActionListener(this);
+ ui.getAcPlDown().addActionListener(this);
+ // Add menu
+ add(ui.getAcPlAdd(), ui.getAcPlAdd().getConstraints());
+ ui.getAcPlAdd().removeActionListener(this);
+ ui.getAcPlAdd().addActionListener(this);
+ add(ui.getAcPlAddPopup(), ui.getAcPlAddPopup().getConstraints());
+ ui.getAcPlAddPopup().setVisible(false);
+ ActiveJButton[] items = ui.getAcPlAddPopup().getItems();
+ for (int i = 0; i < items.length; i++)
+ {
+ items[i].addActionListener(this);
+ }
+ // Remove menu
+ add(ui.getAcPlRemove(), ui.getAcPlRemove().getConstraints());
+ ui.getAcPlRemove().removeActionListener(this);
+ ui.getAcPlRemove().addActionListener(this);
+ add(ui.getAcPlRemovePopup(), ui.getAcPlRemovePopup().getConstraints());
+ ui.getAcPlRemovePopup().setVisible(false);
+ items = ui.getAcPlRemovePopup().getItems();
+ for (int i = 0; i < items.length; i++)
+ {
+ items[i].removeActionListener(this);
+ items[i].addActionListener(this);
+ }
+ // Select menu
+ add(ui.getAcPlSelect(), ui.getAcPlSelect().getConstraints());
+ ui.getAcPlSelect().removeActionListener(this);
+ ui.getAcPlSelect().addActionListener(this);
+ add(ui.getAcPlSelectPopup(), ui.getAcPlSelectPopup().getConstraints());
+ ui.getAcPlSelectPopup().setVisible(false);
+ items = ui.getAcPlSelectPopup().getItems();
+ for (int i = 0; i < items.length; i++)
+ {
+ items[i].removeActionListener(this);
+ items[i].addActionListener(this);
+ }
+ // Misc menu
+ add(ui.getAcPlMisc(), ui.getAcPlMisc().getConstraints());
+ ui.getAcPlMisc().removeActionListener(this);
+ ui.getAcPlMisc().addActionListener(this);
+ add(ui.getAcPlMiscPopup(), ui.getAcPlMiscPopup().getConstraints());
+ ui.getAcPlMiscPopup().setVisible(false);
+ items = ui.getAcPlMiscPopup().getItems();
+ for (int i = 0; i < items.length; i++)
+ {
+ items[i].removeActionListener(this);
+ items[i].addActionListener(this);
+ }
+ // List menu
+ add(ui.getAcPlList(), ui.getAcPlList().getConstraints());
+ ui.getAcPlList().removeActionListener(this);
+ ui.getAcPlList().addActionListener(this);
+ add(ui.getAcPlListPopup(), ui.getAcPlListPopup().getConstraints());
+ ui.getAcPlListPopup().setVisible(false);
+ items = ui.getAcPlListPopup().getItems();
+ for (int i = 0; i < items.length; i++)
+ {
+ items[i].removeActionListener(this);
+ items[i].addActionListener(this);
+ }
+ // Popup menu
+ fipopup = new JPopupMenu();
+ JMenuItem mi = new JMenuItem(ui.getResource("playlist.popup.info"));
+ mi.setActionCommand(PlayerActionEvent.ACPLINFO);
+ mi.removeActionListener(this);
+ mi.addActionListener(this);
+ fipopup.add(mi);
+ fipopup.addSeparator();
+ mi = new JMenuItem(ui.getResource("playlist.popup.play"));
+ mi.setActionCommand(PlayerActionEvent.ACPLPLAY);
+ mi.removeActionListener(this);
+ mi.addActionListener(this);
+ fipopup.add(mi);
+ fipopup.addSeparator();
+ mi = new JMenuItem(ui.getResource("playlist.popup.remove"));
+ mi.setActionCommand(PlayerActionEvent.ACPLREMOVE);
+ mi.removeActionListener(this);
+ mi.addActionListener(this);
+ fipopup.add(mi);
+ validate();
+ repaint();
+ }
+
+ /**
+ * Initialize playlist.
+ */
+ public void initPlayList()
+ {
+ topIndex = 0;
+ nextCursor();
+ }
+
+ /**
+ * Repaint the file list area and scroll it if necessary
+ */
+ public void nextCursor()
+ {
+ currentSelection = playlist.getSelectedIndex();
+ int n = playlist.getPlaylistSize();
+ int nlines = ui.getPlaylistPanel().getLines();
+ while (currentSelection - topIndex > nlines - 1)
+ topIndex += 2;
+ if (topIndex >= n) topIndex = n - 1;
+ while (currentSelection < topIndex)
+ topIndex -= 2;
+ if (topIndex < 0) topIndex = 0;
+ resetScrollBar();
+ repaint();
+ }
+
+ /**
+ * Get the item index according to the mouse y position
+ * @param y
+ * @return
+ */
+ protected int getIndex(int y)
+ {
+ int n0 = playlist.getPlaylistSize();
+ if (n0 == 0) return -1;
+ for (int n = 0; n < 100; n++)
+ {
+ if (ui.getPlaylistPanel().isIndexArea(y, n))
+ {
+ if (topIndex + n > n0 - 1) return -1;
+ return topIndex + n;
+ }
+ }
+ return -1;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent)
+ */
+ public void stateChanged(ChangeEvent e)
+ {
+ Object src = e.getSource();
+ //log.debug("State (EDT=" + SwingUtilities.isEventDispatchThread() + ")");
+ if (src == ui.getAcPlSlider())
+ {
+ int n = playlist.getPlaylistSize();
+ float dx = (100 - ui.getAcPlSlider().getValue()) / 100.0f;
+ int index = (int) (dx * (n - 1));
+ if (index != topIndex)
+ {
+ topIndex = index;
+ paintList();
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
+ */
+ public void actionPerformed(ActionEvent e)
+ {
+ final ActionEvent evt = e;
+ new Thread("PlaylistUIActionEvent")
+ {
+ public void run()
+ {
+ processActionEvent(evt);
+ }
+ }.start();
+ }
+
+ /**
+ * Process action event.
+ * @param e
+ */
+ public void processActionEvent(ActionEvent e)
+ {
+ String cmd = e.getActionCommand();
+ log.debug("Action=" + cmd + " (EDT=" + SwingUtilities.isEventDispatchThread() + ")");
+ int n = playlist.getPlaylistSize();
+ if (cmd.equals(PlayerActionEvent.ACPLUP))
+ {
+ topIndex--;
+ if (topIndex < 0) topIndex = 0;
+ resetScrollBar();
+ paintList();
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLDOWN))
+ {
+ topIndex++;
+ if (topIndex > n - 1) topIndex = n - 1;
+ resetScrollBar();
+ paintList();
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLADDPOPUP))
+ {
+ ui.getAcPlAdd().setVisible(false);
+ ui.getAcPlAddPopup().setVisible(true);
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLREMOVEPOPUP))
+ {
+ ui.getAcPlRemove().setVisible(false);
+ ui.getAcPlRemovePopup().setVisible(true);
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLSELPOPUP))
+ {
+ ui.getAcPlSelect().setVisible(false);
+ ui.getAcPlSelectPopup().setVisible(true);
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLMISCPOPUP))
+ {
+ ui.getAcPlMisc().setVisible(false);
+ ui.getAcPlMiscPopup().setVisible(true);
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLLISTPOPUP))
+ {
+ ui.getAcPlList().setVisible(false);
+ ui.getAcPlListPopup().setVisible(true);
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLINFO))
+ {
+ popupFileInfo();
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLPLAY))
+ {
+ int n0 = playlist.getPlaylistSize();
+ PlaylistItem pli = null;
+ for (int i = n0 - 1; i >= 0; i--)
+ {
+ pli = playlist.getItemAt(i);
+ if (pli.isSelected()) break;
+ }
+ // Play.
+ if ((pli != null) && (pli.getTagInfo() != null))
+ {
+ player.pressStop();
+ player.setCurrentSong(pli);
+ playlist.setCursor(playlist.getIndex(pli));
+ player.pressStart();
+ }
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLREMOVE))
+ {
+ delSelectedItems();
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLADDFILE))
+ {
+ ui.getAcPlAddPopup().setVisible(false);
+ ui.getAcPlAdd().setVisible(true);
+ File[] file = FileSelector.selectFile(player.getLoader(), FileSelector.OPEN, true, config.getExtensions(), ui.getResource("playlist.popup.add.file"), new File(config.getLastDir()));
+ if (FileSelector.getInstance().getDirectory() != null) config.setLastDir(FileSelector.getInstance().getDirectory().getPath());
+ addFiles(file);
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLADDURL))
+ {
+ ui.getAcPlAddPopup().setVisible(false);
+ ui.getAcPlAdd().setVisible(true);
+ UrlDialog UD = new UrlDialog(config.getTopParent(), ui.getResource("playlist.popup.add.url"), player.getLoader().getLocation().x, player.getLoader().getLocation().y + player.getHeight(), null);
+ UD.show();
+ if (UD.getFile() != null)
+ {
+ PlaylistItem pli = new PlaylistItem(UD.getFile(), UD.getURL(), -1, false);
+ playlist.appendItem(pli);
+ resetScrollBar();
+ repaint();
+ }
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLADDDIR))
+ {
+ ui.getAcPlAddPopup().setVisible(false);
+ ui.getAcPlAdd().setVisible(true);
+ File[] file = FileSelector.selectFile(player.getLoader(), FileSelector.DIRECTORY, false, "", ui.getResource("playlist.popup.add.dir"), new File(config.getLastDir()));
+ if (FileSelector.getInstance().getDirectory() != null) config.setLastDir(FileSelector.getInstance().getDirectory().getPath());
+ if (file == null || !file[0].isDirectory()) return;
+ // TODO - add message box for wrong filename
+ addDir(file[0]);
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLREMOVEALL))
+ {
+ ui.getAcPlRemovePopup().setVisible(false);
+ ui.getAcPlRemove().setVisible(true);
+ delAllItems();
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLREMOVESEL))
+ {
+ ui.getAcPlRemovePopup().setVisible(false);
+ ui.getAcPlRemove().setVisible(true);
+ delSelectedItems();
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLREMOVEMISC))
+ {
+ ui.getAcPlRemovePopup().setVisible(false);
+ ui.getAcPlRemove().setVisible(true);
+ // TODO
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLREMOVECROP))
+ {
+ ui.getAcPlRemovePopup().setVisible(false);
+ ui.getAcPlRemove().setVisible(true);
+ // TODO
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLSELALL))
+ {
+ ui.getAcPlSelectPopup().setVisible(false);
+ ui.getAcPlSelect().setVisible(true);
+ selFunctions(1);
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLSELINV))
+ {
+ ui.getAcPlSelectPopup().setVisible(false);
+ ui.getAcPlSelect().setVisible(true);
+ selFunctions(-1);
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLSELZERO))
+ {
+ ui.getAcPlSelectPopup().setVisible(false);
+ ui.getAcPlSelect().setVisible(true);
+ selFunctions(0);
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLMISCOPTS))
+ {
+ ui.getAcPlMiscPopup().setVisible(false);
+ ui.getAcPlMisc().setVisible(true);
+ // TODO
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLMISCFILE))
+ {
+ ui.getAcPlMiscPopup().setVisible(false);
+ ui.getAcPlMisc().setVisible(true);
+ popupFileInfo();
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLMISCSORT))
+ {
+ ui.getAcPlMiscPopup().setVisible(false);
+ ui.getAcPlMisc().setVisible(true);
+ // TODO
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLLISTLOAD))
+ {
+ ui.getAcPlListPopup().setVisible(false);
+ ui.getAcPlList().setVisible(true);
+ File[] file = FileSelector.selectFile(player.getLoader(), FileSelector.OPEN, true, config.getExtensions(), ui.getResource("playlist.popup.list.load"), new File(config.getLastDir()));
+ if (FileSelector.getInstance().getDirectory() != null) config.setLastDir(FileSelector.getInstance().getDirectory().getPath());
+ if ((file != null) && (file[0] != null))
+ {
+ String fsFile = file[0].getName();
+ if ((fsFile.toLowerCase().endsWith(ui.getResource("playlist.extension.m3u"))) || (fsFile.toLowerCase().endsWith(ui.getResource("playlist.extension.pls"))))
+ {
+ if (player.loadPlaylist(config.getLastDir() + fsFile))
+ {
+ config.setPlaylistFilename(config.getLastDir() + fsFile);
+ playlist.begin();
+ playlist.setCursor(-1);
+ // TODO
+ topIndex = 0;
+ }
+ resetScrollBar();
+ repaint();
+ }
+ }
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLLISTSAVE))
+ {
+ ui.getAcPlListPopup().setVisible(false);
+ ui.getAcPlList().setVisible(true);
+ // TODO
+ }
+ else if (cmd.equals(PlayerActionEvent.ACPLLISTNEW))
+ {
+ ui.getAcPlListPopup().setVisible(false);
+ ui.getAcPlList().setVisible(true);
+ // TODO
+ }
+ }
+
+ /**
+ * Display file info.
+ */
+ public void popupFileInfo()
+ {
+ int n0 = playlist.getPlaylistSize();
+ PlaylistItem pli = null;
+ for (int i = n0 - 1; i >= 0; i--)
+ {
+ pli = playlist.getItemAt(i);
+ if (pli.isSelected()) break;
+ }
+ // Display Tag Info.
+ if (pli != null)
+ {
+ TagInfo taginfo = pli.getTagInfo();
+ TagInfoFactory factory = TagInfoFactory.getInstance();
+ TagInfoDialog dialog = factory.getTagInfoDialog(taginfo);
+ dialog.setLocation(player.getLoader().getLocation().x, player.getLoader().getLocation().y + player.getHeight());
+ dialog.show();
+ }
+ }
+
+ /**
+ * Selection operation in pledit window
+ * @param mode -1 : inverse selected items, 0 : select none, 1 : select all
+ */
+ private void selFunctions(int mode)
+ {
+ int n0 = playlist.getPlaylistSize();
+ if (n0 == 0) return;
+ for (int i = 0; i < n0; i++)
+ {
+ PlaylistItem pli = playlist.getItemAt(i);
+ if (pli == null) break;
+ if (mode == -1)
+ { // inverse selection
+ pli.setSelected(!pli.isSelected());
+ }
+ else if (mode == 0)
+ { // select none
+ pli.setSelected(false);
+ }
+ else if (mode == 1)
+ { // select all
+ pli.setSelected(true);
+ }
+ }
+ repaint();
+ }
+
+ /**
+ * Remove all items in playlist.
+ */
+ private void delAllItems()
+ {
+ int n0 = playlist.getPlaylistSize();
+ if (n0 == 0) return;
+ playlist.removeAllItems();
+ topIndex = 0;
+ ui.getAcPlSlider().setValue(100);
+ repaint();
+ }
+
+ /**
+ * Remove selected items in playlist.
+ */
+ private void delSelectedItems()
+ {
+ int n0 = playlist.getPlaylistSize();
+ boolean brepaint = false;
+ for (int i = n0 - 1; i >= 0; i--)
+ {
+ if (playlist.getItemAt(i).isSelected())
+ {
+ playlist.removeItemAt(i);
+ brepaint = true;
+ }
+ }
+ if (brepaint)
+ {
+ int n = playlist.getPlaylistSize();
+ if (topIndex >= n) topIndex = n - 1;
+ if (topIndex < 0) topIndex = 0;
+ resetScrollBar();
+ repaint();
+ }
+ }
+
+ /**
+ * Add file(s) to playlist.
+ * @param file
+ */
+ public void addFiles(File[] file)
+ {
+ if (file != null)
+ {
+ for (int i = 0; i < file.length; i++)
+ {
+ String fsFile = file[i].getName();
+ if ((!fsFile.toLowerCase().endsWith(ui.getResource("skin.extension"))) && (!fsFile.toLowerCase().endsWith(ui.getResource("playlist.extension.m3u"))) && (!fsFile.toLowerCase().endsWith(ui.getResource("playlist.extension.pls"))))
+ {
+ PlaylistItem pli = new PlaylistItem(fsFile, file[i].getAbsolutePath(), -1, true);
+ playlist.appendItem(pli);
+ resetScrollBar();
+ repaint();
+ }
+ }
+ }
+ }
+
+ /**
+ * Handle mouse clicks on playlist.
+ * @param evt
+ */
+ protected void handleMouseClick(MouseEvent evt)
+ {
+ int x = evt.getX();
+ int y = evt.getY();
+ ui.getAcPlAddPopup().setVisible(false);
+ ui.getAcPlAdd().setVisible(true);
+ ui.getAcPlRemovePopup().setVisible(false);
+ ui.getAcPlRemove().setVisible(true);
+ ui.getAcPlSelectPopup().setVisible(false);
+ ui.getAcPlSelect().setVisible(true);
+ ui.getAcPlMiscPopup().setVisible(false);
+ ui.getAcPlMisc().setVisible(true);
+ ui.getAcPlListPopup().setVisible(false);
+ ui.getAcPlList().setVisible(true);
+ // Check select action
+ if (ui.getPlaylistPanel().isInSelectArea(x, y))
+ {
+ int index = getIndex(y);
+ if (index != -1)
+ {
+ // PopUp
+ if (javax.swing.SwingUtilities.isRightMouseButton(evt))
+ {
+ if (fipopup != null) fipopup.show(this, x, y);
+ }
+ else
+ {
+ PlaylistItem pli = playlist.getItemAt(index);
+ if (pli != null)
+ {
+ pli.setSelected(!pli.isSelected());
+ if ((evt.getClickCount() == 2) && (evt.getModifiers() == MouseEvent.BUTTON1_MASK))
+ {
+ player.pressStop();
+ player.setCurrentSong(pli);
+ playlist.setCursor(index);
+ player.pressStart();
+ }
+ }
+ }
+ repaint();
+ }
+ }
+ }
+
+ /**
+ * Process Drag&Drop
+ * @param data
+ */
+ public void processDnD(Object data)
+ {
+ log.debug("Playlist DnD");
+ // Looking for files to drop.
+ if (data instanceof List)
+ {
+ List al = (List) data;
+ if ((al != null) && (al.size() > 0))
+ {
+ ArrayList fileList = new ArrayList();
+ ArrayList folderList = new ArrayList();
+ ListIterator li = al.listIterator();
+ while (li.hasNext())
+ {
+ File f = (File) li.next();
+ if ((f.exists()) && (f.canRead()))
+ {
+ if (f.isFile()) fileList.add(f);
+ else if (f.isDirectory()) folderList.add(f);
+ }
+ }
+ addFiles(fileList);
+ addDirs(folderList);
+ }
+ }
+ else if (data instanceof String)
+ {
+ String files = (String) data;
+ if ((files.length() > 0))
+ {
+ ArrayList fileList = new ArrayList();
+ ArrayList folderList = new ArrayList();
+ StringTokenizer st = new StringTokenizer(files, System.getProperty("line.separator"));
+ // Transfer files dropped.
+ while (st.hasMoreTokens())
+ {
+ String path = st.nextToken();
+ if (path.startsWith("file://"))
+ {
+ path = path.substring(7, path.length());
+ if (path.endsWith("\r")) path = path.substring(0, (path.length() - 1));
+ }
+ File f = new File(path);
+ if ((f.exists()) && (f.canRead()))
+ {
+ if (f.isFile()) fileList.add(f);
+ else if (f.isDirectory()) folderList.add(f);
+ }
+ }
+ addFiles(fileList);
+ addDirs(folderList);
+ }
+ }
+ else
+ {
+ log.info("Unknown dropped objects");
+ }
+ }
+
+ /**
+ * Add files to playlistUI.
+ * @param fileList
+ */
+ public void addFiles(List fileList)
+ {
+ if (fileList.size() > 0)
+ {
+ File[] file = (File[]) fileList.toArray(new File[fileList.size()]);
+ addFiles(file);
+ }
+ }
+
+ /**
+ * Add directories to playlistUI.
+ * @param folderList
+ */
+ public void addDirs(List folderList)
+ {
+ if (folderList.size() > 0)
+ {
+ ListIterator it = folderList.listIterator();
+ while (it.hasNext())
+ {
+ addDir((File) it.next());
+ }
+ }
+ }
+
+ /**
+ * Compute slider value.
+ */
+ private void resetScrollBar()
+ {
+ int n = playlist.getPlaylistSize();
+ float dx = (n < 1) ? 0 : ((float) topIndex / (n - 1)) * (100);
+ ui.getAcPlSlider().setValue(100 - (int) dx);
+ }
+
+ public void paintList()
+ {
+ if (!isVisible()) return;
+ else repaint();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
+ */
+ public void paintComponent(Graphics g)
+ {
+ ui.getPlaylistPanel().paintBackground(g);
+ ui.getPlaylistPanel().paintList(g);
+ }
+
+ /**
+ * Add all files under this directory to play list.
+ * @param fsFile
+ */
+ private void addDir(File fsFile)
+ {
+ // Put all music file extension in a Vector
+ String ext = config.getExtensions();
+ StringTokenizer st = new StringTokenizer(ext, ", ");
+ if (exts == null)
+ {
+ exts = new Vector();
+ while (st.hasMoreTokens())
+ {
+ exts.add("." + st.nextElement());
+ }
+ }
+ // recursive
+ Thread addThread = new AddThread(fsFile);
+ addThread.start();
+ // Refresh thread
+ Thread refresh = new Thread("Refresh")
+ {
+ public void run()
+ {
+ while (isSearching)
+ {
+ resetScrollBar();
+ repaint();
+ try
+ {
+ Thread.sleep(4000);
+ }
+ catch (Exception ex)
+ {
+ }
+ }
+ }
+ };
+ refresh.start();
+ }
+ class AddThread extends Thread
+ {
+ private File fsFile;
+
+ public AddThread(File fsFile)
+ {
+ super("Add");
+ this.fsFile = fsFile;
+ }
+
+ public void run()
+ {
+ isSearching = true;
+ addMusicRecursive(fsFile, 0);
+ isSearching = false;
+ resetScrollBar();
+ repaint();
+ }
+ }
+
+ private void addMusicRecursive(File rootDir, int depth)
+ {
+ // We do not want waste time
+ if (rootDir == null || depth > MAXDEPTH) return;
+ String[] list = rootDir.list();
+ if (list == null) return;
+ for (int i = 0; i < list.length; i++)
+ {
+ File ff = new File(rootDir, list[i]);
+ if (ff.isDirectory()) addMusicRecursive(ff, depth + 1);
+ else
+ {
+ if (isMusicFile(list[i]))
+ {
+ PlaylistItem pli = new PlaylistItem(list[i], rootDir + File.separator + list[i], -1, true);
+ playlist.appendItem(pli);
+ }
+ }
+ }
+ }
+
+ private boolean isMusicFile(String ff)
+ {
+ int sz = exts.size();
+ for (int i = 0; i < sz; i++)
+ {
+ String ext = exts.elementAt(i).toString().toLowerCase();
+ // TODO : Improve
+ if (ext.equalsIgnoreCase(".wsz") || ext.equalsIgnoreCase(".m3u") || ext.equalsIgnoreCase(".pls")) continue;
+ if (ff.toLowerCase().endsWith(exts.elementAt(i).toString().toLowerCase())) return true;
+ }
+ return false;
+ }
+}
diff --git a/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/skin/AbsoluteConstraints.java b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/skin/AbsoluteConstraints.java
new file mode 100644
index 0000000..44149dc
--- /dev/null
+++ b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/skin/AbsoluteConstraints.java
@@ -0,0 +1,151 @@
+/*
+ * AbsoluteConstraints.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.skin;
+
+import java.awt.Dimension;
+import java.awt.Point;
+
+/**
+ * An object that encapsulates position and (optionally) size for
+ * Absolute positioning of components.
+ */
+public class AbsoluteConstraints implements java.io.Serializable
+{
+ /**
+ * generated Serialized Version UID
+ */
+ static final long serialVersionUID = 5261460716622152494L;
+ /**
+ * The X position of the component
+ */
+ public int x;
+ /**
+ * The Y position of the component
+ */
+ public int y;
+ /**
+ * The width of the component or -1 if the component's preferred width should be used
+ */
+ public int width = -1;
+ /**
+ * The height of the component or -1 if the component's preferred height should be used
+ */
+ public int height = -1;
+
+ /**
+ * Creates a new AbsoluteConstraints for specified position.
+ *
+ * @param pos The position to be represented by this AbsoluteConstraints
+ */
+ public AbsoluteConstraints(Point pos)
+ {
+ this(pos.x, pos.y);
+ }
+
+ /**
+ * Creates a new AbsoluteConstraints for specified position.
+ *
+ * @param x The X position to be represented by this AbsoluteConstraints
+ * @param y The Y position to be represented by this AbsoluteConstraints
+ */
+ public AbsoluteConstraints(int x, int y)
+ {
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ * Creates a new AbsoluteConstraints for specified position and size.
+ *
+ * @param pos The position to be represented by this AbsoluteConstraints
+ * @param size The size to be represented by this AbsoluteConstraints or null
+ * if the component's preferred size should be used
+ */
+ public AbsoluteConstraints(Point pos, Dimension size)
+ {
+ this.x = pos.x;
+ this.y = pos.y;
+ if (size != null)
+ {
+ this.width = size.width;
+ this.height = size.height;
+ }
+ }
+
+ /**
+ * Creates a new AbsoluteConstraints for specified position and size.
+ *
+ * @param x The X position to be represented by this AbsoluteConstraints
+ * @param y The Y position to be represented by this AbsoluteConstraints
+ * @param width The width to be represented by this AbsoluteConstraints or -1 if the
+ * component's preferred width should be used
+ * @param height The height to be represented by this AbsoluteConstraints or -1 if the
+ * component's preferred height should be used
+ */
+ public AbsoluteConstraints(int x, int y, int width, int height)
+ {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ }
+
+ /**
+ * @return The X position represented by this AbsoluteConstraints
+ */
+ public int getX()
+ {
+ return x;
+ }
+
+ /**
+ * @return The Y position represented by this AbsoluteConstraints
+ */
+ public int getY()
+ {
+ return y;
+ }
+
+ /**
+ * @return The width represented by this AbsoluteConstraints or -1 if the
+ * component's preferred width should be used
+ */
+ public int getWidth()
+ {
+ return width;
+ }
+
+ /**
+ * @return The height represented by this AbsoluteConstraints or -1 if the
+ * component's preferred height should be used
+ */
+ public int getHeight()
+ {
+ return height;
+ }
+
+ public String toString()
+ {
+ return super.toString() + " [x=" + x + ", y=" + y + ", width=" + width + ", height=" + height + "]";
+ }
+}
diff --git a/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/skin/AbsoluteLayout.java b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/skin/AbsoluteLayout.java
new file mode 100644
index 0000000..03a21bf
--- /dev/null
+++ b/vendor/jlgui/3.0/src/javazoom/jlgui/player/amp/skin/AbsoluteLayout.java
@@ -0,0 +1,196 @@
+/*
+ * AbsoluteLayout.
+ *
+ * JavaZOOM : jlgui@javazoom.net
+ * http://www.javazoom.net
+ *
+ *-----------------------------------------------------------------------
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------
+ */
+package javazoom.jlgui.player.amp.skin;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.LayoutManager;
+import java.awt.LayoutManager2;
+
+/**
+ * AbsoluteLayout is a LayoutManager that works as a replacement for "null" layout to
+ * allow placement of components in absolute positions.
+ */
+public class AbsoluteLayout implements LayoutManager2, java.io.Serializable
+{
+ /**
+ * generated Serialized Version UID
+ */
+ static final long serialVersionUID = -1919857869177070440L;
+
+ /**
+ * Adds the specified component with the specified name to
+ * the layout.
+ *
+ * @param name the component name
+ * @param comp the component to be added
+ */
+ public void addLayoutComponent(String name, Component comp)
+ {
+ throw new IllegalArgumentException();
+ }
+
+ /**
+ * Removes the specified component from the layout.
+ *
+ * @param comp the component to be removed
+ */
+ public void removeLayoutComponent(Component comp)
+ {
+ constraints.remove(comp);
+ }
+
+ /**
+ * Calculates the preferred dimension for the specified
+ * panel given the components in the specified parent container.
+ *
+ * @param parent the component to be laid out
+ * @see #minimumLayoutSize
+ */
+ public Dimension preferredLayoutSize(Container parent)
+ {
+ int maxWidth = 0;
+ int maxHeight = 0;
+ for (java.util.Enumeration e = constraints.keys(); e.hasMoreElements();)
+ {
+ Component comp = (Component) e.nextElement();
+ AbsoluteConstraints ac = (AbsoluteConstraints) constraints.get(comp);
+ Dimension size = comp.getPreferredSize();
+ int width = ac.getWidth();
+ if (width == -1) width = size.width;
+ int height = ac.getHeight();
+ if (height == -1) height = size.height;
+ if (ac.x + width > maxWidth) maxWidth = ac.x + width;
+ if (ac.y + height > maxHeight) maxHeight = ac.y + height;
+ }
+ return new Dimension(maxWidth, maxHeight);
+ }
+
+ /**
+ * Calculates the minimum dimension for the specified
+ * panel given the components in the specified parent container.
+ *
+ * @param parent the component to be laid out
+ * @see #preferredLayoutSize
+ */
+ public Dimension minimumLayoutSize(Container parent)
+ {
+ int maxWidth = 0;
+ int maxHeight = 0;
+ for (java.util.Enumeration e = constraints.keys(); e.hasMoreElements();)
+ {
+ Component comp = (Component) e.nextElement();
+ AbsoluteConstraints ac = (AbsoluteConstraints) constraints.get(comp);
+ Dimension size = comp.getMinimumSize();
+ int width = ac.getWidth();
+ if (width == -1) width = size.width;
+ int height = ac.getHeight();
+ if (height == -1) height = size.height;
+ if (ac.x + width > maxWidth) maxWidth = ac.x + width;
+ if (ac.y + height > maxHeight) maxHeight = ac.y + height;
+ }
+ return new Dimension(maxWidth, maxHeight);
+ }
+
+ /**
+ * Lays out the container in the specified panel.
+ *
+ * @param parent the component which needs to be laid out
+ */
+ public void layoutContainer(Container parent)
+ {
+ for (java.util.Enumeration e = constraints.keys(); e.hasMoreElements();)
+ {
+ Component comp = (Component) e.nextElement();
+ AbsoluteConstraints ac = (AbsoluteConstraints) constraints.get(comp);
+ Dimension size = comp.getPreferredSize();
+ int width = ac.getWidth();
+ if (width == -1) width = size.width;
+ int height = ac.getHeight();
+ if (height == -1) height = size.height;
+ comp.setBounds(ac.x, ac.y, width, height);
+ }
+ }
+
+ /**
+ * Adds the specified component to the layout, using the specified
+ * constraint object.
+ *
+ * @param comp the component to be added
+ * @param constr where/how the component is added to the layout.
+ */
+ public void addLayoutComponent(Component comp, Object constr)
+ {
+ if (!(constr instanceof AbsoluteConstraints)) throw new IllegalArgumentException();
+ constraints.put(comp, constr);
+ }
+
+ /**
+ * Returns the maximum size of this component.
+ *
+ * @see java.awt.Component#getMinimumSize()
+ * @see java.awt.Component#getPreferredSize()
+ * @see LayoutManager
+ */
+ public Dimension maximumLayoutSize(Container target)
+ {
+ return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Returns the alignment along the x axis. This specifies how
+ * the component would like to be aligned relative to other
+ * components. The value should be a number between 0 and 1
+ * where 0 represents alignment along the origin, 1 is aligned
+ * the furthest away from the origin, 0.5 is centered, etc.
+ */
+ public float getLayoutAlignmentX(Container target)
+ {
+ return 0;
+ }
+
+ /**
+ * Returns the alignment along the y axis. This specifies how
+ * the component would like to be aligned relative to other
+ * components. The value should be a number between 0 and 1
+ * where 0 represents alignment along the origin, 1 is aligned
+ * the furthest away from the origin, 0.5 is centered, etc.
+ */
+ public float getLayoutAlignmentY(Container target)
+ {
+ return 0;
+ }
+
+ /**
+ * Invalidates the layout, indicating that if the layout manager
+ * has cached information it should be discarded.
+ */
+ public void invalidateLayout(Container target)
+ {
+ }
+ /**
+ * A mapping null, but cannot
+ * be of type Holder
+ * @throws ClassCastException if o is of type Holder
+ */
+ public Holder(Object o) {
+ if (o instanceof Holder) {
+ throw new ClassCastException();
+ }
+ else if (o == null) {
+ o = new Integer(0);
+ }
+ this.o = o;
+ }
+
+ /**
+ * Returns the referenced Object.
+ *
+ * @return an Object
+ */
+ public final Object get() {
+ return o;
+ }
+
+ /**
+ * Returns the hashCode of the encapsulated Object or
+ * {@link java.lang.Object#hashCode()} if the Object is null.
+ *
+ * @return the hashCode
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode() {
+ return getClass().getName().hashCode() ^ (o == null ? 0 : o.hashCode());
+ }
+
+ /**
+ * Returns if this Object is equal to another Object.
+ *
+ * @param obj the other Object, may be null
+ * @return if both Objects are equal
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof Holder)) {
+ return false;
+ }
+ Holder h = (Holder) obj;
+ return o == null ? h.o == null : o.equals(h.o);
+ }
+
+ /**
+ * Returns a String representation of this Object.
+ *
+ * @return a String, never null
+ * @see java.lang.Object#toString()
+ * @see #toStringBuffer(StringBuffer)
+ */
+ public final String toString() {
+ return toStringBuffer(null).toString();
+ }
+
+ /**
+ * Appends a String representation of this Object to the given
+ * {@link StringBuffer} or creates a new one if none is given.
+ *
+ * @param in the StringBuffer to append to, may be null
+ * @return a StringBuffer, never null
+ */
+ public StringBuffer toStringBuffer(StringBuffer in) {
+ if (in == null) {
+ in = new StringBuffer(32);
+ }
+ else {
+ in.ensureCapacity(in.length() + 32);
+ }
+ in.append("{ Holder: o = ");
+ in.append(o);
+ in.append(" }");
+ return in;
+ }
+
+}
diff --git a/vendor/nativecall/0.4.1/java/com/eaio/nativecall/IntCall.java b/vendor/nativecall/0.4.1/java/com/eaio/nativecall/IntCall.java
new file mode 100644
index 0000000..3dc60ff
--- /dev/null
+++ b/vendor/nativecall/0.4.1/java/com/eaio/nativecall/IntCall.java
@@ -0,0 +1,143 @@
+/*
+ * IntCall.java
+ *
+ * Created on 07.09.2004.
+ *
+ * eaio: NativeCall - calling operating system methods from Java
+ * Copyright (c) 2004-2006 Johann Burkard (false if calling {@link #executeCall()} returned
+ * 0, true otherwise.
+ * true or false
+ */
+ public boolean executeBooleanCall() {
+ return executeCall() == 0 ? false : true;
+ }
+
+ /**
+ * Returns false if calling {@link #executeCall(Object)}
+ * returned 0, true otherwise.
+ * null
+ * @return true or false
+ * @see #executeBooleanCall(Object[])
+ */
+ public boolean executeBooleanCall(Object param) {
+ return executeCall(param) == 0 ? false : true;
+ }
+
+ /**
+ * Returns false if calling
+ * {@link #executeCall(Object[])} returned 0, true otherwise.
+ * null
+ * @return true or false
+ */
+ public boolean executeBooleanCall(Object[] params) {
+ return executeCall(params) == 0 ? false : true;
+ }
+
+ /**
+ * Calls the function, returning its output.
+ * int
+ */
+ public native int executeCall();
+
+ /**
+ * Calls the function using the given parameter.
+ * null
+ * @return an int
+ * @see #executeCall(Object[])
+ */
+ public int executeCall(Object param) {
+ return executeCall(new Object[] { param });
+ }
+
+ /**
+ * Calls the function using the given parameters.
+ * null
+ * @return an int
+ */
+ public int executeCall(Object[] params) {
+ if (params == null || params.length == 0) {
+ return executeCall();
+ }
+ check(params);
+ return executeCall0(params);
+ }
+
+ private native int executeCall0(Object[] params);
+
+}
diff --git a/vendor/nativecall/0.4.1/java/com/eaio/nativecall/NativeCall.java b/vendor/nativecall/0.4.1/java/com/eaio/nativecall/NativeCall.java
new file mode 100644
index 0000000..482ca84
--- /dev/null
+++ b/vendor/nativecall/0.4.1/java/com/eaio/nativecall/NativeCall.java
@@ -0,0 +1,355 @@
+/*
+ * NativeCall.java
+ *
+ * Created on 07.09.2004.
+ *
+ * eaio: NativeCall - calling operating system methods from Java
+ * Copyright (c) 2004-2006 Johann Burkard (
+ * try {
+ * NativeCall.init();
+ * }
+ * catch (IOException ex) { ... }
+ * catch (SecurityException ex) { ... }
+ * catch (UnsatisfiedLinkError er) { ... }
+ * catch (sun.misc.ServiceConfigurationError) { ... }
+ * catch (UnsupportedOperationException) { ... }
+ *
+ * After usage, each NativeCall object must be destroyed to release
+ * resources. This is done by calling the {@link #destroy()} method. Failure
+ * to call this method might result in memory leaks.
+ *
+ * @see #destroy()
+ * @see #init()
+ * @author Johann Burkard
+ * @version $Id: NativeCall.java,v 1.3 2006/04/19 20:54:58 grnull Exp $
+ */
+public abstract class NativeCall {
+
+ /**
+ * The error code of the last call.
+ * NativeCall.dll could
+ * not be found
+ * @throws sun.misc.ServiceConfigurationError
+ * @throws UnsupportedOperationException if no matching
+ * {@link Verifier} could be found
+ */
+ public static synchronized void init()
+ throws
+ IOException,
+ SecurityException,
+ UnsatisfiedLinkError,
+ ServiceConfigurationError,
+ UnsupportedOperationException {
+ if (!initialized) {
+ Verifiers.init();
+ if (Verifiers.getInstance() == null) {
+ throw new UnsupportedOperationException();
+ }
+ new NativeLoader("NativeCall").load();
+ initIDs();
+ initialized = true;
+ }
+ }
+
+ /**
+ * Constructor for NativeCall.
+ *
+ * @param function the name of the function to use, may not be
+ * null
+ * @throws IllegalArgumentException if the function could not be found
+ * @throws NullPointerException if function is null
+ * @see Verifier#getDefaultModule()
+ * @see NativeCall#NativeCall(String, String)
+ */
+ public NativeCall(String function)
+ throws IllegalArgumentException, NullPointerException {
+ this(Verifiers.getInstance().getDefaultModule(), function);
+ }
+
+ /**
+ * Constructor for NativeCall.
+ *
+ * @param module the name of the module the function is stored in, may be
+ * null
+ * @param function the name of the function to use, may not be
+ * null
+ * @throws IllegalArgumentException if the function could not be found
+ * @throws NullPointerException if function is null
+ */
+ public NativeCall(String module, String function)
+ throws IllegalArgumentException, NullPointerException {
+ Verifier v = Verifiers.getInstance();
+ this.function = v.verifyFunctionName(function);
+ this.module = v.verifyModuleName(module);
+ if (!initHandles()) {
+ if (lastErrorCode != 0) {
+ throw new IllegalArgumentException(getLastError());
+ }
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Attempts to acquire handles to the functions. Returns if these could be
+ * acquired.
+ *
+ * @return if the handles could be acquired
+ */
+ private native boolean initHandles();
+
+ /**
+ * Returns the error code that was returned during the last method call or
+ * 0 if the last method call did not produce an error.
+ *
+ * @see #getLastError()
+ * @return the last error code or 0
+ */
+ public final int getLastErrorCode() {
+ return lastErrorCode;
+ }
+
+ /**
+ * Returns a formatted String containing the last error code or
+ * null if the last call did not produce an error.
+ *
+ * @see #getLastErrorCode()
+ * @return a String or null if the last error code is 0
+ */
+ public final native String getLastError();
+
+ /**
+ * Releases acquired module handles. This method must be called if the
+ * instance is not used anymore. After this method is called, methods of this
+ * NativeCall Object cannot be called anymore.
+ * null
+ * @throws ClassCastException if the type of one argument is not supported
+ */
+ protected void check(Object[] params) throws ClassCastException {
+ if (params == null) {
+ return;
+ }
+ for (int i = 0; i < params.length; ++i) {
+ checkParam(params[i]);
+ if (params[i] instanceof String) {
+ params[i] =
+ Verifiers.getInstance().handleString(
+ (String) params[i],
+ module,
+ function);
+ }
+ }
+ }
+
+ /**
+ * Checks one Object for illegal/unsupported types.
+ *
+ * @param o the Object, may be null
+ * @throws ClassCastException if the type of one argument is not supported
+ */
+ protected void checkParam(Object o) throws ClassCastException {
+ if (o == null
+ || o instanceof Boolean
+ || o instanceof Integer
+ || o instanceof byte[]
+ || o instanceof char[]
+ || o instanceof String) {
+ return;
+ }
+ if (o instanceof Holder) {
+ checkParam(((Holder) o).get());
+ return;
+ }
+ throw new ClassCastException(o.getClass().getName());
+ }
+
+ /**
+ * Returns if this Object is equal to another Object. The other Object must
+ * be an instance of the same type as this Object. Also, both the module
+ * and the function field must be equal.
+ *
+ * @param obj the other Object
+ * @return if this and the other Object are equal
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof NativeCall)) {
+ return false;
+ }
+ if (!getClass().getName().equals(obj.getClass().getName())) {
+ return false;
+ }
+ NativeCall c = (NativeCall) obj;
+ return module.equals(c.module) && function.equals(c.function);
+ }
+
+ /**
+ * Returns the hashCode of this Object. The hashCode is computed by XOR'ing
+ * the hash codes of the function and the module names.
+ *
+ * @return the hashCode
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode() {
+ int out = function.hashCode();
+ out ^= module.hashCode();
+ return out;
+ }
+
+ /**
+ * Calls {@link #destroy()}.
+ *
+ * @see java.lang.Object#finalize()
+ */
+ protected void finalize() throws Throwable {
+ try {
+ destroy();
+ }
+ finally {
+ super.finalize();
+ // in case NativeCall is a subclass of a class other than Object
+ }
+ }
+
+ /**
+ * Returns a String representation of this Object.
+ *
+ * @return a String, never null
+ * @see java.lang.Object#toString()
+ * @see #toStringBuffer(StringBuffer)
+ */
+ public final String toString() {
+ return toStringBuffer(null).toString();
+ }
+
+ /**
+ * Appends a String representation of this Object to the given
+ * {@link StringBuffer} or creates a new one if none is given.
+ *
+ * @param in the StringBuffer to append to, may be null
+ * @return a StringBuffer, never null
+ */
+ public StringBuffer toStringBuffer(StringBuffer in) {
+ if (in == null) {
+ in = new StringBuffer(64);
+ }
+ else {
+ in.ensureCapacity(in.length() + 64);
+ }
+ in.append("{ ");
+ int idx = getClass().getName().lastIndexOf(".");
+ if (idx > -1) {
+ in.append(getClass().getName().substring(++idx));
+ }
+ else {
+ in.append(getClass().getName());
+ }
+ in.append(": module = ");
+ in.append(module);
+ in.append(", function = ");
+ in.append(function);
+ in.append(" }");
+ return in;
+ }
+
+}
diff --git a/vendor/nativecall/0.4.1/java/com/eaio/nativecall/Verifier.java b/vendor/nativecall/0.4.1/java/com/eaio/nativecall/Verifier.java
new file mode 100644
index 0000000..085ae8b
--- /dev/null
+++ b/vendor/nativecall/0.4.1/java/com/eaio/nativecall/Verifier.java
@@ -0,0 +1,101 @@
+/*
+ * Verifier.java
+ *
+ * Created on 07.09.2004.
+ *
+ * eaio: NativeCall - calling operating system methods from Java
+ * Copyright (c) 2004-2006 Johann Burkard (null
+ * @see NativeCall#NativeCall(String)
+ */
+ String getDefaultModule();
+
+ /**
+ * Returns if this Verifier supports the given operating system.
+ *
+ * @return if this operating system is supported
+ * @throws SecurityException because {@link java.lang.System} properties
+ * may be queried
+ */
+ boolean supports() throws SecurityException;
+
+ /**
+ * Verifies that the given module name is correct.
+ *
+ * @param module the module name, may be null
+ * @return a module name, possibly modified, never null
+ * @throws NullPointerException if the module name is null
+ * and there is no default module defined
+ * @throws IllegalArgumentException if the module is illegal in the
+ * operating system
+ * @see #getDefaultModule()
+ */
+ String verifyModuleName(String module)
+ throws NullPointerException, IllegalArgumentException;
+
+ /**
+ * Verifies that the given function name is correct.
+ *
+ * @param function the function name, may be null
+ * @return a function name, possibly modified, never null
+ * @throws NullPointerException if the function name is null
+ * @throws IllegalArgumentException if the function is illegal in the
+ * operating system
+ */
+ String verifyFunctionName(String function)
+ throws NullPointerException, IllegalArgumentException;
+
+ /**
+ * Converts the given String to one of the following data types, based on the
+ * module and the function name:
+ *
+ *
+ *
+ *
+ * @param val the String, never byte arraychar arraynull
+ * @param module the module name, never null
+ * @param function the function name, never null
+ * @return the String converted, never null
+ */
+ Object handleString(String val, String module, String function);
+
+}
diff --git a/vendor/nativecall/0.4.1/java/com/eaio/nativecall/Verifiers.java b/vendor/nativecall/0.4.1/java/com/eaio/nativecall/Verifiers.java
new file mode 100644
index 0000000..6c86654
--- /dev/null
+++ b/vendor/nativecall/0.4.1/java/com/eaio/nativecall/Verifiers.java
@@ -0,0 +1,83 @@
+/*
+ * Verifiers.java
+ *
+ * Created on 07.09.2004.
+ *
+ * eaio: NativeCall - calling operating system methods from Java
+ * Copyright (c) 2004-2006 Johann Burkard (null
+ */
+ static Verifier getInstance() {
+ return v;
+ }
+
+}
diff --git a/vendor/nativecall/0.4.1/java/com/eaio/nativecall/VoidCall.java b/vendor/nativecall/0.4.1/java/com/eaio/nativecall/VoidCall.java
new file mode 100644
index 0000000..c3ce15e
--- /dev/null
+++ b/vendor/nativecall/0.4.1/java/com/eaio/nativecall/VoidCall.java
@@ -0,0 +1,99 @@
+/*
+ * VoidCall.java
+ *
+ * Created on 16.09.2004
+ *
+ * eaio: NativeCall - calling operating system methods from Java
+ * Copyright (c) 2004-2006 Johann Burkard (null
+ * @see #executeCall(Object[])
+ */
+ public void executeCall(Object param) {
+ executeCall(new Object[] { param });
+ }
+
+ /**
+ * Calls the function using the given parameters.
+ * null
+ */
+ public void executeCall(Object[] params) {
+ if (params == null || params.length == 0) {
+ executeCall();
+ return;
+ }
+ check(params);
+ executeCall0(params);
+ }
+
+ private native void executeCall0(Object[] params);
+
+}
diff --git a/vendor/nativecall/0.4.1/java/com/eaio/nativecall/Win32Verifier.java b/vendor/nativecall/0.4.1/java/com/eaio/nativecall/Win32Verifier.java
new file mode 100644
index 0000000..85bd60a
--- /dev/null
+++ b/vendor/nativecall/0.4.1/java/com/eaio/nativecall/Win32Verifier.java
@@ -0,0 +1,122 @@
+/*
+ * Win32Verifier.java
+ *
+ * Created on 08.09.2004.
+ *
+ * eaio: NativeCall - calling operating system methods from Java
+ * Copyright (c) 2004-2006 Johann Burkard (null
+ * or an empty String. If the module name contains forward slashes (/), they
+ * are converted to backward slashes (\).
+ *
+ * @see
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/loadlibrary.asp
+ *
+ * @see com.eaio.nativecall.Verifier#verifyModuleName(java.lang.String)
+ */
+ public String verifyModuleName(String module) {
+ if (module == null || module.length() == 0) {
+ return getDefaultModule();
+ }
+ if (module.indexOf('/') != -1) {
+ module = module.replace('/', '\\');
+ }
+ return module;
+ }
+
+ /**
+ * Throws a {@link java.lang.NullPointerException} if the function
+ * name is null or an empty String. No further processing is
+ * done.
+ *
+ * @see com.eaio.nativecall.Verifier#verifyFunctionName(java.lang.String)
+ */
+ public String verifyFunctionName(String function) {
+ if (function == null || function.length() == 0) {
+ throw new NullPointerException();
+ }
+ return function;
+ }
+
+ /**
+ * Returns "kernel32".
+ *
+ * @return "kernel32"
+ * @see com.eaio.nativecall.Verifier#getDefaultModule()
+ */
+ public String getDefaultModule() {
+ return "kernel32";
+ }
+
+ /**
+ * If the function name ends on 'W' (Windows' Unicode functions), a
+ * char array is returned, otherwise a byte array
+ * is returned.
+ * null-terminated.
+ *
+ * @see com.eaio.nativecall.Verifier#handleString(java.lang.String,
+ * java.lang.String,
+ * java.lang.String)
+ */
+ public Object handleString(String val, String module, String function) {
+ if (function.charAt(function.length() - 1) == 'W') {
+ char[] buf = new char[val.length() + 1];
+ val.getChars(0, val.length(), buf, 0);
+ return buf;
+ }
+ byte[] buf = new byte[val.length() + 1];
+ val.getBytes(0, val.length(), buf, 0);
+ return buf;
+ }
+
+}
diff --git a/vendor/nativecall/0.4.1/java/com/eaio/nativecall/package.html b/vendor/nativecall/0.4.1/java/com/eaio/nativecall/package.html
new file mode 100644
index 0000000..22b3abc
--- /dev/null
+++ b/vendor/nativecall/0.4.1/java/com/eaio/nativecall/package.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
diff --git a/vendor/nativecall/0.4.1/nativecall-0.4.1.jar b/vendor/nativecall/0.4.1/nativecall-0.4.1.jar
new file mode 100644
index 0000000..7b89804
Binary files /dev/null and b/vendor/nativecall/0.4.1/nativecall-0.4.1.jar differ
diff --git a/vendor/nativecall/0.4.1/nativeloader-200505172341.jar b/vendor/nativecall/0.4.1/nativeloader-200505172341.jar
new file mode 100644
index 0000000..b4aad60
Binary files /dev/null and b/vendor/nativecall/0.4.1/nativeloader-200505172341.jar differ
diff --git a/vendor/wiigee/1.5.6/org/wiigee/control/Wiigee.java b/vendor/wiigee/1.5.6/org/wiigee/control/Wiigee.java
new file mode 100644
index 0000000..41af532
--- /dev/null
+++ b/vendor/wiigee/1.5.6/org/wiigee/control/Wiigee.java
@@ -0,0 +1,46 @@
+/*
+ * wiigee - accelerometerbased gesture recognition
+ * Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
+ *
+ * Developed at University of Oldenburg
+ * Contact: wiigee@benjaminpoppinga.de
+ *
+ * This file is part of wiigee.
+ *
+ * wiigee is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package org.wiigee.control;
+
+import org.wiigee.util.Log;
+
+/**
+ * The mother of all classes. :-) It's just used as parent class
+ * to print version information and later on maybe dynamic configuring
+ * of the whole wiimote system... detecting plugins and devices automatically
+ * maybe. :)
+ *
+ * @author Benjamin 'BePo' Poppinga
+ */
+public class Wiigee {
+
+ protected static String version = "1.5.6";
+ protected static String releasedate = "20090817";
+
+ protected Wiigee() {
+ Log.write("This is wiigee version "+version+" ("+releasedate+")");
+ }
+
+}
diff --git a/vendor/wiigee/1.5.6/org/wiigee/control/WiimoteDeviceDiscovery.java b/vendor/wiigee/1.5.6/org/wiigee/control/WiimoteDeviceDiscovery.java
new file mode 100644
index 0000000..bdc611f
--- /dev/null
+++ b/vendor/wiigee/1.5.6/org/wiigee/control/WiimoteDeviceDiscovery.java
@@ -0,0 +1,103 @@
+/*
+ * wiigee - accelerometerbased gesture recognition
+ * Copyright (C) 2007, 2008, 2009 Benjamin Poppinga
+ *
+ * Developed at University of Oldenburg
+ * Contact: wiigee@benjaminpoppinga.de
+ *
+ * This file is part of wiigee.
+ *
+ * wiigee is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+package org.wiigee.control;
+
+import java.io.IOException;
+import java.util.Vector;
+
+import javax.bluetooth.DeviceClass;
+import javax.bluetooth.DiscoveryListener;
+import javax.bluetooth.RemoteDevice;
+import javax.bluetooth.ServiceRecord;
+
+import org.wiigee.util.Log;
+
+import org.wiigee.device.Wiimote;
+
+public class WiimoteDeviceDiscovery implements DiscoveryListener {
+
+ private Vector