diff options
author | Alberto Ruiz <alberto.ruiz@sun.com> | 2007-10-30 17:21:07 +0000 |
---|---|---|
committer | Alberto Ruiz <alberto.ruiz@sun.com> | 2007-10-30 17:21:07 +0000 |
commit | aadeffb3f0716ffd231d1146d050847e3be355ee (patch) | |
tree | 9f2ed61a84a37fce5f154498023b28d6bfbf69bf /src |
2007-30-10 Alberto Ruiz <alberto.ruiz@sun.com>
* Initial commit.
Diffstat (limited to 'src')
84 files changed, 11235 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..05023f1 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = com/ diff --git a/src/com/Makefile.am b/src/com/Makefile.am new file mode 100644 index 0000000..1d06788 --- /dev/null +++ b/src/com/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = sun diff --git a/src/com/sun/Makefile.am b/src/com/sun/Makefile.am new file mode 100644 index 0000000..b5d5f2c --- /dev/null +++ b/src/com/sun/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = apoc diff --git a/src/com/sun/apoc/Makefile.am b/src/com/sun/apoc/Makefile.am new file mode 100644 index 0000000..75ad827 --- /dev/null +++ b/src/com/sun/apoc/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = daemon diff --git a/src/com/sun/apoc/daemon/Makefile.am b/src/com/sun/apoc/daemon/Makefile.am new file mode 100644 index 0000000..f76f046 --- /dev/null +++ b/src/com/sun/apoc/daemon/Makefile.am @@ -0,0 +1,5 @@ +all: + $(ANT) + +clean-local: + $(ANT) -q clean diff --git a/src/com/sun/apoc/daemon/admin/AdminManager.java b/src/com/sun/apoc/daemon/admin/AdminManager.java new file mode 100644 index 0000000..3dfcf68 --- /dev/null +++ b/src/com/sun/apoc/daemon/admin/AdminManager.java @@ -0,0 +1,286 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.admin; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transport.*; + +import java.io.*; +import java.net.*; +import java.nio.*; +import java.nio.channels.*; +import java.util.*; + +public class AdminManager extends Thread +{ + private static final byte[] sSuccess = { 0 }; + private static final byte[] sFailure = { 1 }; + private static final byte sOpChangeDetect = ( byte )1; + private static final byte sOpReload = ( byte )6; + private static final byte sOpStatus = ( byte )9; + private static final byte sOpStop = ( byte )10; + + private static final byte[] sAcceptByte = { 1 }; + private static final ByteBuffer sAccept = + ( ByteBuffer )ByteBuffer.wrap( sAcceptByte ); + + private Selector mSelector; + private ServerSocketChannel mChannel; + private AdminOpHandler mAdminOpHandler; + private final Object mTerminateLock = new Object(); + private boolean mTerminate = false; + + public AdminManager( final AdminOpHandler inAdminOpHandler ) + throws APOCException + { + setName( "AdminManager" ); + mAdminOpHandler = inAdminOpHandler; + initChannel(); + } + + public void run() + { + APOCLogger.fine( "Admr001" ); + while ( ! shouldTerminate() ) + { + try + { + final ClientChannel theChannel = acceptClientChannel(); + if ( theChannel != null ) + { + if ( authenticate( theChannel ) ) + { + try + { + handleRequest( theChannel ); + } + catch( Exception theException ) + { + APOCLogger.throwing( "AdminManager", + "run", + theException ); + } + } + theChannel.close(); + } + } + catch ( IOException theException ) + { + APOCLogger.throwing( "AdminManager", "run", theException ); + break; + } + } + closeServerChannel(); + APOCLogger.fine( "Admr002" ); + } + + public void terminate() + { + synchronized( mTerminateLock ) + { + mTerminate = true; + } + } + + private ClientChannel acceptClientChannel() + throws IOException + { + ClientChannel theChannel = null; + if ( mSelector.select() > 0 ) + { + final Iterator theIterator = mSelector.selectedKeys().iterator(); + while ( theIterator.hasNext() ) + { + final SelectionKey theKey = ( SelectionKey )theIterator.next(); + theIterator.remove(); + if ( theKey.isAcceptable() ) + { + SocketChannel theSocketChannel = null; + try + { + theSocketChannel = + (( ServerSocketChannel )theKey.channel() ).accept(); + if ( theSocketChannel. + socket(). + getInetAddress(). + isLoopbackAddress() ) + { + theChannel = + new ClientChannel( theSocketChannel, null); + theChannel.write( sAccept ); + sAccept.flip(); + break; + } + } + catch( IOException theException ) + { + if ( theSocketChannel != null ) + { + try + { + theSocketChannel.close(); + } + catch( IOException ignore ){} + } + APOCLogger.throwing( "AdminManager", + "acceptClientChannel", + theException ); + } + } + } + } + return theChannel; + } + + private boolean authenticate( final ClientChannel inChannel ) + { + boolean isAuthenticated; + APOCAuthenticator theAuthenticator = null; + try + { + theAuthenticator = new APOCAuthenticator( null ); + byte[] theChallenge = theAuthenticator.getChallenge(); + inChannel.write( + ( ByteBuffer )ByteBuffer.allocate( theChallenge.length + 1 ) + .put( theChallenge ) + .put( ( byte )0 ) + .flip() ); + ByteBuffer theAuthBuffer = + ByteBuffer.wrap( + new byte[ APOCAuthenticator.getAuthBufferSize() ] ); + while ( inChannel.read( theAuthBuffer ) == 0 ){} + theAuthenticator.processResponse( theAuthBuffer.array() ); + inChannel.write( + ( ByteBuffer )ByteBuffer.allocate( 1 ).put( sSuccess ).flip() ); + isAuthenticated = true; + } + catch( Exception theException ) + { + inChannel.write( + ( ByteBuffer )ByteBuffer.allocate( 1 ).put( sFailure ).flip() ); + isAuthenticated = false; + } + finally + { + if ( theAuthenticator != null ) + { + theAuthenticator.cleanup(); + } + } + return isAuthenticated; + } + + private void closeServerChannel() + { + try + { + mSelector.close(); + mChannel.close(); + } + catch( IOException theException ) + { + APOCLogger.throwing( "AdminManager", + "closeServerChannel", + theException ); + } + } + + private void handleRequest( final ClientChannel inChannel ) + throws Exception + { + int theRC; + ByteBuffer theBuffer = ByteBuffer.wrap( new byte[ 1 ] ); + while ( inChannel.read( theBuffer ) != 1 ){} + switch( theBuffer.array()[ 0 ] ) + { + case sOpStop: + theRC = mAdminOpHandler.onStop(); + terminate(); + break; + + case sOpStatus: + theRC = mAdminOpHandler.onStatus(); + break; + + case sOpReload: + theRC = mAdminOpHandler.onReload(); + break; + + case sOpChangeDetect: + theRC = mAdminOpHandler.onChangeDetect(); + break; + + default: + theRC = -1; + break; + } + theBuffer = ByteBuffer.wrap( theRC == 0 ? sSuccess : sFailure ); + inChannel.write( theBuffer ); + } + + private void initChannel() + throws APOCException + { + try + { + mSelector = Selector.open(); + mChannel = ServerSocketChannel.open(); + mChannel.configureBlocking( false ); + mChannel.socket().bind( null ); + mChannel.register( mSelector, SelectionKey.OP_ACCEPT ); + /* + * 6417539 - Need to use IANA registered port + * Use a PortMapper instance to let admin. clients + * know which port the agent is using. + */ + new PortMapper( + ( ( InetSocketAddress )mChannel.socket().getLocalSocketAddress() ) + .getPort() ).start(); + } + catch( IOException theException ) + { + throw new APOCException( theException ); + } + } + + private boolean shouldTerminate() + { + synchronized( mTerminateLock ) + { + return mTerminate; + } + } +} diff --git a/src/com/sun/apoc/daemon/admin/AdminOpHandler.java b/src/com/sun/apoc/daemon/admin/AdminOpHandler.java new file mode 100644 index 0000000..edc357c --- /dev/null +++ b/src/com/sun/apoc/daemon/admin/AdminOpHandler.java @@ -0,0 +1,43 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.admin; + +public interface AdminOpHandler +{ + int onStop(); + int onStatus(); + int onReload(); + int onChangeDetect(); +} diff --git a/src/com/sun/apoc/daemon/admin/PortMapper.java b/src/com/sun/apoc/daemon/admin/PortMapper.java new file mode 100644 index 0000000..04c3b5f --- /dev/null +++ b/src/com/sun/apoc/daemon/admin/PortMapper.java @@ -0,0 +1,100 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.admin; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.misc.*; + +import java.io.*; +import java.nio.*; +import java.nio.channels.*; +import java.net.*; + +/* + * Not really a port mapper but .... + * + * This class is used to inform admin. clients which port is currently being + * used for admin. access. It simply accepts a udp connection and reponds + * with the relevant port number. This is repeated indefinitely. + */ +public class PortMapper extends Thread +{ + private static int sPort = + DaemonConfig.getIntProperty( DaemonConfig.sDaemonPort ); + private ByteBuffer mAdminPort; + private DatagramChannel mChannel; + + public PortMapper( int inAdminPort ) + throws APOCException + { + try + { + setName( "PortMapper" ); + setDaemon( true ); + mAdminPort = + ( ByteBuffer )ByteBuffer.allocate( 6 ) + .put( String.valueOf( inAdminPort ).getBytes() ) + .put( ( byte )0 ); + mChannel = DatagramChannel.open(); + mChannel.socket().bind( new InetSocketAddress( sPort ) ); + } + catch( Exception theException ) + { + throw new APOCException( theException ); + } + } + + public void run() + { + ByteBuffer theBuffer = ByteBuffer.allocate( 1 ); + while ( true ) + { + try + { + InetSocketAddress theClient = + ( InetSocketAddress )mChannel.receive( + ( ByteBuffer )theBuffer.position( 0 ) ); + if ( theClient != null && + theClient.getAddress().isLoopbackAddress() ) + { + mChannel.send( ( ByteBuffer )mAdminPort.position( 0 ), + theClient ); + } + } + catch( Exception theIgnore ) + {} + } + } +} diff --git a/src/com/sun/apoc/daemon/apocd/Cache.java b/src/com/sun/apoc/daemon/apocd/Cache.java new file mode 100755 index 0000000..515ce09 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/Cache.java @@ -0,0 +1,927 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.localdatabase.*; +import com.sun.apoc.daemon.misc.*; + +import com.sun.apoc.spi.*; +import com.sun.apoc.spi.policies.*; + +import java.util.*; +import javax.security.auth.callback.*; + + +public class Cache implements ConfigEventListener +{ + private String mUserName; + private String mEntityType; + private String mEntityId; + private CallbackHandler mHandler; + private DataSource mDataSources[] = null; + private final HashSet mSessions = new HashSet(); + private int mRefCount = 0; + private boolean mIsLocalPolicyEnabled = + DaemonConfig.getBooleanProperty( DaemonConfig.sApplyLocalPolicy ); + private static final String[] sStringModel = new String[ 0 ]; + + public Cache( final String inUserName, + final String inEntityType, + final String inEntityId, + final SaslAuthCallbackHandler inHandler ) + { + mUserName = inUserName; + mEntityType = inEntityType; + mEntityId = inEntityId; + mHandler = inHandler; + createDataSources(); + inHandler.setReconnectMode(); + DaemonConfig.addConfigEventListener( this ); + } + + public synchronized int acquire( final Session inSession ) + { + mSessions.add( inSession ); + return ++ mRefCount; + } + public synchronized int release( final Session inSession ) + { + mSessions.remove( inSession ); + return -- mRefCount; + } + public synchronized Session [] getSessions() + { + return (Session []) mSessions.toArray(new Session [0]); + } + public synchronized ArrayList changeDetect() + { + for ( int theIndex = 0 ; theIndex < mDataSources.length ; ++ theIndex ) + { + mDataSources[ theIndex ].open(mHandler); + } + ArrayList theResults = new ArrayList(); + HashSet theOriginalList = null; + int theOnlineDataSourceCount = 0; + + for ( int theIndex = 0 ; theIndex < mDataSources.length ; ++ theIndex ) + { + if ( mDataSources[ theIndex ].isOnline()) + { + ++ theOnlineDataSourceCount; + } + } + if ( theOnlineDataSourceCount > 1 ) + { + theOriginalList = list(); + } + for ( int theIndex = 0 ; theIndex < mDataSources.length ; theIndex ++ ) + { + final ArrayList theResult = + changeDetect( mDataSources[ theIndex ] ); + if ( theResult != null ) + { + theResults.addAll( theResult ); + } + } + if ( theOnlineDataSourceCount > 1 ) + { + theResults = mergeUpdateResults( theResults, theOriginalList ); + } + return theResults; + } + + public synchronized void close() + { + for ( int theIndex = 0; theIndex < mDataSources.length ; theIndex ++ ) + { + mDataSources[ theIndex ].close(); + } + } + + public String getEntityType() { return mEntityType; } + + public String getEntityId() { return mEntityId; } + + public boolean isOutOfDate() + { + long lastChangeDetect = Timestamp.getMillis(getLastChangeDetect()) ; + + if (lastChangeDetect == 0) { return true ; } + return lastChangeDetect + + (long) (DaemonConfig.getFloatProperty( + DaemonConfig.sChangeDetectionInterval) * 60000) < + Timestamp.getMillis(Timestamp.getTimestamp()) ; + } + + public synchronized String getLastChangeDetect() + { + String theResult = null; + for ( int theIndex = 0; theIndex < mDataSources.length; theIndex ++ ) + { + final LocalDatabase theDatabase = + mDataSources[ theIndex ].getLocalDatabase(); + if ( theDatabase != null ) + { + try + { + theDatabase.beginTransaction(); + final String theTimestamp=theDatabase.getLastChangeDetect(); + if ( theTimestamp.compareTo( Timestamp.sEpoch ) == 0 ) + { + break; + } + else if ( theResult == null ) + { + theResult = theTimestamp; + } + else if ( Timestamp.isNewer( theResult, theTimestamp ) ) + { + theResult = theTimestamp; + } + } + catch( APOCException theException ) + { + APOCLogger.throwing( "Cache", + "getLastChangeDetect", + theException ); + } + finally + { + try + { + theDatabase.endTransaction(); + } + catch( APOCException theException ) + { + APOCLogger.throwing( "Cache", + "getLastChangeDetect", + theException ); + } + } + } + } + return theResult != null ? theResult : Timestamp.sEpoch; + } + + public String getUserId() { return mUserName; } + + public synchronized boolean hasDatabase( final Database inDatabase ) + { + boolean haveLocalDatabase = false; + for ( int theIndex = 0; theIndex < mDataSources.length; theIndex ++ ) + { + if ( mDataSources[ theIndex ].getLocalDatabase() == inDatabase ) + { + haveLocalDatabase = true; + break; + } + } + return haveLocalDatabase; + } + + public synchronized HashSet list() + { + HashSet theComponents = new HashSet(); + for ( int theIndex = 0; theIndex < mDataSources.length; theIndex ++ ) + { + final HashSet theSet = list ( mDataSources[ theIndex ] ); + if ( theSet != null ) + { + theComponents.addAll( theSet ); + } + } + return theComponents; + } + + public synchronized void onConfigEvent() + { + boolean isLocalPolicyEnabled = + DaemonConfig.getBooleanProperty( DaemonConfig.sApplyLocalPolicy ); + if ( isLocalPolicyEnabled != mIsLocalPolicyEnabled ) + { + mIsLocalPolicyEnabled = isLocalPolicyEnabled; + if ( mIsLocalPolicyEnabled ) + { + enableLocalPolicy(); + } + else + { + disableLocalPolicy(); + } + } + } + + public synchronized ArrayList read( final String inComponentName ) + { + final ArrayList theResults = new ArrayList(); + for ( int theIndex = 0; theIndex < mDataSources.length; theIndex ++ ) + { + final ArrayList theResult = + read( mDataSources[ theIndex ], inComponentName ); + if ( theResult != null ) + { + theResults.addAll( theResult ); + } + } + return theResults; + } + + public synchronized String toString() + { + final StringBuffer theBuffer = new StringBuffer(); + for ( int theIndex = 0; theIndex < mDataSources.length; theIndex ++ ) + { + theBuffer.append( " dataSource" + ( theIndex + 1 ) ) + .append( "\n " ) + .append( mDataSources[ theIndex ].toString() ) + .append( "\n" ); + } + return theBuffer.toString(); + } + + private ArrayList changeDetect( final DataSource inDataSource ) + { + ArrayList theResult = null; + if ( inDataSource.isOnline() ) + { + final LocalDatabase theDatabase = inDataSource.getLocalDatabase(); + try + { + theDatabase.beginTransaction(); + switch( inDataSource.getState() ) + { + case DataSource.sStateEnabled: + theResult = updateLocalDatabase( inDataSource ); + break; + + case DataSource.sStateDisabling: + theResult = new ArrayList(); + addRemovalItems( theResult, + theDatabase.getLocalComponentList() ); + break; + case DataSource.sStateEnabling: + theResult = new ArrayList(); + addAdditionItems( theResult, + inDataSource, + theDatabase.getLocalComponentList() ); + inDataSource.setState( DataSource.sStateEnabled ); + break; + + default: + break; + } + } + catch( Exception theException ) + { + APOCLogger.throwing( "Cache", "changeDetect", theException ); + } + finally + { + try + { + theDatabase.endTransaction(); + } + catch( APOCException theException ) + { + APOCLogger.throwing( "Cache", + "changeDetect", + theException ); + } + } + if ( inDataSource.mState == DataSource.sStateDisabling ) + { + inDataSource.close(); + } + } + return theResult; + } + + private void createDataSources() + { + mDataSources = new DataSource [2]; + mDataSources[ 0 ] = new DataSource( mUserName, + mEntityType, + mEntityId, + true ); + mDataSources[ 1 ] = new DataSource( mUserName, + mEntityType, + mEntityId, + false ); + if ( mIsLocalPolicyEnabled ) + { + mDataSources[ 0 ].open( mHandler ); + } + mDataSources[ 1 ].open( mHandler ); + } + + private void disableLocalPolicy() + { + mDataSources[ 0 ].setState( DataSource.sStateDisabling ); + } + + private void enableLocalPolicy() + { + mDataSources[ 0 ].setState( DataSource.sStateEnabling ); + } + + private HashSet list( final DataSource inDataSource ) + { + HashSet theSet = null; + if ( inDataSource.getState() == DataSource.sStateEnabled ) + { + final LocalDatabase theDatabase = inDataSource.getLocalDatabase(); + if ( theDatabase != null ) + { + try + { + theDatabase.beginTransaction(); + theSet = theDatabase.getRemoteComponentList(); + } + catch ( APOCException theException ) + { + APOCLogger.throwing( "Cache", "list", theException ); + } + finally + { + try + { + theDatabase.endTransaction(); + } + catch( APOCException theException ) + { + APOCLogger.throwing( "Cache", "list", theException ); + } + } + } + } + return theSet; + } + + private ArrayList mergeUpdateResults( final ArrayList inResults, + final HashSet inOriginalList ) + { + ArrayList theResult = inResults; + if ( inResults.size() > 0 && + inOriginalList != null && + inOriginalList.size() > 0 ) + { + final HashSet theNewList = list(); + final HashSet theUpdatedComponents = new HashSet(); + final Iterator theIterator = inResults.iterator(); + theResult = new ArrayList(); + while ( theIterator.hasNext() ) + { + final UpdateItem theItem = ( UpdateItem )theIterator.next(); + final String theName = theItem.getComponentName(); + if ( theUpdatedComponents.add( theName ) ) + { + if ( ( theItem.getUpdateType() == UpdateItem.ADD && + inOriginalList.contains( theName ) ) || + ( theItem.getUpdateType() == UpdateItem.REMOVE ) && + theNewList.contains( theName ) ) + { + theItem.setUpdateType( UpdateItem.MODIFY ); + } + theResult.add( theItem ); + } + } + } + return theResult; + } + + private ArrayList read( final DataSource inDataSource, + final String inComponentName ) + { + final ArrayList theResult = new ArrayList(); + final LocalDatabase theDatabase = inDataSource.getLocalDatabase(); + if ( theDatabase != null ) + { + try + { + theDatabase.beginTransaction(); + boolean haveComponent = + theDatabase.hasComponent( inComponentName ); + if ( ! haveComponent && inDataSource.isOnline() ) + { + final HashSet theSet = theDatabase.getRemoteComponentList(); + if ( theSet != null && theSet.contains( inComponentName ) ) + { + final Policy[] thePolicies = + inDataSource. + getPolicyBackend(). + getLayeredPolicies( + inComponentName, + false ); + if ( thePolicies != null ) + { + theDatabase. + update( + new UpdateItem( + UpdateItem.ADD, + inComponentName, + thePolicies ), + Timestamp.getTimestamp() ); + haveComponent = true; + } + } + } + if ( haveComponent ) + { + final Vector theLayerIds = + theDatabase.getLayerIds( inComponentName ); + for ( int theIndex = 0; + theIndex < theLayerIds.size(); + ++ theIndex ) + { + final String theLayerId = + ( String )theLayerIds.elementAt( theIndex ); + theResult.add( + new CacheReadResult( + theDatabase. + getLastModified( theLayerId, + inComponentName ), + theDatabase. + getLayer( inComponentName, theLayerId ) ) ); + } + } + } + catch ( APOCException theException ) + { + APOCLogger.throwing( "Cache", "read", theException ); + } + finally + { + try + { + theDatabase.endTransaction(); + } + catch( APOCException theException ) + { + APOCLogger.throwing( "Cache", "read", theException ); + } + } + } + return theResult; + } + + private void addDownloadItems( final ArrayList outResult, + final DataSource inDataSource, + final HashSet inAddComponents, + final HashSet inModifyComponents ) + throws APOCException + { + if ( inAddComponents != null && inModifyComponents != null ) + { + final HashSet theSet = ( HashSet)inAddComponents.clone(); + int theAddCount = theSet.size(); + theSet.addAll( inModifyComponents ); + final Policy[][] thePolicies = + ( Policy[][] )inDataSource.getPolicyBackend(). + getLayeredPolicies( theSet, false ); + final Iterator theIterator = theSet.iterator(); + int theIndex = 0; + while ( theIterator.hasNext() ) + { + final String theComponent = ( String )theIterator.next(); + outResult.add( + new UpdateItem( inAddComponents.contains( theComponent ) ? + UpdateItem.ADD : UpdateItem.MODIFY, + theComponent, + thePolicies[ theIndex ++ ] ) ); + } + + } + else + if ( inAddComponents != null ) + { + addAdditionItems( outResult, inDataSource, inAddComponents ); + } + else if ( inModifyComponents != null ) + { + addModificationItems( outResult, inDataSource, inModifyComponents ); + } + + } + + private void addAdditionItems( final ArrayList outResult, + final DataSource inDataSource, + final HashSet inComponents ) + throws APOCException + { + if ( inComponents != null ) + { + final Policy[][] thePolicies = + ( Policy[][] )inDataSource. + getPolicyBackend(). + getLayeredPolicies( inComponents, false ); + final Iterator theIterator = inComponents.iterator(); + int theIndex = 0; + while ( theIterator.hasNext() ) + { + outResult.add( + new UpdateItem( UpdateItem.ADD, + ( String )theIterator.next(), + thePolicies[ theIndex ++ ] ) ); + } + } + } + + private void addModificationItems( final ArrayList outResult, + final DataSource inDataSource, + final HashSet inComponents ) + throws APOCException + { + if ( inComponents != null ) + { + final Policy[][] thePolicies = + ( Policy[][] )inDataSource. + getPolicyBackend(). + getLayeredPolicies( inComponents, false ); + final Iterator theIterator = inComponents.iterator(); + int theIndex = 0; + while ( theIterator.hasNext() ) + { + outResult.add( + new UpdateItem( UpdateItem.MODIFY, + ( String )theIterator.next(), + thePolicies[ theIndex ++ ] ) ); + } + } + } + + private void addRemovalItems( final ArrayList outResult, + final HashSet inComponents ) + throws APOCException + { + if ( inComponents != null ) + { + final Iterator theIterator = inComponents.iterator(); + while ( theIterator.hasNext() ) + { + outResult.add( + new UpdateItem( UpdateItem.REMOVE, + ( String )theIterator.next(), + null ) ); + } + } + } + + private int compareLayers( final DataSource inDataSource, + final String inComponentName, + final PolicyInfo[] inPolicies ) + throws APOCException + { + int theRC = 0; + final LocalDatabase theDatabase = inDataSource.getLocalDatabase(); + final Vector theLayerIds = + theDatabase.getLayerIds( inComponentName ); + if ( theLayerIds.size() != inPolicies.length ) + { + theRC = 1; + } + else + { + final String theComponentName = inPolicies[ 0 ].getId(); + for ( int theIndex = 0 ; theIndex < inPolicies.length; ++ theIndex) + { + final String theLayerId = + ( String )theLayerIds.elementAt( theIndex ); + + + if ( theLayerId.compareTo( + String.valueOf( + inPolicies[ theIndex ].getProfileId().hashCode() ) ) + != 0 + || + Timestamp.getTimestamp( + inPolicies[ theIndex ].getLastModified() ).compareTo( + theDatabase. + getLastModified( theLayerId, theComponentName )) + != 0 ) + { + theRC = 1; + break; + } + } + } + return theRC; + } + + private void createUpdateItems( final ArrayList outResult, + final DataSource inDataSource, + final HashSet inRemoteComponents ) + throws APOCException + { + final HashSet theLocalComponents = + inDataSource.getLocalDatabase().getLocalComponentList(); + final HashSet theAdditions = + diff( inRemoteComponents, theLocalComponents ); + final HashSet theRemovals = + diff( theLocalComponents, inRemoteComponents ); + final HashSet theModifications = + getModifications( inDataSource, + diff( theLocalComponents, theRemovals ) ); + addDownloadItems( outResult, + inDataSource, + theAdditions, + theModifications ); + addRemovalItems( outResult, theRemovals ); + } + + private HashSet diff( final HashSet inSet1, final HashSet inSet2 ) + { + HashSet theResult = null; + if ( inSet2 == null ) + { + theResult = inSet1; + } + else + if ( inSet1 != null ) + { + theResult = ( HashSet )inSet1.clone(); + theResult.removeAll( inSet2 ); + if ( theResult.size() == 0 ) + { + theResult = null; + } + } + return theResult; + } + + private HashSet getModifications( final DataSource inDataSource, + final HashSet inSet ) + throws APOCException + { + HashSet theModifications = null; + if ( inSet != null ) + { + final PolicyInfo[][] thePolicies = + inDataSource. + getPolicyBackend(). + getLayeredPolicies( inSet, true ); + final String[] theComponents = + ( String[] )inSet.toArray( sStringModel ); + theModifications = new HashSet(); + for ( int theIndex = 0 ; theIndex < thePolicies.length; ++ theIndex) + { + if ( isUpdated( inDataSource, + theComponents[ theIndex ], + thePolicies[ theIndex ] ) ) + { + theModifications.add( theComponents[ theIndex ] ); + } + } + if ( theModifications.size() == 0 ) + { + theModifications = null; + } + } + return theModifications; + } + + private boolean isUpdated( final DataSource inDataSource, + final String inComponent, + final PolicyInfo[] inPolicies ) + throws APOCException + { + boolean isUpdated = false; + if ( inPolicies == null ) + { + isUpdated = true; + } + else + { + isUpdated = compareLayers( inDataSource, inComponent, inPolicies ) + == 0 ? false : true; + } + return isUpdated; + } + + private ArrayList updateLocalDatabase( final DataSource inDataSource ) + throws APOCException + { + final ArrayList theResult = new ArrayList(); + try + { + final PolicyBackend theBackend = inDataSource.getPolicyBackend(); + theBackend.refreshProfiles(); + final HashSet theRemoteComponents = theBackend.getComponentList(); + createUpdateItems( theResult, inDataSource, theRemoteComponents ); + theResult.trimToSize(); + final String theTimestamp= Timestamp.getTimestamp(); + final LocalDatabase theDatabase = inDataSource.getLocalDatabase(); + theDatabase.update( theResult, theTimestamp ); + theDatabase.putLastChangeDetect( theTimestamp ); + theDatabase.putRemoteComponentList( + theRemoteComponents != null ? + theRemoteComponents : new HashSet() ); + } + catch( SPIException theException ) + { + throw new APOCException( theException ); + } + return theResult; + } + + private static class DataSource + { + protected LocalDatabase mLocalDatabase; + protected PolicyBackend mPolicyBackend; + protected Name mName; + protected int mState = sStateDisabled; + protected boolean mInitialised = false; + + static final int sStateEnabled = 0; + static final int sStateDisabled = 1; + static final int sStateEnabling = 2; + static final int sStateDisabling = 3; + + DataSource( final String inUserName, + final String inEntityType, + final String inEntityId, + final boolean inIsLocal ) + { + mName = new Name( inUserName, inEntityType, inEntityId, inIsLocal ); + } + + void close() + { + closePolicyBackend(); + closeLocalDatabase(); + } + + synchronized LocalDatabase getLocalDatabase() { return mLocalDatabase; } + + synchronized PolicyBackend getPolicyBackend() { return mPolicyBackend; } + + synchronized int getState() { return mState; } + + synchronized boolean isOnline() { + return mPolicyBackend != null && mLocalDatabase != null; } + + synchronized void open( final CallbackHandler inHandler ) + { + boolean isLocal = mName.isLocal(); + if ( ! isLocal || + DaemonConfig.getBooleanProperty( + DaemonConfig.sApplyLocalPolicy ) ) + { + if ( mLocalDatabase == null ) + { + mLocalDatabase = openLocalDatabase(); + } + try + { + if ( mLocalDatabase != null && mPolicyBackend == null && + ( mInitialised || + mLocalDatabase.getLastChangeDetect().compareTo( + Timestamp.sEpoch ) == 0 ) ) + { + mPolicyBackend = openPolicyBackend( inHandler ); + if ( ! mInitialised && mPolicyBackend != null ) + { + initialiseDatabase(); + } + } + } + catch( APOCException theException ) + { + APOCLogger.throwing( "DataSource", "open", theException ); + } + mInitialised = true; + if ( ! isLocal || mState != sStateEnabling ) + { + mState = sStateEnabled; + } + } + } + + synchronized void setState( int inState ) { mState = inState; } + + public String toString() + { + return new StringBuffer( " Name: " ) + .append( mName.toString() ) + .append( "\n Cache: " ) + .append( mLocalDatabase ) + .append( "\n Backend: " ) + .append( mPolicyBackend ) + .toString(); + } + + protected void initialiseDatabase() + { + try + { + final HashSet theSet = mPolicyBackend.getComponentList(); + if ( theSet != null ) + { + mLocalDatabase.beginTransaction(); + mLocalDatabase.putRemoteComponentList( theSet ); + mLocalDatabase.endTransaction(); + } + } + catch( Exception theException ) + { + APOCLogger.throwing( "DataSource", + "initialiseDatabase", + theException); + } + } + + protected void closeLocalDatabase() + { + if ( mLocalDatabase != null ) + { + try + { + LocalDatabaseFactory.getInstance().closeLocalDatabase( + mLocalDatabase ); + } + catch( Exception theException ){} + finally { mLocalDatabase = null; } + } + } + + protected void closePolicyBackend() + { + if ( mPolicyBackend != null ) + { + PolicyBackendFactory.getInstance().closePolicyBackend( + mPolicyBackend ); + mPolicyBackend = null; + } + } + + protected LocalDatabase openLocalDatabase() + { + LocalDatabase theLocalDatabase = null; + try + { + theLocalDatabase = + LocalDatabaseFactory.getInstance(). + openLocalDatabase( mName ); + } + catch( Exception theException ) + { + APOCLogger.throwing( "DataSource", + "openLocalDatabase", + theException ); + } + return theLocalDatabase; + } + + protected PolicyBackend openPolicyBackend( + final CallbackHandler inHandler ) + { + PolicyBackend theBackend = null; + try + { + theBackend = + PolicyBackendFactory + .getInstance() + .openPolicyBackend( mName, inHandler ); + } + catch( APOCException theException ) + { + APOCLogger.throwing( "PolicyBackend", + "openPolicyBackend", + theException ); + } + return theBackend; + } + } +} diff --git a/src/com/sun/apoc/daemon/apocd/CacheFactory.java b/src/com/sun/apoc/daemon/apocd/CacheFactory.java new file mode 100755 index 0000000..65d5f39 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/CacheFactory.java @@ -0,0 +1,151 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.misc.*; + +import java.util.*; +import javax.security.auth.callback.*; + +public class CacheFactory +{ + private final HashMap mCaches = new HashMap(); + private static final CacheFactory sInstance = new CacheFactory(); + private static final Cache[] sCacheModel = new Cache[ 0 ]; + + private synchronized void closeCache( final Cache inCache, + final Session inSession ) + { + if ( inCache.release( inSession ) == 0 ) + { + final Cache theCache = + ( Cache )mCaches.remove( + makeKey( inCache.getUserId(), + inCache.getEntityType(), + inCache.getEntityId() ) ); + if ( theCache != null ) + { + theCache.close(); + } + } + } + + public void closeCaches( final Cache[] inCaches, final Session inSession ) + { + for ( int theIndex = 0 ; theIndex < inCaches.length ; ++ theIndex ) + { + closeCache( inCaches[ theIndex ], inSession ); + } + } + + public synchronized Cache[] getCaches() + { + Cache[] theCaches = null; + if ( mCaches.size() > 0 ) + { + theCaches = ( Cache[] )mCaches.values().toArray( sCacheModel ); + } + return theCaches; + } + + public static CacheFactory getInstance() { return sInstance; } + + public synchronized Cache [] openCaches( + final String inUserId, + final Hashtable inEntities, + final Session inSession, + final SaslAuthCallbackHandler inHandler ) + throws APOCException + { + String [] theSources = PolicyBackendFactory.getInstance().getSources(); + ArrayList theCaches = new ArrayList(); + + for ( int theIndex = 0 ; theIndex < theSources.length ; ++ theIndex ) + { + String theEntity = + (String) inEntities.get( theSources[ theIndex ] ); + Cache theCache = getCache( inUserId, theSources[ theIndex ], + theEntity, inHandler ); + + theCache.acquire( inSession ); + theCaches.add( theCache ); + } + return (Cache []) theCaches.toArray( sCacheModel ); + } + + private CacheFactory(){} + + private Cache getCache(final String inUserId, + final String inEntityType, + final String inEntityId, + final SaslAuthCallbackHandler inHandler) + throws APOCException + { + Cache retCode = getExistingCache(inUserId, inEntityType, inEntityId) ; + + if (retCode == null) + { + retCode = createNewCache(inUserId, inEntityType, + inEntityId, inHandler) ; + } + return retCode ; + } + private Cache createNewCache( final String inUserId, + final String inEntityType, + final String inEntityId, + final SaslAuthCallbackHandler inHandler ) + throws APOCException + { + Cache theCache = new Cache( inUserId, inEntityType, + inEntityId, inHandler ); + mCaches.put( makeKey( inUserId, inEntityType, inEntityId ), theCache ); + return theCache; + } + + private Cache getExistingCache( final String inUserId, + final String inEntityType, + final String inEntityId ) + { + return ( Cache )mCaches.get( makeKey( inUserId, inEntityType, + inEntityId ) ); + } + + private String makeKey( final String inUserId, final String inEntityType, + final String inEntityId ) + { + return inUserId + "/" + inEntityType + "/" + + ( inEntityId != null ? inEntityId : "" ); + } +} diff --git a/src/com/sun/apoc/daemon/apocd/CacheReadResult.java b/src/com/sun/apoc/daemon/apocd/CacheReadResult.java new file mode 100755 index 0000000..e7e9a75 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/CacheReadResult.java @@ -0,0 +1,47 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +public class CacheReadResult +{ + public String mTimestamp; + public String mData; + + public CacheReadResult( final String inTimestamp, final String inData ) + { + mTimestamp = inTimestamp; + mData = inData; + } +} diff --git a/src/com/sun/apoc/daemon/apocd/ChangeDetectEventHandler.java b/src/com/sun/apoc/daemon/apocd/ChangeDetectEventHandler.java new file mode 100644 index 0000000..0ee5bb6 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/ChangeDetectEventHandler.java @@ -0,0 +1,93 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.localdatabase.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.transaction.*; + +class ChangeDetectEventHandler implements EventHandler +{ + private final ChangeDetectTransaction mTransaction; + private long sTimeout = 100; + private final Object mCompleteLock = new Object(); + private boolean mComplete = false; + + ChangeDetectEventHandler( final ClientManager inManager, + final Cache inCache, + final UpdateAggregator inAggregator ) + { + mTransaction = TransactionFactory + .getInstance() + .createChangeDetectTransaction( inManager, + inCache, + inAggregator ); + } + + public void handleEvent( final Messenger inMessenger ) + { + mTransaction.execute(); + setComplete(); + } + + public synchronized void waitForCompletion() + { + while ( ! isComplete() ) + { + try + { + wait( sTimeout ); + } + catch( InterruptedException theException ) + {} + } + } + + private boolean isComplete() + { + synchronized( mCompleteLock ) + { + return mComplete; + } + } + + private void setComplete() + { + synchronized( mCompleteLock ) + { + mComplete = true; + } + } +} diff --git a/src/com/sun/apoc/daemon/apocd/Client.java b/src/com/sun/apoc/daemon/apocd/Client.java new file mode 100644 index 0000000..ff67959 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/Client.java @@ -0,0 +1,148 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transport.*; +import java.util.*; + +public class Client +{ + private final ClientChannel mChannel; + private final HashMap mSessions = new HashMap( 1 ); // norm is 1 session + private final HashSet mSessionListeners = new HashSet( 1 ); + + public Client( final ClientChannel inChannel ) + { + mChannel = inChannel; + } + + public ClientChannel getClientChannel() { return mChannel; } + + // Changing this from a simple accessor because when change detection + // and session closure occur around the same time, the toArray() call + // below ( originally located in ClientManager ) can get confused. + public Object[] getSessions() + { + synchronized( mSessions ) + { + return mSessions.values().toArray(); + } + } + + public Session getSession( final String inSessionId ) + { + synchronized( mSessions ) + { + return inSessionId != null ? + ( Session )mSessions.get( inSessionId ): + null; + } + } + + public void addSession( final Session inSession ) + { + synchronized( mSessions ) + { + mSessions.put( inSession.getSessionId(), inSession ); + } + notifySessionCreated( inSession ); + } + + public void addSessionListener( final SessionListener inSessionListener ) + { + synchronized( mSessionListeners ) + { + mSessionListeners.add( inSessionListener ); + } + } + + public void closeSession( final Session inSession ) + { + synchronized( mSessions ) + { + mSessions.remove( inSession.getSessionId() ); + } + inSession.close(); + notifySessionDestroyed( inSession ); + } + + synchronized public void close() + { + final Iterator theIterator = mSessions.keySet().iterator(); + while ( theIterator.hasNext() ) + { + final Session theSession = + ( Session )mSessions.get( theIterator.next() ); + theSession.close(); + notifySessionDestroyed( theSession ); + } + mSessions.clear(); + } + + public void removeSessionListener( final SessionListener inSessionListener ) + { + synchronized( mSessionListeners ) + { + mSessionListeners.remove( inSessionListener ); + } + } + + private void notifySessionCreated( final Session inSession ) + { + synchronized( mSessionListeners ) + { + final Iterator theIterator = mSessionListeners.iterator(); + while ( theIterator.hasNext() ) + { + ( ( SessionListener )theIterator.next() ) + .onSessionCreate( inSession ); + } + } + } + + private void notifySessionDestroyed( final Session inSession ) + { + synchronized( mSessionListeners ) + { + final Iterator theIterator = mSessionListeners.iterator(); + while ( theIterator.hasNext() ) + { + ( ( SessionListener )theIterator.next() ) + .onSessionDestroy( inSession ); + } + } + } +} diff --git a/src/com/sun/apoc/daemon/apocd/ClientEventHandler.java b/src/com/sun/apoc/daemon/apocd/ClientEventHandler.java new file mode 100644 index 0000000..9df1cba --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/ClientEventHandler.java @@ -0,0 +1,79 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transaction.*; + +import java.io.*; + +class ClientEventHandler implements EventHandler +{ + private final Client mClient; + + ClientEventHandler( final Client inClient) + { + mClient = inClient; + } + + public void handleEvent( final Messenger inMessenger ) + { + try + { + inMessenger.setClientChannel( mClient.getClientChannel() ); + final Transaction theTransaction = + TransactionFactory + .getInstance() + .createTransaction( + mClient, + inMessenger.receiveRequest() ); + inMessenger.sendResponse( theTransaction.execute() ); + } + catch( APOCException theException ) + { + final Throwable theThrowable = theException.getCause(); + if ( theThrowable == null || !(theThrowable instanceof IOException)) + { + APOCLogger.throwing( "ClientEventHandler", + "handleEvent", + theException ); + inMessenger.sendResponse( + MessageFactory.createResponse( + APOCSymbols.sSymRespInvalidRequest, null, null ) ); + } + } + } +} diff --git a/src/com/sun/apoc/daemon/apocd/ClientManager.java b/src/com/sun/apoc/daemon/apocd/ClientManager.java new file mode 100644 index 0000000..061e184 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/ClientManager.java @@ -0,0 +1,311 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.localdatabase.*; +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transaction.*; +import com.sun.apoc.daemon.transport.*; + +import java.util.*; + +public class ClientManager implements ClientChannelEventListener, + ConfigEventListener, + SessionListener +{ + private final HashMap mClients = + new HashMap( DaemonConfig.getIntProperty( + DaemonConfig.sMaxClientConnections ) ); + private final EventQueue mPendingEvents = + new EventQueue(); + private final EventWorkerThreadPool mThreadPool = + new EventWorkerThreadPool( + mPendingEvents, + DaemonConfig.getIntProperty( DaemonConfig.sMaxClientThreads ) ); + private final DaemonTimerTask mChangeDetector = + new DaemonTimerTask( new ChangeDetector( this ) ); + private int mSessionCount = 0; + + public ClientManager( final ChannelManager inChannelManager ) + throws APOCException + { + inChannelManager.addClientChannelEventListener( this ); + DaemonConfig.addConfigEventListener( this ); + APOCLogger.fine( "Clmr001" ); + } + + public void changeDetect() + { + new ChangeDetector( this ).run(); + } + + public void onPending( final ClientChannel inClientChannel ) + { + putEventHandler( + new ClientEventHandler( getClient( inClientChannel)) ); + } + + public void onClosed( final ClientChannel inClientChannel ) + { + synchronized( mClients ) + { + final Client theClient = + ( Client )mClients.remove( inClientChannel ); + if ( theClient != null ) + { + theClient.close(); + APOCLogger.finer( "Clmr002" ); + } + } + } + + public void onConfigEvent() + { + startChangeDetectionTimer(); + + mThreadPool.resizePool( + DaemonConfig.getIntProperty( + DaemonConfig.sMaxClientThreads ) ); + } + + /* Warning: putting this here because we need access to the EventQueue. + * This Queue should be separated from this class in future. + */ + public void onGarbageCollect() + { + try + { + Object[] theDatabases = + LocalDatabaseFactory.getInstance().getDatabases(); + if ( theDatabases != null ) + { + for ( int theIndex = 0; + theIndex < theDatabases.length; + ++ theIndex ) + { + putEventHandler( + new GarbageCollectEventHandler( + ( Database )theDatabases[ theIndex ] ) ); + } + } + } + catch( Exception theException ) + { + APOCLogger.throwing( "ClientManager", + "onGarbageCollect", + theException ); + } + } + + synchronized public void onSessionCreate( final Session inSession ) + { + mSessionCount ++; + doInitialChangeDetect( inSession ); + } + + synchronized public void onSessionDestroy( final Session inSession ) + { + mSessionCount --; + stopChangeDetectionTimer(); + } + + public void terminate() + { + mThreadPool.terminate(); + APOCLogger.fine( "Clmr007" ); + } + + private void doInitialChangeDetect( final Session inSession ) + { + try + { + Cache [] theCaches = inSession.getCaches() ; + ArrayList theOutOfDateCaches = new ArrayList() ; + + for (int i = 0 ; i < theCaches.length ; ++ i) + { + if (theCaches [i].isOutOfDate()) + { + theOutOfDateCaches.add(theCaches [i]) ; + } + } + final DaemonTimerTask theTask = + new DaemonTimerTask( + new ChangeDetector( + this, + (Cache []) theOutOfDateCaches.toArray( + new Cache [0])), + true) ; + + theTask.setPeriod( + DaemonConfig.getIntProperty( + DaemonConfig.sInitialChangeDetectionDelay) * + 1000) ; + startChangeDetectionTimer() ; + } + catch( Exception theException ) + {} + } + + private Client getClient( final ClientChannel inClientChannel ) + { + synchronized( mClients ) + { + Client theClient = ( Client )mClients.get( inClientChannel ); + if ( theClient == null ) + { + theClient = new Client( inClientChannel ); + theClient.addSessionListener( this ); + mClients.put( inClientChannel, theClient ); + APOCLogger.finer( "Clmr005" ); + } + return theClient; + } + } + + private boolean putEventHandler( final EventHandler inEventHandler ) + { + boolean theRC = true; + mPendingEvents.put( inEventHandler ); + try + { + mThreadPool.ensureThread(); + } + catch( APOCException theException ) + { + theRC = false; + APOCLogger.throwing( "ChangeDetector", "run", theException ); + } + return theRC; + } + + private void startChangeDetectionTimer() + { + if ( mSessionCount > 0 ) + { + final float theMinuteDelay = + DaemonConfig.getFloatProperty( + DaemonConfig.sChangeDetectionInterval ); + if ( mChangeDetector.setPeriod( ( long )(60000 * theMinuteDelay) ) ) + { + if ( mChangeDetector.getPeriod() > 0 ) + { + APOCLogger.fine( "Clmr004", + String.valueOf( theMinuteDelay ) ); + } + else + { + APOCLogger.fine( "Clmr006" ); + } + } + } + } + + private void stopChangeDetectionTimer() + { + if ( mSessionCount < 1 ) + { + mChangeDetector.cancel(); + } + } + + static class ChangeDetector implements Runnable + { + private ClientManager mManager; + private Cache [] mCaches = null; + boolean mCheckCaches = false ; + + public ChangeDetector( final ClientManager inManager, + final Cache [] inCaches ) + { + mManager = inManager; + mCaches = inCaches ; + mCheckCaches = true ; + } + + public ChangeDetector( final ClientManager inManager ) + { + mManager = inManager; + } + + public void run() + { + Cache [] theCaches = mCaches ; + + if ( theCaches == null ) + { + synchronized( mManager.mClients ) + { + if ( ! mManager.mClients.isEmpty() ) + { + theCaches = CacheFactory.getInstance().getCaches(); + } + } + } + if ( theCaches != null ) + { + final ArrayList theHandlers = new ArrayList(); + final UpdateAggregator theAggregator = new UpdateAggregator() ; + + for ( int theIndex = 0; + theIndex < theCaches.length; + ++ theIndex ) + { + if (!mCheckCaches || theCaches [theIndex].isOutOfDate()) { + final ChangeDetectEventHandler theHandler = + new ChangeDetectEventHandler( + mManager, theCaches[ theIndex ], + theAggregator ); + if ( mManager.putEventHandler( theHandler ) ) + { + theHandlers.add( theHandler ); + } + } + } + int theHandlerCount = theHandlers.size(); + for ( int theIndex = 0; + theIndex < theHandlerCount; + ++ theIndex ) + { + ( ( ChangeDetectEventHandler )theHandlers + .get( theIndex ) ).waitForCompletion(); + } + theAggregator.sendNotifications() ; + mManager.startChangeDetectionTimer(); + } + } + } +} diff --git a/src/com/sun/apoc/daemon/apocd/Daemon.java b/src/com/sun/apoc/daemon/apocd/Daemon.java new file mode 100644 index 0000000..8eddcaa --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/Daemon.java @@ -0,0 +1,209 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.admin.*; +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.localdatabase.*; +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transport.*; + +import java.io.*; +import java.util.*; + +public class Daemon implements ConfigEventListener, AdminOpHandler +{ + private ChannelManager mChannelManager; + private ClientManager mClientManager; + private AdminManager mAdminManager; + private final DaemonTimerTask mGarbageCollector = + new DaemonTimerTask( new GarbageCollector() ); + + public static void main( final String[] inArgs ) + { + try + { + new Daemon( inArgs ).run(); + } + catch( Exception theException ) + { + APOCLogger.throwing( "Daemon", "main", theException ); + } + } + + public Daemon( final String[] inArgs ) + throws APOCException, IOException, InterruptedException + { + if ( inArgs.length != 2 ) + { + usage(); + System.exit( 1 ); + } + init( inArgs ); + } + + public void onConfigEvent() + { + startGarbageCollectionTimer(); + DaemonConfig.log(); + } + + public int onStop() + { + mChannelManager.terminate(); + return 0; + } + + public int onStatus() + { + return 0; + } + + public int onReload() + { + int theRC; + try + { + DaemonConfig.reload(); + DaemonConfig.log(); + theRC = 0; + } + catch( Exception theException ) + { + APOCLogger.throwing( "Daemon", "onReload", theException ); + theRC = 1; + } + return theRC; + } + + public int onChangeDetect() + { + mClientManager.changeDetect(); + return 0; + } + + public void run() + throws APOCException, InterruptedException + { + APOCLogger.info( "Dmon001" ); + + startGarbageCollectionTimer(); + mChannelManager = new ChannelManager(); + mClientManager = new ClientManager( mChannelManager ); + verifyConfig(); + mChannelManager.start(); + DaemonConfig.addConfigEventListener( this ); + mAdminManager = new AdminManager( this ); + mAdminManager.start(); + mChannelManager.join(); + + mClientManager.terminate(); + mChannelManager.closeChannels(); + APOCLogger.info( "Dmon002" ); + } + + private void usage() + { + System.err.println( "Usage: apocd <daemon installation directory>" ); + } + + private void init( final String[] inArgs ) + throws IOException, APOCException + { + System.loadLibrary( "FileAccess" ); + initConfig( inArgs ); + initAuthDir(); + } + + private void initAuthDir() + throws APOCException + { + if ( ! APOCAuthenticator.sAuthDir.exists() ) + { + if ( ! APOCAuthenticator.sAuthDir.mkdirs() ) + { + throw new APOCException(); + } + } + else + { + if ( ! APOCAuthenticator.sAuthDir.isDirectory() ) + { + throw new APOCException(); + } + } + FileAccess.chmod( APOCAuthenticator.sAuthDir.getAbsolutePath(), 0755 ); + FileAccess.chmod( APOCAuthenticator.sAuthDir.getParent(), 0755 ); + } + + private void initConfig( final String[] inArgs ) + throws IOException, APOCException + { + DaemonConfig.init( inArgs ); + DaemonConfig.log(); + } + + private void startGarbageCollectionTimer() + { + final long theMinuteDelay = + DaemonConfig.getIntProperty( + DaemonConfig.sGarbageCollectionInterval ); + if ( mGarbageCollector.setPeriod( 60000 * theMinuteDelay ) ) + { + if ( mGarbageCollector.getPeriod() > 0 ) + { + APOCLogger.fine( "Dmon003", String.valueOf( theMinuteDelay ) ); + } + else + { + APOCLogger.fine( "Dmon004" ); + } + } + } + + private void verifyConfig() + throws APOCException + { + LocalDatabaseFactory.getInstance(); + } + + class GarbageCollector implements Runnable + { + public void run() + { + mClientManager.onGarbageCollect(); + } + } +} diff --git a/src/com/sun/apoc/daemon/apocd/EventHandler.java b/src/com/sun/apoc/daemon/apocd/EventHandler.java new file mode 100644 index 0000000..a1550a4 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/EventHandler.java @@ -0,0 +1,42 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.messaging.*; + +interface EventHandler +{ + public void handleEvent( final Messenger inMessenger ); +} diff --git a/src/com/sun/apoc/daemon/apocd/EventQueue.java b/src/com/sun/apoc/daemon/apocd/EventQueue.java new file mode 100644 index 0000000..b913754 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/EventQueue.java @@ -0,0 +1,100 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import java.util.*; + +class EventQueue +{ + private final List mList = new ArrayList(); + static private final long sTimeout = 100; + + public void put( final EventHandler inEventHandler ) + { + add( inEventHandler ); + synchronized( mList ) + { + mList.notify(); + } + } + + public EventHandler get() + { + EventHandler theEventHandler = remove(); + if ( theEventHandler == null ) + { + try + { + synchronized( mList ) + { + mList.wait( sTimeout ); + } + } + catch ( InterruptedException theException ) + {} + theEventHandler = remove(); + } + return theEventHandler; + } + + public void releaseWaitingThreads() + { + synchronized( mList ) + { + mList.notifyAll(); + } + } + + private void add( final EventHandler inEventHandler ) + { + synchronized( mList ) + { + mList.add( inEventHandler ); + } + } + + private EventHandler remove() + { + EventHandler theEventHandler = null; + synchronized( mList ) + { + if ( ! mList.isEmpty() ) + { + theEventHandler = ( EventHandler )mList.remove( 0 ); + } + } + return theEventHandler; + } +} diff --git a/src/com/sun/apoc/daemon/apocd/EventWorkerThread.java b/src/com/sun/apoc/daemon/apocd/EventWorkerThread.java new file mode 100644 index 0000000..bfef9f7 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/EventWorkerThread.java @@ -0,0 +1,122 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transaction.*; + +import java.io.*; +import java.util.*; + +class EventWorkerThread extends Thread +{ + private final EventQueue mQueue; + private final Messenger mMessenger = new Messenger(); + private final Object mStateLock = new Object(); + private long mTimestamp = System.currentTimeMillis(); + private int mState = sStateIdle; + + private static int sStateIdle = 0; + private static int sStateBusy = 1; + private static int sStateTerminating = 2; + private static long sIdleTimeout = + ( long )DaemonConfig. + getIntProperty( DaemonConfig.sThreadTimeToLive ) * 60000; + + public EventWorkerThread( final EventQueue inQueue ) + throws APOCException + { + setName( "EventWorker" ); + setDaemon( true ); + mQueue = inQueue; + } + + public boolean isAvailable() + { + return privgetState() == sStateIdle; + } + + public void run() + { + while ( ! ( privgetState() == sStateTerminating ) ) + { + final EventHandler theEventHandler = mQueue.get(); + if ( theEventHandler != null ) + { + setState( sStateBusy ); + theEventHandler.handleEvent( mMessenger ); + setState( sStateIdle ); + } + } + } + + public boolean terminate( boolean inIfIdle ) + { + boolean isTerminated = true; + if ( ! inIfIdle ) + { + setState( sStateTerminating ); + } + else + { + long theIdleTime = + privgetState() == sStateIdle ? + System.currentTimeMillis() - mTimestamp : 0; + if ( theIdleTime > sIdleTimeout ) + { + setState( sStateTerminating ); + } + else + { + isTerminated = false; + } + } + return isTerminated; + } + + private synchronized int privgetState() { return mState; } + + private synchronized void setState( int inState ) + { + if ( mState != sStateTerminating ) + { + mTimestamp = inState == sStateTerminating ? + 0 : System.currentTimeMillis(); + mState = inState; + } + } +} diff --git a/src/com/sun/apoc/daemon/apocd/EventWorkerThreadPool.java b/src/com/sun/apoc/daemon/apocd/EventWorkerThreadPool.java new file mode 100644 index 0000000..191015b --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/EventWorkerThreadPool.java @@ -0,0 +1,191 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transaction.*; + +import java.io.*; +import java.util.*; + +class EventWorkerThreadPool +{ + private final EventQueue mQueue; + private final ArrayList mPool = new ArrayList(); + private int mMaxPoolSize; + private int mPoolSize = 0; + private final DaemonTimerTask mIdleDetector = + new DaemonTimerTask( new IdleDetector() ); + + private static long sIdleDetectorPeriod = + ( long )DaemonConfig. + getIntProperty( DaemonConfig.sIdleThreadDetectionInterval ) * 60000; + + public EventWorkerThreadPool( final EventQueue inQueue, + final int inPoolSize ) + throws APOCException + { + mQueue = inQueue; + mMaxPoolSize = inPoolSize; + mIdleDetector.setPeriod( sIdleDetectorPeriod ); + } + + synchronized public void ensureThread() + throws APOCException + { + if ( mPoolSize < mMaxPoolSize && ! haveIdleThread() ) + { + final EventWorkerThread theThread = new EventWorkerThread( mQueue ); + mPool.add( theThread ); + mPoolSize ++; + theThread.start(); + } + } + + synchronized public void resizePool( int inPoolSize ) + { + inPoolSize = inPoolSize > 0 ? inPoolSize : 1; + if ( inPoolSize != mMaxPoolSize ) + { + if ( inPoolSize > mMaxPoolSize ) + { + mMaxPoolSize = inPoolSize; + } + else if ( inPoolSize < mMaxPoolSize ) + { + shrinkPool( inPoolSize ); + } + } + } + + public synchronized void terminate() + { + terminateThreads(); + waitForLiveThreads(); + } + + private boolean haveIdleThread() + { + boolean haveIdleThread = false; + for ( int theIndex = 0; theIndex < mPoolSize; theIndex ++ ) + { + if ( ( ( EventWorkerThread )mPool.get( theIndex ) ).isAvailable() ) + { + haveIdleThread = true; + break; + } + } + return haveIdleThread; + } + + private boolean haveLiveThread() + { + boolean haveLiveThread = false; + for ( int theIndex = 0; theIndex < mPoolSize; theIndex ++ ) + { + if ( ( ( EventWorkerThread )mPool.get( theIndex ) ).isAlive() ) + { + haveLiveThread = true; + break; + } + } + return haveLiveThread; + } + + private void shrinkPool( int inPoolSize ) + { + for ( int theIndex = mPoolSize; theIndex > inPoolSize; theIndex -- ) + { + ( ( EventWorkerThread )( mPool.remove( 0 ) ) ).terminate( false ); + } + mPool.trimToSize(); + mMaxPoolSize = inPoolSize; + } + + private void terminateThreads() + { + terminateThreads( false ); + } + + private synchronized void terminateThreads( boolean inIdleOnly ) + { + int theTerminatedCount = 0; + for ( int theIndex = mPoolSize - 1; theIndex >= 0; theIndex -- ) + { + EventWorkerThread theThread = + ( EventWorkerThread )mPool.get( theIndex ); + if ( theThread.terminate( inIdleOnly ) ) + { + mPool.remove( theIndex ); + theTerminatedCount ++; + } + } + if ( theTerminatedCount > 0 ) + { + mQueue.releaseWaitingThreads(); + mPoolSize -= theTerminatedCount; + } + } + + private void waitForLiveThreads() + { + for ( int theIndex = 0; theIndex < 5; theIndex ++ ) + { + if ( haveLiveThread() ) + { + try + { + wait( 1000 ); + } + catch( Exception theException ){} + } + else + { + break; + } + } + } + + class IdleDetector implements Runnable + { + public void run() + { + terminateThreads( true ); + } + } +} + diff --git a/src/com/sun/apoc/daemon/apocd/GarbageCollectEventHandler.java b/src/com/sun/apoc/daemon/apocd/GarbageCollectEventHandler.java new file mode 100644 index 0000000..8c09ba5 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/GarbageCollectEventHandler.java @@ -0,0 +1,56 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.localdatabase.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.transaction.*; + +class GarbageCollectEventHandler implements EventHandler +{ + private final GarbageCollectTransaction mTransaction; + + GarbageCollectEventHandler( final Database inDatabase ) + { + mTransaction = TransactionFactory + .getInstance() + .createGarbageCollectTransaction( inDatabase ); + } + + public void handleEvent( final Messenger inMessenger ) + { + mTransaction.execute(); + } +} diff --git a/src/com/sun/apoc/daemon/apocd/PolicyBackend.java b/src/com/sun/apoc/daemon/apocd/PolicyBackend.java new file mode 100644 index 0000000..66e8401 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/PolicyBackend.java @@ -0,0 +1,366 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.spi.*; +import com.sun.apoc.spi.entities.*; +import com.sun.apoc.spi.environment.*; +import com.sun.apoc.spi.policies.*; +import com.sun.apoc.spi.profiles.*; + +import java.io.*; +import java.net.*; +import java.util.*; +import javax.security.auth.callback.*; + +public class PolicyBackend +{ + protected static final PolicyInfo[] sPolicyInfoModel= new PolicyInfo[ 0 ]; + protected static final Policy[] sPolicyModel = new Policy[ 0 ]; + protected static final Profile[] sProfileModel = new Profile[ 0 ]; + + protected Name mName; + protected PolicyManager mPolicyMgr; + protected Entity mEntity; + protected Profile[] mProfiles; + private int mRefCount = 0; + private Object mLock = new Object(); + private boolean mProfilesInitialised = false; + + public synchronized int acquire() { return ++ mRefCount; } + public synchronized int release() { return -- mRefCount; } + + public PolicyBackend( final Name inName, + final Properties inProperties ) + throws APOCException + { + mName = inName; + try + { + mPolicyMgr = + PolicyBackendFactory + .getInstance() + .openPolicyMgr( inProperties, mName ); + } + catch( Exception theException ) + { + throw new APOCException( theException ); + } + } + + public void close() + { + PolicyBackendFactory.getInstance().closePolicyMgr( mPolicyMgr ); + } + + public String toString() { return mName.toString() ; } + + public synchronized HashSet getComponentList() + throws APOCException + { + try + { + initProfiles(); + HashSet theComponentList = null; + if ( mProfiles != null && mProfiles.length > 0 ) + { + theComponentList = new HashSet(); + for ( int theIndex = 0; + theIndex < mProfiles.length; + theIndex ++ ) + { + Iterator theIterator = mProfiles[ theIndex ].getPolicies(); + if ( theIterator != null ) + { + while ( theIterator.hasNext() ) + { + Policy policy = (Policy) theIterator.next() ; + + theComponentList.add(policy.getId()) ; + } + } + } + } + return theComponentList; + } + catch( SPIException theException ) + { + throw new APOCException( theException ); + } + } + + public synchronized PolicyInfo[][] getLayeredPolicies( + final Set inComponentList, + boolean inTimeStampOnly ) + throws APOCException + { + try + { + initProfiles(); + PolicyInfo[][] thePolicies = null; + + if ( inComponentList != null && + mProfiles != null && + mProfiles.length > 0 ) + { + int theIndex; + int theComponentCount = inComponentList.size(); + if ( theComponentCount > 0 ) + { + final Hashtable theTable = + new Hashtable( theComponentCount ); + final ArrayList theComponentList = + new ArrayList( inComponentList ); + for ( theIndex = 0; + theIndex < theComponentCount; + ++ theIndex ) + { + theTable.put( theComponentList.get( theIndex ), + new ArrayList() ); + } + for ( theIndex = 0; + theIndex < mProfiles.length; + ++ theIndex ) + { + final Iterator theIterator = + inTimeStampOnly ? + mProfiles[ theIndex ].getPolicyInfos( + inComponentList.iterator() ) : + mProfiles[ theIndex ].getPolicies( + inComponentList.iterator() ); + while ( theIterator.hasNext() ) + { + final PolicyInfo thePolicy = + ( PolicyInfo )theIterator.next(); + ( ( ArrayList )theTable.get( thePolicy.getId() ) ) + .add( thePolicy ); + } + } + thePolicies = inTimeStampOnly ? + new PolicyInfo[ theComponentCount ][] : + new Policy[ theComponentCount ][]; + for ( theIndex = 0; + theIndex < theComponentCount; + ++ theIndex ) + { + ArrayList theList = + ( ArrayList )theTable.get( + theComponentList.get( theIndex ) ); + theList.trimToSize(); + if ( theList.size() > 0 ) + { + thePolicies[ theIndex ] = + inTimeStampOnly ? + ( PolicyInfo[] )theList. + toArray( sPolicyInfoModel ) : + ( Policy[] )theList.toArray( sPolicyModel ); + } + else + { + thePolicies[ theIndex ] = null; + } + } + } + } + return thePolicies; + } + catch( SPIException theException ) + { + throw new APOCException( theException ); + } + } + + public synchronized Policy[] getLayeredPolicies( + final String inComponentName, + boolean inTimeStampOnly ) + throws APOCException + { + try + { + Policy[] thePolicies = null; + + if ( inComponentName != null ) + { + if ( mProfiles != null && mProfiles.length > 0 ) + { + ArrayList theList = new ArrayList(); + for ( int theIndex = 0; + theIndex < mProfiles.length; + ++ theIndex ) + { + Policy thePolicy = mProfiles[ theIndex ]. + getPolicy( inComponentName ); + if ( thePolicy != null ) + { + theList.add( thePolicy ); + } + } + theList.trimToSize(); + if ( theList.size() > 0 ) + { + thePolicies = + ( Policy[] )theList.toArray( sPolicyModel ); + } + } + } + return thePolicies; + } + catch( SPIException theException ) + { + throw new APOCException( theException ); + } + } + + public Name getName() { return mName; } + + public synchronized void refreshProfiles() + throws SPIException + { + if ( mName.isLocal() ) + { + refreshLocalProfiles(); + } + else + { + refreshGlobalProfiles(); + } + } + + private Entity findEntity() + { + Entity theEntity = null; + + try + { + final Node theRoot = + ( Node ) mPolicyMgr.getRootEntity( mName.getEntityType() ); + final Iterator theIterator = + theRoot.findEntities( mName.getEntityName(), true ); + if ( theIterator != null && theIterator.hasNext() ) + { + theEntity = ( Entity ) theIterator.next(); + } + } + catch ( Exception theException ){} + return theEntity; + } + + private void initProfiles() + throws SPIException + { + // There are two special cases to handle here + // 1. Creation of a first ever session for a user. + // In this case, we need to write the remote component list to bdb + // and we need profiles to figure out the list + // 2. Reading a component for the first time + // If a component isn't yet in bdb, we'll need the profiles to + // get the appropriate layers + synchronized( mLock ) + { + if ( ! mProfilesInitialised ) + { + refreshProfiles(); + mProfilesInitialised = true; + } + } + } + + private void refreshGlobalProfiles() + throws SPIException + { + mProfiles = null; + if ( mEntity == null ) + { + mEntity = findEntity(); + } + if ( mEntity != null ) + { + final Iterator theIterator = mEntity.getLayeredProfiles(); + if ( theIterator != null ) + { + final ArrayList theProfiles = new ArrayList(); + while ( theIterator.hasNext() ) + { + theProfiles.add( theIterator.next() ); + } + if ( mEntity instanceof User ) + { + final Profile theProfile = + ( ( User ) mEntity ).getUserProfile(); + if ( theProfile != null ) + { + theProfiles.add( theProfile ); + } + } + if ( theProfiles.size() > 0 ) + { + mProfiles = + ( Profile[] )theProfiles.toArray( sProfileModel ); + } + } + } + } + + private void refreshLocalProfiles() + throws SPIException + { + mProfiles = null; + final ProfileProvider theProvider = + mPolicyMgr.getProfileProvider( mName.getEntityType() ); + final Iterator theIterator = theProvider.getAllProfiles(); + + if ( theIterator != null ) + { + final ArrayList theProfiles = new ArrayList(); + while ( theIterator.hasNext() ) + { + final Profile theProfile = ( Profile )theIterator.next(); + final Applicability theApp = theProfile.getApplicability(); + if ( theApp.equals( Applicability.ALL ) || + theApp.equals( mName.getEntityType() ) ) + { + theProfiles.add( theProfile ); + } + } + if ( theProfiles.size() > 0 ) + { + mProfiles = + ( Profile[] )theProfiles.toArray( sProfileModel ); + } + } + } +} diff --git a/src/com/sun/apoc/daemon/apocd/PolicyBackendFactory.java b/src/com/sun/apoc/daemon/apocd/PolicyBackendFactory.java new file mode 100644 index 0000000..35dddf9 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/PolicyBackendFactory.java @@ -0,0 +1,235 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.misc.*; + +import com.sun.apoc.spi.*; +import com.sun.apoc.spi.entities.*; +import com.sun.apoc.spi.environment.*; +import com.sun.apoc.spi.profiles.*; + +import java.io.*; +import java.util.*; +import javax.security.auth.callback.*; + +public class PolicyBackendFactory +{ + public static int sTypeHost = 0; + public static int sTypeUser = 1; + public static final String sLocalHostName = "localHost"; + public static final String sLocalUserName = "localUsers"; + public static final Properties sLocalProperties= new Properties(); + + private HashMap mPolicyBackends = new HashMap(); + private HashMap mPolicyMgrs = new HashMap(); + private static PolicyBackendFactory sInstance; + private static final String sLocalPolicyDir = + new StringBuffer( "file://" ) + .append( DaemonConfig.getStringProperty( DaemonConfig.sDataDir ) ) + .append( "/" ) + .append( "Policies/" ) + .toString(); + + static + { + sLocalProperties.setProperty( + EnvironmentConstants.URL_KEY, sLocalPolicyDir ); + String sourcesList = + (String) ((Properties) DaemonConfig.getLocalConfig()).get( + EnvironmentConstants.SOURCES_KEY) ; + + if (sourcesList != null) { + sLocalProperties.setProperty(EnvironmentConstants.SOURCES_KEY, + sourcesList); + } + try + { + new File ( + new java.net.URI( sLocalPolicyDir + "/assignments" ) ).mkdirs(); + new File ( + new java.net.URI( sLocalPolicyDir + "/profiles" ) ).mkdirs(); + new File ( + new java.net.URI( + sLocalPolicyDir + "/entities.txt" ) ).createNewFile(); + } + catch( Exception theException ) + { + APOCLogger.throwing( "PolicyBackendFactory", "init", theException ); + } + } + + public void closePolicyBackend( final PolicyBackend inPolicyBackend ) + { + synchronized( mPolicyBackends ) + { + if ( inPolicyBackend.release() == 0 ) + { + inPolicyBackend.close(); + mPolicyBackends.remove( + createPolicyBackendKey( inPolicyBackend.getName() ) ); + } + } + } + + public void closePolicyMgr( final PolicyManager inPolicyMgr ) + { + synchronized( mPolicyMgrs ) + { + final RefCountedPolicyMgr thePolicyMgr = + ( RefCountedPolicyMgr )inPolicyMgr; + if ( thePolicyMgr.release() == 0 ) + { + try + { + thePolicyMgr.close(); + } + catch( SPIException theException ){} + mPolicyMgrs.remove( + createPolicyMgrKey( thePolicyMgr.mName ) ); + } + } + } + + public static PolicyBackendFactory getInstance() + { + if ( sInstance == null ) + { + sInstance = new PolicyBackendFactory(); + } + return sInstance; + } + + public PolicyBackend openPolicyBackend( + final Name inName, + final CallbackHandler inHandler ) + throws APOCException + { + final String theKey = createPolicyBackendKey( inName ); + PolicyBackend theBackend = null; + synchronized( mPolicyBackends ) + { + theBackend = ( PolicyBackend )mPolicyBackends.get( theKey ); + if ( theBackend == null ) + { + final Properties theProperties = inName.isLocal() ? + sLocalProperties : + ( Properties )( + ( Properties )DaemonConfig.getLocalConfig() ).clone(); + if ( inHandler != null ) + { + theProperties.put( EnvironmentConstants.LDAP_AUTH_CBH, + inHandler ); + } + theBackend = new PolicyBackend( inName, theProperties ); + mPolicyBackends.put( theKey, theBackend ); + } + if ( theBackend != null ) + { + theBackend.acquire(); + } + } + return theBackend; + } + + public static String [] getSources() + { + return EnvironmentMgr.getSources( DaemonConfig.getLocalConfig() ); + } + + public PolicyManager openPolicyMgr( final Properties inProperties, + final Name inName ) + throws APOCException + { + final String theKey = createPolicyMgrKey( inName ); + RefCountedPolicyMgr thePolicyMgr = null; + synchronized( mPolicyMgrs ) + { + try + { + thePolicyMgr = + ( RefCountedPolicyMgr )mPolicyMgrs.get( theKey ); + if ( thePolicyMgr == null ) + { + thePolicyMgr = + new RefCountedPolicyMgr( + inName, + inProperties ); + mPolicyMgrs.put( theKey, thePolicyMgr ); + } + if ( thePolicyMgr != null ) + { + thePolicyMgr.acquire(); + } + } + catch( Exception theException ) + { + throw new APOCException( theException ); + } + } + return thePolicyMgr; + } + + private PolicyBackendFactory() + { + } + + private String createPolicyBackendKey( final Name inName ) + { + return inName.toString(); + } + + private String createPolicyMgrKey( final Name inName ) + { + return inName.getUserName() + Name.sSep + inName.getLocation(); + } + + class RefCountedPolicyMgr extends PolicyManager + { + private int mRefCount = 0; + private Name mName; + + RefCountedPolicyMgr( final Name inName, + final Hashtable inProperties ) throws SPIException + { + super( inProperties ); + mName = inName; + } + + int acquire() { return ++ mRefCount; } + int release() { return -- mRefCount; } + } +} diff --git a/src/com/sun/apoc/daemon/apocd/SaslAuthCallbackHandler.java b/src/com/sun/apoc/daemon/apocd/SaslAuthCallbackHandler.java new file mode 100644 index 0000000..f594b25 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/SaslAuthCallbackHandler.java @@ -0,0 +1,221 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transport.*; + +import com.sun.apoc.spi.ldap.authentication.*; + +import java.io.IOException; +import java.nio.*; +import javax.security.auth.callback.*; + +class SaslAuthCallbackHandler implements CallbackHandler +{ + private Messenger mMessenger = new Messenger(); + private ClientChannel mChannel; + private ByteBuffer mBuffer; + private boolean mReconnectMode = false; + + SaslAuthCallbackHandler( final Client inClient ) + throws APOCException + { + mChannel = inClient.getClientChannel(); + mMessenger.setClientChannel( mChannel ); + } + + public void handle( Callback[] inCallbacks ) + throws IOException, UnsupportedCallbackException + { + final LdapSaslGSSAPICallback theCallback = + ( LdapSaslGSSAPICallback )inCallbacks[ 0 ]; + if ( mBuffer == null ) + { + createTokens( theCallback ); + } + theCallback.setResponse( getToken() ); + } + + public void setReconnectMode() { mReconnectMode = true; } + + private void createTokens( final LdapSaslGSSAPICallback inCallback ) + { + try + { + if ( mReconnectMode ) + { + mChannel.registerForSelection( false ); + } + mMessenger.sendResponse( + MessageFactory.createResponse( + APOCSymbols.sSymRespSuccessContinueSASLAuth, + null, + new StringBuffer( inCallback.getServiceName() ) + .append( "/" ) + .append( inCallback.getHostname() ) + .toString() ), + false ); + final CredentialsProviderMessage theMessage = + ( CredentialsProviderMessage )mMessenger.receiveRequest( + ! mReconnectMode ); + + if ( theMessage != null ) + { + final String theCreds = theMessage.getCredentials(); + if ( theCreds != null ) + { + mBuffer = + ByteBuffer.wrap( + base64ToByteArray( theCreds.toCharArray() ) ); + } + } + if ( mReconnectMode ) + { + mMessenger.sendResponse( + MessageFactory.createResponse( + APOCSymbols.sSymRespSuccess, null, null ), + true ); + } + } + catch( Exception theException ) + { + APOCLogger.throwing( "SaslAuthCallbackHandler", + "createTokens", + theException ); + } + } + + private byte[] getToken() + { + byte[] theToken = null; + if ( mBuffer != null && mBuffer.hasRemaining() ) + { + int theTokenSize = nextTokenSize(); + if ( theTokenSize > 0 ) + { + theToken = new byte[ theTokenSize ]; + mBuffer = mBuffer.get( theToken ); + } + if ( ! mBuffer.hasRemaining() ) + { + mBuffer = null; + } + } + return theToken; + } + + private int nextTokenSize() + { + int theTokenSize = 0; + try + { + if ( mBuffer.hasRemaining() ) + { + final byte[] theTokenSizeBytes = new byte[ 5 ]; + mBuffer = mBuffer.get( theTokenSizeBytes ); + theTokenSize = + Integer.parseInt( new String( theTokenSizeBytes ) ); + } + } + catch( Exception theException ) + {} + return theTokenSize; + } + + // Code borrowed from java.util.prefs.Base64 + private static final byte base64ToInt[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 + }; + + private byte[] base64ToByteArray(char[] encoded) { + byte[] alphaToInt = base64ToInt; + int encodedLen = encoded.length; + int numGroups = encodedLen/4; + if (4*numGroups != encodedLen) + throw new IllegalArgumentException( + "String length must be a multiple of four."); + int missingBytesInLastGroup = 0; + int numFullGroups = numGroups; + if (encodedLen != 0) { + if (encoded[encodedLen-1] == '=') { + missingBytesInLastGroup++; + numFullGroups--; + } + if (encoded[encodedLen-2] == '=') + missingBytesInLastGroup++; + } + byte[] result = new byte[3*numGroups - missingBytesInLastGroup]; + + // Translate all full groups from base64 to byte array elements + int inCursor = 0, outCursor = 0; + for (int i=0; i<numFullGroups; i++) { + int ch0 = base64toInt(encoded[inCursor++], alphaToInt); + int ch1 = base64toInt(encoded[inCursor++], alphaToInt); + int ch2 = base64toInt(encoded[inCursor++], alphaToInt); + int ch3 = base64toInt(encoded[inCursor++], alphaToInt); + result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4)); + result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2)); + result[outCursor++] = (byte) ((ch2 << 6) | ch3); + } + + // Translate partial group, if present + if (missingBytesInLastGroup != 0) { + int ch0 = base64toInt(encoded[inCursor++], alphaToInt); + int ch1 = base64toInt(encoded[inCursor++], alphaToInt); + result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4)); + + if (missingBytesInLastGroup == 1) { + int ch2 = base64toInt(encoded[inCursor++], alphaToInt); + result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2)); + } + } + return result; + } + + private int base64toInt(char c, byte[] alphaToInt) { + int result = alphaToInt[c]; + if (result < 0) + throw new IllegalArgumentException("Illegal character " + c); + return result; + } +} diff --git a/src/com/sun/apoc/daemon/apocd/Session.java b/src/com/sun/apoc/daemon/apocd/Session.java new file mode 100644 index 0000000..44d2416 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/Session.java @@ -0,0 +1,335 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +import com.sun.apoc.daemon.config.DaemonConfig; +import com.sun.apoc.daemon.localdatabase.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transport.*; + +import com.sun.apoc.spi.entities.*; +import com.sun.apoc.spi.environment.*; + +import java.io.*; +import java.nio.*; +import java.net.*; +import java.util.*; +import java.util.logging.*; + + +public class Session +{ + private Client mClient; + private String mSessionId; + private HashMap mListeners = new HashMap(); + private Cache[] mCaches; + private Object mLock = new Object(); + private Hashtable mEntities = null ; + + private static final String sSep = "."; + private static final Random sRandom = new Random(); + private static int sAuthBufferSize = 20; + private static int sCantLock = 0; + private static int sUnlocked = 1; + private static int sLocked = 2; + private int mState = sUnlocked; + + Session() {} + + public Session( final Client inClient, + final String inUserId, + String inEntityName ) + throws APOCException + { + Hashtable theEntities = new Hashtable(); + + if (inEntityName == null) { inEntityName = inUserId ; } + theEntities.put( EnvironmentConstants.USER_SOURCE, inEntityName ); + initialise( inClient, inUserId, theEntities ); + } + public Session( final Client inClient, + final String inUserId, + final Hashtable inEntities) + throws APOCException + { + initialise( inClient, inUserId, inEntities ); + } + private void initialise( final Client inClient, + final String inUserId, + Hashtable inoutEntities) throws APOCException { + APOCLogger.finer( "Sess001" ); + try + { + authenticate( inClient, inUserId ); + mClient = inClient; + mSessionId = String.valueOf ( sRandom.nextLong() ); + if (!inoutEntities.containsKey(EnvironmentConstants.HOST_SOURCE)) { + String hostName = DaemonConfig.getHostIdentifier() ; + + if (hostName != null) { + inoutEntities.put(EnvironmentConstants.HOST_SOURCE, + hostName) ; + } + } + mEntities = inoutEntities ; + mCaches = CacheFactory + .getInstance() + .openCaches( + inUserId, + mEntities, + this, + new SaslAuthCallbackHandler( mClient ) ); + } + catch( APOCException theException ) + { + close(); + throw theException; + } + APOCLogger.finer( "Sess002", toString( inUserId ) ); + } + + public Cache[] getCaches() { return mCaches; } + public Client getClient() { return mClient; } + public String getSessionId() { return mSessionId; } + + public void addListeners( final Vector inComponentNames, + final String inClientData ) + { + synchronized( mListeners ) + { + for ( int theIndex = 0; + theIndex < inComponentNames.size(); + ++theIndex ) + { + mListeners.put( inComponentNames.elementAt( theIndex ), + inClientData ); + } + } + } + + public void removeListeners( final Vector inComponentNames ) + { + synchronized( mListeners ) + { + for ( int theIndex = 0; + theIndex < inComponentNames.size(); + ++ theIndex ) + { + mListeners.remove( inComponentNames.elementAt( theIndex ) ); + } + } + } + + public void close() + { + synchronized( mLock ) + { + if ( mState == sLocked ) + { + try + { + mLock.wait(); + } + catch( Exception e ) + {} + } + mState = sCantLock; + mLock.notify(); + } + if ( mCaches != null ) + { + CacheFactory.getInstance().closeCaches( mCaches, this ); + mCaches = null; + } + if ( mSessionId != null ) + { + APOCLogger.finer( "Sess003", mSessionId ); + } + } + + public String getListenerClientData( final String inComponentName ) + { + return ( String )mListeners.get( inComponentName ); + } + + public String getListenerComponentName( final String inComponentName ) + { + synchronized( mListeners ) + { + String theComponentName = + mListeners.containsKey( inComponentName ) ? inComponentName : + null; + if ( theComponentName == null ) + { + final StringTokenizer theTokenizer = + new StringTokenizer( inComponentName, sSep ); + final StringBuffer theBuffer = new StringBuffer(); + int theCount = theTokenizer.countTokens(); + for ( int theIndex = 0; theIndex < theCount - 1 ; theIndex ++ ) + { + final String theContainerName = + theBuffer.append( theTokenizer.nextToken() ) + .append( sSep ) + .toString(); + if ( mListeners.containsKey( theContainerName ) ) + { + theComponentName = theContainerName; + break; + } + } + } + return theComponentName; + } + } + + // + // lock() & unlock() are provided to support the case where a + // change detection transaction and a destroy session transaction are + // happening at the same time. lock() will allow a change detection to + // continue using the session until it's complete without fear of the + // session being closed. Once complete, the change detection transaction + // will unlock the session, allowing it to be destroyed. + // + public boolean lock() + { + boolean isLocked = false; + synchronized( mLock ) + { + if ( mState == sUnlocked ) + { + mState = sLocked; + isLocked = true; + } + } + return isLocked; + } + + public void unlock() + { + synchronized( mLock ) + { + mState = sUnlocked; + mLock.notify(); + } + } + + public void sendNotification(UpdateItem aUpdate) { + String component = aUpdate.getComponentName() ; + String listenerComponent = getListenerComponentName(component) ; + + if (listenerComponent == null) { return ; } + int notificationType = -1 ; + StringBuffer logMessage = new StringBuffer(" sessionId = ") + .append(mSessionId).append("\n") + .append(" component name = ") + .append(component).append("\n") + .append(" type = ") ; + + switch (aUpdate.getUpdateType()) { + case UpdateItem.ADD: + notificationType = APOCSymbols.sSymAddNotification ; + logMessage.append("Add") ; + break ; + case UpdateItem.REMOVE: + notificationType = APOCSymbols.sSymRemoveNotification ; + logMessage.append("Remove") ; + break ; + case UpdateItem.MODIFY: + notificationType = APOCSymbols.sSymModifyNotification ; + logMessage.append("Modify") ; + break ; + default: + notificationType = -1 ; + logMessage.append("Unknown") ; + break ; + } + APOCLogger.finer("Cdtn003", logMessage.toString()) ; + final Notification notification = + (Notification) MessageFactory.createNotification(mSessionId, + notificationType) ; + + notification.setComponentName(component) ; + notification.setClientData(getListenerClientData(listenerComponent)) ; + mClient.getClientChannel().write(notification.serialise()) ; + } + + private void authenticate( final Client inClient, + final String inUserId ) + throws APOCException + { + APOCAuthenticator theAuthenticator = null; + try + { + theAuthenticator = new APOCAuthenticator( inUserId ); + final Messenger theMessenger = new Messenger(); + theMessenger.setClientChannel( inClient.getClientChannel() ); + theMessenger.sendResponse( + MessageFactory.createResponse( + APOCSymbols.sSymRespSuccessContinueLocalAuth, + null, + new String( theAuthenticator.getChallenge() ) ), + false ); + final CredentialsProviderMessage theMessage = + ( CredentialsProviderMessage )theMessenger.receiveRequest(); + theAuthenticator.processResponse( + theMessage.getCredentials().getBytes() ); + } + finally + { + if ( theAuthenticator != null ) + { + theAuthenticator.cleanup(); + } + } + } + + private String toString( final String inUserId ) + { + StringBuffer theMessage = new StringBuffer() + .append( " userId = " ) + .append( inUserId ) + .append( "\n" ) + + .append( " sessionId = ") + .append( mSessionId ) + .append( "\n" ); + for ( int theIndex = 0 ; theIndex < mCaches.length ; ++ theIndex ) + { + theMessage.append( mCaches[ theIndex ].toString() ).append( "\n "); + } + return theMessage.toString(); + } +} diff --git a/src/com/sun/apoc/daemon/apocd/SessionListener.java b/src/com/sun/apoc/daemon/apocd/SessionListener.java new file mode 100644 index 0000000..3648b92 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/SessionListener.java @@ -0,0 +1,42 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd; + +public interface SessionListener +{ + void onSessionCreate( final Session inSession ); + + void onSessionDestroy( final Session inSession ); +} diff --git a/src/com/sun/apoc/daemon/apocd/UpdateAggregator.java b/src/com/sun/apoc/daemon/apocd/UpdateAggregator.java new file mode 100644 index 0000000..a51b058 --- /dev/null +++ b/src/com/sun/apoc/daemon/apocd/UpdateAggregator.java @@ -0,0 +1,92 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.apocd ; + +import com.sun.apoc.daemon.localdatabase.UpdateItem ; + +import java.util.ArrayList ; +import java.util.HashMap ; +import java.util.Iterator ; +import java.util.Map ; + +public class UpdateAggregator { + // Key = session, value = updates + private Map mUpdates = new HashMap() ; + + public synchronized void addUpdate(Session [] aSessions, + UpdateItem aUpdate) { + for (int i = 0 ; i < aSessions.length ; ++ i) { + Session session = aSessions [i] ; + + if (!mUpdates.containsKey(session)) { + ArrayList updateList = new ArrayList() ; + + updateList.add(aUpdate) ; + mUpdates.put(session, updateList) ; + } + else { + ArrayList updateList = (ArrayList) mUpdates.get(session) ; + + for (int j = 0 ; j < updateList.size() ; ++ j) { + UpdateItem update = (UpdateItem) updateList.get(j) ; + + if (update.getComponentName().equals( + aUpdate.getComponentName())) { + if (update.getUpdateType() != aUpdate.getUpdateType()) { + update.setUpdateType(UpdateItem.MODIFY) ; + } + return ; + } + } + updateList.add(aUpdate) ; + } + } + } + public void sendNotifications() { + Iterator updates = mUpdates.entrySet().iterator() ; + + while (updates.hasNext()) { + Map.Entry update = (Map.Entry) updates.next(); + Session session = (Session) update.getKey() ; + ArrayList updateList = (ArrayList) update.getValue() ; + int nbUpdates = updateList.size() ; + + for (int i = 0 ; i < nbUpdates ; ++ i) { + session.sendNotification((UpdateItem) updateList.get(i)) ; + } + } + } +} + diff --git a/src/com/sun/apoc/daemon/build.xml.in b/src/com/sun/apoc/daemon/build.xml.in new file mode 100644 index 0000000..0ddc898 --- /dev/null +++ b/src/com/sun/apoc/daemon/build.xml.in @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +#************************************************************************* +#* +#* $RCSfile: build.xml,v $ +#* +#* Creation date cas 12 February, 2002 +#* last change $Author: cm122549 $ $Date: 2006/11/27 15:42:26 $ +#* $Revision: 1.4 $ +#* +#* Copyright 2003, Sun Microsystems, Inc. All Rights Reserved. +#* +#************************************************************************* +--> +<project name="ap_policy" default="main" basedir="../../../../../"> + + <property name="jarname" value="apocd.jar"/> + <property name="package" value="com/sun/apoc/daemon"/> + <property name="build.dir" value="build"/> + <property name="build.class" value="build/class"/> + <property name="build.inc" value="build/inc"/> + + <target name="info"> + <echo message="-------------------------------"/> + <echo message="| APOC Daemon |"/> + <echo message="-------------------------------"/> + </target> + + <path id="classpath"> + <pathelement location="@SPIJDK@"/> + <pathelement location="@BDBJDK@"/> + </path> + + <target name="prepare"> + <mkdir dir="${build.dir}"/> + <mkdir dir="${build.class}"/> + </target> + + <target name="compile" depends="prepare"> + <javac srcdir="src" + destdir="${build.class}" + optimize="${optimize}" + debug="${debug}" + classpathref="classpath"> + <include name="${package}/**/*.java"/> + </javac> + </target> + + <target name="jar" depends="compile"> + <condition property="dataDir" value="@APOC_DATADIR@"> + <os name="SunOS"/> + </condition> + <condition property="dataDir" value="@APOC_DATADIR@"> + <os name="Linux"/> + </condition> + <condition property="dataDir" value="\\Documents and Settings\\All Users\\Application Data\\apoc"> + <os family="Windows"/> + </condition> + + <copy file="src/${package}/properties/defaults.properties" + tofile="${build.class}/${package}/defaults.properties"/> + <copy file="src/${package}/properties/os.properties" filtering="true" + tofile="${build.class}/${package}/os.properties"> + <filterset> + <filter token="DataDir" value="${dataDir}"/> + </filterset> + </copy> + <copy file="src/${package}/properties/daemon.properties" + tofile="${build.class}/com/sun/apoc/daemon.properties"/> + + <jar jarfile="${build.class}/${jarname}" + basedir="${build.class}" + includes="${package}/** ${package}/defaults.properties ${package}/os.properties com/sun/apoc/daemon.properties"> + <manifest> + <attribute name="Class-Path" value="@SPIJDK@ @BDBJDK@"/> + </manifest> + </jar> + </target> + + <target name="main" depends="info, jar"/> + + <target name="clean" depends="info"> + <delete file="${build.class}/${jarname}"/> + <delete dir="${build.class}/${package}"/> + </target> + +</project> diff --git a/src/com/sun/apoc/daemon/config/ConfigEventListener.java b/src/com/sun/apoc/daemon/config/ConfigEventListener.java new file mode 100644 index 0000000..52e31fb --- /dev/null +++ b/src/com/sun/apoc/daemon/config/ConfigEventListener.java @@ -0,0 +1,40 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.config; + +public interface ConfigEventListener +{ + public void onConfigEvent(); +} diff --git a/src/com/sun/apoc/daemon/config/DaemonConfig.java b/src/com/sun/apoc/daemon/config/DaemonConfig.java new file mode 100644 index 0000000..639d712 --- /dev/null +++ b/src/com/sun/apoc/daemon/config/DaemonConfig.java @@ -0,0 +1,418 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.config; + +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.spi.*; + +import java.io.*; +import java.net.*; +import java.util.*; +import java.util.logging.*; +import java.util.zip.*; + +public class DaemonConfig implements ConfigEventListener +{ + // Public bootstrap properties + public static final String sDaemonPort = "DaemonPort"; + public static final String sDataDir = "DataDir"; + + // Non bootstrap + public static final String sMaxClientThreads = + "MaxClientThreads"; + public static final String sMaxClientConnections = + "MaxClientConnections"; + public static final String sMaxRequestSize = + "MaxRequestSize"; + public static final String sConfigCDInterval = + "DaemonChangeDetectionInterval"; + public static final String sChangeDetectionInterval = + "ChangeDetectionInterval"; + public static final String sGarbageCollectionInterval = + "GarbageCollectionInterval"; + public static final String sTimeToLive = + "TimeToLive"; + public static final String sLogLevel = + "LogLevel"; + public static final String sIdleThreadDetectionInterval = + "IdleThreadDetectionInterval"; + public static final String sThreadTimeToLive = + "ThreadTimeToLive"; + public static final String sConnectionReadTimeout = + "ConnectionReadTimeout"; + public static final String sInitialChangeDetectionDelay = + "InitialChangeDetectionDelay"; + public static final String sApplyLocalPolicy = + "ApplyLocalPolicy"; + public static final String sMaxDbLocks = + "MaxDatabaseLocks"; + private static DaemonConfig sInstance; + + private static final String sAPOCJarFile = "apocd.jar"; + private static final String sDefaultsPropertiesFile = "defaults.properties"; + public static final String sOSPropertiesFile = "os.properties"; + public static final String sApocPropertiesFile = "apocd.properties"; + public static final String sJProxyPropertiesFile = "policymgr.properties"; + private static final String[] sLocalPropertiesFiles = + { sOSPropertiesFile, sApocPropertiesFile, sJProxyPropertiesFile }; + private static String sDaemonInstallDir; + private static String sDaemonPropertiesDir; + + private Properties mDefaultProperties; + private RemoteConfig mRemoteConfig; + private LocalConfig mLocalConfig; + private final HashSet mConfigEventListeners = new HashSet(); + private String mHostIdentifier; + private final DaemonTimerTask mConfigLoader = + new DaemonTimerTask( new ConfigLoader() ); + + public static void addConfigEventListener( + final ConfigEventListener inConfigListener ) + { + synchronized( sInstance.mConfigEventListeners ) + { + sInstance.mConfigEventListeners.add( inConfigListener ); + } + } + + static public String getHostIdentifier() + { + return sInstance.mHostIdentifier; + } + + public static DaemonConfig getInstance() + { + return sInstance; + } + + public static boolean getBooleanProperty( final String inPropertyName ) + { + return getBooleanProperty( inPropertyName, null ); + } + + public static boolean getBooleanProperty( final String inPropertyName, + final String inDefaultValue ) + { + return Boolean.valueOf( + getStringProperty( inPropertyName, inDefaultValue ).trim() ). + booleanValue(); + } + + public static float getFloatProperty( final String inPropertyName ) + { + return getFloatProperty( inPropertyName, null ); + } + + public static float getFloatProperty( final String inPropertyName, + final String inDefaultValue ) + { + return Float.parseFloat( + getStringProperty( inPropertyName, inDefaultValue ).trim() ); + } + + public static int getIntProperty( final String inPropertyName ) + { + return getIntProperty( inPropertyName, null ); + } + + public static int getIntProperty( final String inPropertyName, + final String inDefaultValue ) + { + return Integer.parseInt( + getStringProperty( inPropertyName, inDefaultValue ).trim() ); + } + + public static LocalConfig getLocalConfig() + { + return sInstance.mLocalConfig; + } + + public static String getStringProperty( final String inPropertyName ) + { + return getStringProperty( inPropertyName, null ); + } + + public static String getStringProperty( final String inPropertyName, + final String inDefaultValue ) + { + return sInstance.mLocalConfig.getProperty( inPropertyName, + inDefaultValue ); + } + + public static void init( final String[] inArgs ) + throws IOException, APOCException + { + sInstance = new DaemonConfig( inArgs ); + reload(); + addConfigEventListener( sInstance ); + sInstance.pollForChanges(); + } + + public static void log() + { + if ( APOCLogger.isLoggable( Level.CONFIG ) && + sInstance != null && + sInstance.mLocalConfig != null ) + { + final StringBuffer theBuffer = new StringBuffer( "" ); + final Enumeration theEnumeration = + sInstance.mLocalConfig.propertyNames(); + while ( theEnumeration.hasMoreElements() ) + { + final String theName = ( String )theEnumeration.nextElement(); + theBuffer.append( " " ) + .append( theName ) + .append( " = " ) + .append( + theName.compareTo( "Password" ) == 0 ? + obscure( + DaemonConfig.getStringProperty( theName ) ): + DaemonConfig.getStringProperty( theName ) ) + .append( "\n" ); + } + APOCLogger.config( "Dcfg001", theBuffer.toString() ); + } + } + + public void onConfigEvent() + { + pollForChanges(); + } + + public static void reload() + throws IOException + { + reload( false ); + } + + public static void reload( boolean inRemoteOnly ) + throws IOException + { + final Set theOriginalValues = sInstance.getAllValues(); + if ( ! inRemoteOnly ) + { + sInstance.mLocalConfig.load( sLocalPropertiesFiles ); + sInstance.setHostIdentifier(); + } + sInstance.mRemoteConfig.load(); + if ( ! sInstance.getAllValues().equals( theOriginalValues ) ) + { + sInstance.configLoaded(); + } + } + + public static void removeConfigEventListener( + final ConfigEventListener inConfigListener) + { + synchronized( sInstance.mConfigEventListeners ) + { + sInstance.mConfigEventListeners.remove( inConfigListener ); + } + } + + private DaemonConfig( final String[] inArgs ) + throws IOException + { + sDaemonInstallDir = inArgs[ 0 ]; + sDaemonPropertiesDir = inArgs[ 1 ]; + createDefaults(); + mLocalConfig = new LocalConfig( sDaemonPropertiesDir ); + mRemoteConfig = new RemoteConfig(); + mLocalConfig.setDefaults( mRemoteConfig ); + mRemoteConfig.setDefaults( mDefaultProperties ); + } + + private void configLoaded() + { + Object[] theConfigEventListeners; + synchronized( mConfigEventListeners ) + { + theConfigEventListeners = mConfigEventListeners.toArray(); + } + if ( theConfigEventListeners != null ) + { + for ( int theIndex = 0; + theIndex < theConfigEventListeners.length; + ++ theIndex ) + { + ( ( ConfigEventListener )theConfigEventListeners[ theIndex ] ) + .onConfigEvent(); + } + } + } + + private void createDefaults() + throws IOException + { + ZipFile theZipFile = + new ZipFile( + new StringBuffer( sDaemonInstallDir ) + .append( File.separatorChar ) + .append( sAPOCJarFile ) + .toString() ); + + String thePath = new String( "com/sun/apoc/daemon/" ); + + mDefaultProperties = new Properties(); + mDefaultProperties.load( + theZipFile.getInputStream( + theZipFile.getEntry( + new StringBuffer( thePath ) + .append( sDefaultsPropertiesFile ) + .toString() ) ) ); + + mDefaultProperties.load( + theZipFile.getInputStream( + theZipFile.getEntry( + new StringBuffer( thePath ) + .append( sOSPropertiesFile ) + .toString() ) ) ); + } + + private Set getAllValues() + { + final HashSet theSet = new HashSet(); + if ( mLocalConfig != null ) + { + final Enumeration theEnumeration = mLocalConfig.propertyNames(); + while ( theEnumeration.hasMoreElements() ) + { + theSet.add( + mLocalConfig.getProperty( + ( String )theEnumeration.nextElement() ) ); + } + } + return theSet; + } + + /** + * Check if the address can be used to identify the machine from + * an external point of view. For the moment limited to checking + * that it's not the loopback address. + */ + private static boolean isAcceptableAddress(InetAddress inAddress) { + return !inAddress.isLoopbackAddress() ; + } + + private String guessHostIdentifer() + { + String theHostIdentifier = null; + try + { + Enumeration theInterfaces = NetworkInterface.getNetworkInterfaces(); + if ( theInterfaces != null ) + { + while ( theInterfaces.hasMoreElements() ) + { + NetworkInterface theInterface = + ( NetworkInterface )theInterfaces.nextElement(); + Enumeration theInetAddresses= + theInterface.getInetAddresses(); + if ( theInetAddresses != null ) + { + while ( theInetAddresses.hasMoreElements() ) + { + InetAddress theAddress = + ( InetAddress )theInetAddresses.nextElement(); + if (isAcceptableAddress(theAddress)) + { + theHostIdentifier = theAddress.getHostAddress(); + break; + } + } + } + } + } + } + catch( Exception theException ){} + return theHostIdentifier; + } + + private static String obscure( final String inString ) + { + String theString = null; + if ( inString != null ) + { + theString = inString.replaceAll( "\\p{Alnum}", "*" ); + } + return theString; + } + + private void pollForChanges() + { + mConfigLoader.setPeriod( 60000 * getIntProperty( sConfigCDInterval ) ); + } + + private void setHostIdentifier() + { + try + { + if ( mLocalConfig.getProperty( "HostIdentifierType", "Hostname" ) + .compareTo( "IPAddress" ) == 0 ) + { + InetAddress theLocalHost = InetAddress.getLocalHost() ; + if (isAcceptableAddress(theLocalHost)) + { + mHostIdentifier = theLocalHost.getHostAddress() ; + } + else + { + mHostIdentifier = guessHostIdentifer(); + } + } + else + { + mHostIdentifier = InetAddress.getLocalHost().getHostName(); + } + } + catch( UnknownHostException theException ) + { + mHostIdentifier = null; + } + } + + class ConfigLoader implements Runnable + { + public void run() + { + try + { + sInstance.reload( true ); + } + catch( IOException theException ) + {} + } + } +} diff --git a/src/com/sun/apoc/daemon/config/LocalConfig.java b/src/com/sun/apoc/daemon/config/LocalConfig.java new file mode 100644 index 0000000..26c8e65 --- /dev/null +++ b/src/com/sun/apoc/daemon/config/LocalConfig.java @@ -0,0 +1,79 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.config; + +import java.io.*; +import java.util.*; + +class LocalConfig extends Properties +{ + private String mPropertiesDir; + + public LocalConfig( final String inPropertiesDir ) + { + super(); + mPropertiesDir = + new StringBuffer( inPropertiesDir ) + .append( File.separatorChar ) + .toString(); + } + + public void load ( final String[] inFileNames ) + { + clear(); + for ( int theIndex = 0; theIndex < inFileNames.length; theIndex ++ ) + { + load( inFileNames[ theIndex ] ); + } + } + + public void setDefaults( final Properties inDefaults ) + { + defaults = inDefaults; + } + + private void load( final String inFileName ) + { + try + { + load( + new FileInputStream( + new StringBuffer( mPropertiesDir ) + .append( inFileName ) + .toString() ) ); + } + catch( IOException theException ) {} + } +} diff --git a/src/com/sun/apoc/daemon/config/RemoteConfig.java b/src/com/sun/apoc/daemon/config/RemoteConfig.java new file mode 100644 index 0000000..b3935f9 --- /dev/null +++ b/src/com/sun/apoc/daemon/config/RemoteConfig.java @@ -0,0 +1,198 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.config; + +import com.sun.apoc.daemon.misc.*; + +import com.sun.apoc.spi.*; +import com.sun.apoc.spi.cfgtree.*; +import com.sun.apoc.spi.cfgtree.property.*; +import com.sun.apoc.spi.cfgtree.policynode.*; +import com.sun.apoc.spi.cfgtree.readwrite.*; +import com.sun.apoc.spi.entities.*; +import com.sun.apoc.spi.environment.*; +import com.sun.apoc.spi.policies.*; +import com.sun.apoc.spi.profiles.*; + +import java.util.*; + +class RemoteConfig extends Properties +{ + private static final String sParentNodeName = "com.sun.apoc.apocd"; + + public void load() + { + clear(); + PolicyManager thePolicyMgr = null; + try + { + final Properties theProperties = + ( Properties )DaemonConfig.getLocalConfig().clone(); + theProperties.put( EnvironmentConstants.LDAP_AUTH_TYPE_KEY, + EnvironmentConstants.LDAP_AUTH_TYPE_ANONYMOUS ); + thePolicyMgr = new PolicyManager( theProperties ); + load( thePolicyMgr ); + } + catch ( Exception theException ) + {} + finally + { + if ( thePolicyMgr != null ) + { + try + { + thePolicyMgr.close(); + } + catch( Exception theException ) + { + APOCLogger.throwing( "RemoteConfig", "load", theException ); + } + } + } + } + + public void setDefaults( final Properties inProperties ) + { + defaults = inProperties; + } + + private String getPropertyValue( final PolicyNode inParentNode, + final String inPropertyName ) + { + String theValue = null; + if ( inParentNode != null ) + { + final Property theProperty = + inParentNode.getProperty( inPropertyName ); + if ( theProperty != null ) + { + try + { + theValue = theProperty.getValue(); + } + catch( SPIException theException ){} + } + } + return theValue; + } + + private void load( final PolicyManager inPolicyMgr ) + throws SPIException + { + final Entity theDomain = + inPolicyMgr.getRootEntity( EnvironmentConstants.HOST_SOURCE ); + final Iterator theIterator = ((Domain) theDomain).findEntities( + DaemonConfig.getHostIdentifier(), + true ); + if ( theIterator != null && theIterator.hasNext() ) + { + final Entity theEntity = ( Entity )theIterator.next(); + final Iterator theProfiles = theEntity.getLayeredProfiles(); + if ( theProfiles != null ) + { + final ArrayList thePolicies = new ArrayList(); + while ( theProfiles.hasNext() ) + { + final Profile theProfile = ( Profile )theProfiles.next(); + final Policy thePolicy = + theProfile.getPolicy( sParentNodeName); + if ( thePolicy != null ) + { + thePolicies.add( thePolicy ); + } + } + if ( thePolicies.size() > 0 ) + { + final PolicyTree theTree = + new ReadWritePolicyTreeFactoryImpl() + .getPolicyTree( thePolicies.iterator() ); + if ( theTree != null ) + { + final PolicyNode theParentNode = + theTree.getNode( sParentNodeName ); + if ( theParentNode != null ) + { + setProp( DaemonConfig.sMaxClientThreads, + getPropertyValue( + theParentNode, + DaemonConfig.sMaxClientThreads ) ); + setProp( DaemonConfig.sMaxClientConnections, + getPropertyValue( + theParentNode, + DaemonConfig.sMaxClientConnections ) ); + setProp( DaemonConfig.sMaxRequestSize, + getPropertyValue( + theParentNode, + DaemonConfig.sMaxRequestSize ) ); + setProp( DaemonConfig.sConfigCDInterval, + getPropertyValue( + theParentNode, + DaemonConfig.sConfigCDInterval ) ); + setProp( DaemonConfig.sChangeDetectionInterval, + getPropertyValue( + theParentNode, + DaemonConfig.sChangeDetectionInterval ) ); + setProp( DaemonConfig.sGarbageCollectionInterval, + getPropertyValue( + theParentNode, + DaemonConfig.sGarbageCollectionInterval ) ); + setProp( DaemonConfig.sTimeToLive, + getPropertyValue( + theParentNode, + DaemonConfig.sTimeToLive ) ); + setProp( DaemonConfig.sLogLevel, + getPropertyValue( + theParentNode, + DaemonConfig.sLogLevel ) ); + setProp( DaemonConfig.sApplyLocalPolicy, + getPropertyValue( + theParentNode, + DaemonConfig.sApplyLocalPolicy ) ); + } + } + } + } + } + } + + private void setProp( final String inPropertyName, + final String inPropertyValue ) + { + if ( inPropertyValue != null ) + { + setProperty( inPropertyName, inPropertyValue ); + } + } +} diff --git a/src/com/sun/apoc/daemon/localdatabase/Database.java b/src/com/sun/apoc/daemon/localdatabase/Database.java new file mode 100644 index 0000000..6470c6c --- /dev/null +++ b/src/com/sun/apoc/daemon/localdatabase/Database.java @@ -0,0 +1,365 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.localdatabase; + +import com.sleepycat.db.*; + +import com.sun.apoc.daemon.misc.*; + +import java.io.*; +import java.util.*; + +public class Database extends Db +{ + protected final Name mName; + private Dbc mDbc; + + private static final int sDbType = Db.DB_BTREE; + private static final int sDbFlags = Db.DB_CREATE; + private static final int sDbMode = 0600; + private static final String sValueEpoch = "19700101000000Z"; + + public static final String sKeyLastChangeDetect = "lastChangeDetect"; + public static final String sKeyLastModified = "lastModified/"; + public static final String sKeyLastRead = "lastRead"; + public static final String sKeyLayerIds = "layerIds/"; + public static final String sKeyDBs = "dbs"; + public static final String sKeyRemoteComponentList = + "remoteComponentList"; + public static final String sKeyLocalComponentList = + "localComponentList"; + + public Database( final Name inName ) + throws APOCException, DbException, FileNotFoundException + { + super( LocalDatabaseFactory.getInstance(), 0 ); + mName = inName; + openDatabase( LocalDatabaseFactory.getLocalDatabaseFileName(mName), + getDatabaseName(mName)); + } + + public Database(final Name inName, final String inFileName) + throws APOCException, DbException, FileNotFoundException + { + super(LocalDatabaseFactory.getInstance(), 0) ; + mName = inName ; + openDatabase(inFileName, getDatabaseName(mName)) ; + } + private void openDatabase(final String inFileName, + final String inDatabaseName) + throws APOCException, DbException, FileNotFoundException + { + open(null, inFileName, inDatabaseName, sDbType, sDbFlags, sDbMode) ; + } + + public Name getName() { return mName; } + + public static String getDatabaseName(Name aName) + { + return new StringBuffer(aName.getEntityType()).append(Name.sSep) + .append(aName.getEntityName()).append(Name.sSep) + .append(aName.getLocation()).toString() ; + } + + public static Database createDatabase(String aName) + throws APOCException, DbException, FileNotFoundException + { + String [] components = aName.split(Name.sSep) ; + + if (components != null && components.length > 2) + { + return new Database(new Name(null, + components [0], + components [1], + components [2])) ; + } + throw new APOCException() ; + } + + public String toString() { return getDatabaseName(mName) ; } + + public void beginTransaction() + throws APOCException + { + try + { + final Dbc theCursor = cursor( null, Db.DB_WRITECURSOR ); + mDbc = theCursor; + } + catch( DbException theException ) + { + throw new APOCException( theException ); + } + } + + public void endTransaction() + throws APOCException + { + if ( mDbc != null ) + { + try + { + final Dbc theCursor = mDbc; + mDbc = null; + theCursor.close(); + } + catch( DbException theException ) + { + throw new APOCException( theException ); + } + } + } + + public int get( String inKey, final Dbt outValue ) + throws APOCException + { + return get( new StringDbt( inKey ), outValue ); + } + + public int get( final Dbt inKey, final Dbt outValue ) + throws APOCException + { + try + { + return get( null, inKey, outValue, 0 ); + } + catch( DbException theException ) + { + throw new APOCException( theException ); + } + } + + public HashSet getDBList() + throws APOCException + { + final SetDbt theSetDbt = new SetDbt(); + get( sKeyDBs, theSetDbt ); + return theSetDbt.getApocData(); + } + + public String getLastChangeDetect() + throws APOCException + { + final StringDbt theValue = new StringDbt(); + get( sKeyLastChangeDetect, theValue ); + if ( theValue.get_size() > 0 ) + { + return theValue.getApocData(); + } + else + { + return sValueEpoch; + } + } + + public String getLastModified( final String inLayerId, + final String inComponentName ) + throws APOCException + { + final StringDbt theValue = new StringDbt(); + get( new StringBuffer( sKeyLastModified ) + .append( inLayerId ) + .append( "/" ) + .append( inComponentName ) + .toString(), + theValue ); + if ( theValue.get_size() > 0 ) + { + return theValue.getApocData(); + } + else + { + return sValueEpoch; + } + } + + public String getLastRead() + throws APOCException + { + final StringDbt theValue = new StringDbt(); + get( sKeyLastRead, theValue ); + if ( theValue.get_size() > 0 ) + { + return theValue.getApocData(); + } + else + { + return sValueEpoch; + } + } + + public String getLayer( final String inComponentName, + final String inLayerId ) + throws APOCException + { + final String theKey = new StringBuffer( inLayerId ) + .append( "/" ) + .append( inComponentName ) + .toString(); + StringDbt theValue = new StringDbt(); + get( theKey, theValue ); + return theValue.getApocData(); + } + + public Vector getLayerIds( final String inComponentName ) + throws APOCException + { + final VectorStringDbt theVectorDbt = new VectorStringDbt(); + get( new StringBuffer( sKeyLayerIds ) + .append( inComponentName ) + .toString(), + theVectorDbt ); + return theVectorDbt.retrieveData(); + } + + public HashSet getLocalComponentList() + throws APOCException + { + final SetDbt theSetDbt = new SetDbt(); + get( sKeyLocalComponentList, theSetDbt ); + return theSetDbt.getApocData(); + } + + public HashSet getRemoteComponentList() + throws APOCException + { + final SetDbt theSetDbt = new SetDbt(); + get( sKeyRemoteComponentList, theSetDbt ); + return theSetDbt.getApocData(); + } + + public int put( final Dbt inKey, final String inData ) + throws APOCException + { + return put( inKey, new StringDbt( inData ) ); + } + + public int put( final String inKey, final HashSet inData ) + throws APOCException + { + return put( new StringDbt( inKey ), new SetDbt( inData ) ); + } + + public int put( final Dbt inKey, final HashSet inData ) + throws APOCException + { + return put( inKey, new SetDbt( inData ) ); + } + + public int put(final String inKey, final Vector inData) + throws APOCException + { + return put(new StringDbt(inKey), new VectorStringDbt(inData)) ; + } + + public int put( final String inKey, final String inData ) + throws APOCException + { + return put( new StringDbt( inKey ), new StringDbt( inData ) ); + } + + public int put( final String inKey, final Dbt inData ) + throws APOCException + { + return put( new StringDbt( inKey ), inData ); + } + + public int put( final Dbt inKey, final Dbt inData ) + throws APOCException + { + try + { + return mDbc.put( inKey, inData, Db.DB_KEYFIRST ); + } + catch( DbException theException ) + { + throw new APOCException( theException ); + } + } + + public void putDBList( final HashSet inDBList ) + throws APOCException + { + put( sKeyDBs, inDBList ); + } + + public void putLastChangeDetect( final String inTimestamp ) + throws APOCException + { + put( sKeyLastChangeDetect, inTimestamp ); + } + + public void putLastModified( final String inLayerId, + final String inComponentName, + final String inTimestamp ) + throws APOCException + { + put( new StringBuffer( sKeyLastModified ) + .append( inLayerId ) + .append( "/" ) + .append( inComponentName ) + .toString(), + inTimestamp ); + } + + public void putLayerIds( final String inComponentName, + final Vector inLayerIds ) + throws APOCException + { + put ( new StringBuffer( sKeyLayerIds ) + .append( inComponentName ) + .toString(), + inLayerIds ); + } + + public void putRemoteComponentList( final HashSet inRemoteComponentList ) + throws APOCException + { + put( sKeyRemoteComponentList, inRemoteComponentList ); + } + + public void putLocalComponentList( final HashSet inComponentNames ) + throws APOCException + { + put( sKeyLocalComponentList, inComponentNames ); + } + + protected void putLastRead() + throws APOCException + { + put( sKeyLastRead, Timestamp.getTimestamp() ); + } + +} diff --git a/src/com/sun/apoc/daemon/localdatabase/LocalDatabase.java b/src/com/sun/apoc/daemon/localdatabase/LocalDatabase.java new file mode 100644 index 0000000..6154dff --- /dev/null +++ b/src/com/sun/apoc/daemon/localdatabase/LocalDatabase.java @@ -0,0 +1,200 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.localdatabase; + +import com.sleepycat.db.*; + +import com.sun.apoc.daemon.apocd.*; +import com.sun.apoc.daemon.misc.*; + +import com.sun.apoc.spi.policies.*; + +import java.io.*; +import java.nio.*; +import java.util.*; + +public class LocalDatabase extends Database +{ + private HashSet mLocalComponentList; + private int mRefCount = 0; + + public LocalDatabase( final Name inName ) + throws APOCException, DbException, FileNotFoundException + { + super( inName ); + initLocalComponentList(); + } + + synchronized public int acquire() { return ++mRefCount; } + synchronized public int release() + { + if ( --mRefCount == 0 ) + { + try + { + beginTransaction(); + putLastRead(); + endTransaction(); + close( 0 ); + } + catch( DbException theException ) + {} + catch( APOCException theException ) + {} + } + return mRefCount; + } + + public boolean hasComponent( final String inComponentName ) + { + return mLocalComponentList.contains( inComponentName ); + } + + public void putLocalComponentList( final HashSet inLocalComponentList ) + throws APOCException + { + mLocalComponentList = inLocalComponentList; + super.putLocalComponentList( mLocalComponentList ); + } + + public void update( final UpdateItem inUpdateItem, final String inTimestamp) + throws APOCException + { + if ( inUpdateItem != null ) + { + updateItem( inUpdateItem, new StringDbt( inTimestamp ) ); + } + } + + public void update( final ArrayList inUpdateItems, final String inTimestamp) + throws APOCException + { + int theSize; + if ( inUpdateItems != null && ( theSize = inUpdateItems.size() ) > 0 ) + { + StringDbt theTimestamp = new StringDbt( inTimestamp ); + for ( int theIndex = 0; theIndex < theSize; ++ theIndex ) + { + updateItem( ( UpdateItem )inUpdateItems.get( theIndex ), + theTimestamp ); + } + } + } + + private void addLocalComponent( final String inComponentName ) + throws APOCException + { + mLocalComponentList.add( inComponentName ); + super.putLocalComponentList( mLocalComponentList ); + } + + private void initLocalComponentList() + throws APOCException + { + if ( ( mLocalComponentList = super.getLocalComponentList() ) == null ) + { + mLocalComponentList = new HashSet(); + } + } + + private void putComponent( final String inComponentName, + final Policy[] inPolicies ) + throws APOCException + { + if ( inPolicies != null && inPolicies.length > 0 ) + { + final Vector theLayerIds = new Vector( inPolicies.length ); + for ( int theIndex = 0; theIndex < inPolicies.length; theIndex ++ ) + { + final String theLayerId = + String.valueOf( + inPolicies[ theIndex].getProfileId().hashCode() ); + + String theKey = new StringBuffer( theLayerId ) + .append( "/" ) + .append( inComponentName ) + .toString(); + put( theKey, inPolicies[ theIndex ].getData() ); + + theLayerIds.add( theLayerId ); + + putLastModified( theLayerId, + inComponentName, + Timestamp.getTimestamp( + inPolicies[ theIndex ].getLastModified() )); + } + putLayerIds( inComponentName, theLayerIds ); + } + } + + private void removeLocalComponent( final String inComponentName ) + throws APOCException + { + mLocalComponentList.remove( inComponentName ); + super.putLocalComponentList( mLocalComponentList ); + } + + private void updateItem( final UpdateItem inUpdateItem ) + throws APOCException + { + updateItem( inUpdateItem, new StringDbt( Timestamp.getTimestamp() ) ); + } + + private void updateItem( final UpdateItem inUpdateItem, + final Dbt inTimestamp ) + throws APOCException + { + String theComponentName = inUpdateItem.getComponentName(); + Policy[] thePolicies = inUpdateItem.getPolicies(); + switch ( inUpdateItem.getUpdateType() ) + { + case UpdateItem.ADD: + putComponent( theComponentName, thePolicies ); + addLocalComponent( theComponentName ); + break; + + case UpdateItem.MODIFY: + putComponent( theComponentName, thePolicies ); + break; + + case UpdateItem.REMOVE: + removeLocalComponent( theComponentName ); + break; + + default: + break; + } + } +} diff --git a/src/com/sun/apoc/daemon/localdatabase/LocalDatabaseFactory.java b/src/com/sun/apoc/daemon/localdatabase/LocalDatabaseFactory.java new file mode 100644 index 0000000..13ae22b --- /dev/null +++ b/src/com/sun/apoc/daemon/localdatabase/LocalDatabaseFactory.java @@ -0,0 +1,460 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.localdatabase; + +import com.sleepycat.db.*; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.misc.*; + +import java.io.*; +import java.util.*; + +public class LocalDatabaseFactory extends DbEnv +{ + private static LocalDatabaseFactory sInstance; + private static final HashMap sDatabases = + new HashMap( DaemonConfig.getIntProperty( + DaemonConfig.sMaxClientConnections ) ); + private static final String sLDBHome = + new StringBuffer( + DaemonConfig.getStringProperty( DaemonConfig.sDataDir ) ) + .append( File.separatorChar ) + .append( "LocalDB" ) + .toString(); + private static final Name sDbListDbName = + new Name(null, "DbListType", "DbList", true) ; + + + private static final int sDbEnvFlags = Db.DB_CREATE | + Db.DB_INIT_CDB | + Db.DB_INIT_MPOOL | + Db.DB_PRIVATE; + + private static final int sDbEnvMode = 0600; + private static final String s__dbPrefix = "__db."; + + private LocalDatabaseFactory() + throws APOCException, DbException + { + super( 0 ); + createDBHome(); + initLocks(); + openEnv(); + } + + public void deleteDatabase( final Database inDatabase ) + { + final Name theName = inDatabase.getName(); + synchronized ( sDatabases ) + { + if ( ! sDatabases.containsKey( createDatabaseKey( theName ) ) ) + { + try + { + final HashSet theDBs = removeDbFromDbList( theName ); + if ( theDBs == null || theDBs.size() == 0 ) + { + new File(getLocalDatabaseFilePath(theName)).delete() ; + } + } + catch( Exception theException ) + {} + } + } + } + public static LocalDatabaseFactory getInstance() + throws APOCException + { + if ( sInstance == null ) + { + try + { + sInstance = new LocalDatabaseFactory(); + Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { + public void run() { + try { + Iterator databases = + sDatabases.values().iterator() ; + + while (databases.hasNext()) { + ((Database) databases.next()).close(0) ; + } + sInstance.close(0) ; + } + catch (DbException ignored) {} + } + })) ; + + } + catch ( DbException theException ) + { + throw new APOCException( theException ); + } + } + return sInstance; + } + + public Object[] getDatabases() + { + Object[] theDatabases = null; + final String[] theDBFileNames = new File( sLDBHome ).list(); + if ( theDBFileNames != null ) + { + final ArrayList theDBList = new ArrayList( theDBFileNames.length ); + for ( int theIndex = 0; + theIndex < theDBFileNames.length; + ++ theIndex ) + { + if ( theDBFileNames[ theIndex ].startsWith( s__dbPrefix ) ) + { + continue; + } + String[] theNames = + getDatabaseNames( theDBFileNames[ theIndex ] ); + if ( theNames != null ) + { + for ( int theNamesIndex = 0; + theNamesIndex < theNames.length; + ++ theNamesIndex ) + { + synchronized( sDatabases ) + { + // No need to include LocalDatabase instances + // ( i.e. databases with client connections ) + // in return array + Database theDatabase = + ( Database )sDatabases. + get( theNames[ theNamesIndex ] ); + if ( theDatabase == null ) + { + try + { + theDatabase = + Database.createDatabase( + theNames [ theNamesIndex ] ) ; + theDBList.add( theDatabase ); + } + catch( Exception theException) + {} + } + } + } + } + } + theDatabases = theDBList.toArray(); + } + return theDatabases; + } + + public String[] getDatabaseNames( final String inDBFileName ) + { + String[] theDatabaseNames = null; + try + { + final HashSet theDBNames = getDBList( inDBFileName ); + if ( theDBNames != null && theDBNames.size() > 0 ) + { + theDatabaseNames = + ( String[] )theDBNames.toArray( new String[ 0 ] ); + } + } + catch( Exception theException ) + {} + return theDatabaseNames; + } + + public Object[] openLocalDatabases() + { + Object[] theLocalDatabases = null; + if ( ! sDatabases.isEmpty() ) + { + theLocalDatabases = sDatabases.values().toArray(); + } + return theLocalDatabases; + } + + public LocalDatabase openLocalDatabase( final Name inName ) + throws APOCException + { + final String theKey = createDatabaseKey( inName ); + LocalDatabase theLocalDatabase = null; + synchronized( sDatabases ) + { + theLocalDatabase = ( LocalDatabase )sDatabases.get( theKey ); + if ( theLocalDatabase == null ) + { + theLocalDatabase = createNewLocalDatabase( inName ); + } + if ( theLocalDatabase != null ) + { + theLocalDatabase.acquire(); + } + } + return theLocalDatabase; + } + + public void closeLocalDatabase( final LocalDatabase inLocalDatabase ) + { + synchronized( sDatabases ) + { + if ( inLocalDatabase.release() == 0 ) + { + sDatabases.remove( + createDatabaseKey( + inLocalDatabase.getName() ) ); + } + } + } + + private void addDbToDbList( final Name inName ) + throws APOCException, DbException, FileNotFoundException + { + final Database theDatabase = + new Database(sDbListDbName, getLocalDatabaseFileName(inName)) ; + HashSet theDBList = theDatabase.getDBList(); + if ( theDBList == null ) + { + theDBList = new HashSet( 1 ); + } + theDBList.add( createDatabaseKey(inName) ); + theDatabase.beginTransaction(); + theDatabase.putDBList( theDBList ); + theDatabase.endTransaction(); + theDatabase.close( 0 ); + } + + private static String createDatabaseKey( final Name inName ) + { + return Database.getDatabaseName(inName); + } + + private void createDBHome() + throws APOCException + { + final File theFile = new File( sLDBHome ); + if ( ! theFile.exists() ) + { + if ( ! theFile.mkdirs() ) + { + throw new APOCException( APOCSymbols.sSymDBEnvCreateFailed ); + } + } + else + { + if ( ! theFile.isDirectory() ) + { + throw new APOCException( APOCSymbols.sSymDBEnvCreateFailed ); + } + } + FileAccess.chmod( sLDBHome, 0700 ); + FileAccess.chmod( theFile.getParent(), 0755 ); + } + + private LocalDatabase createNewLocalDatabase( final Name inName ) + throws APOCException + { + return createNewLocalDatabase( inName, true ); + } + + private LocalDatabase createNewLocalDatabase( final Name inName, + boolean inDeleteRetry ) + throws APOCException + { + ensureNonZeroLengthDBFile( inName ); + try + { + final LocalDatabase theLocalDatabase = new LocalDatabase( inName ); + addDbToDbList( inName ); + sDatabases.put( createDatabaseKey( inName ), theLocalDatabase ); + return theLocalDatabase; + } + catch ( Exception theException ) + { + if ( inDeleteRetry ) + { + new File( getLocalDatabaseFilePath(inName)).delete(); + return createNewLocalDatabase( inName, false ); + } + else + { + throw new APOCException( theException ); + } + } + } + + private void ensureNonZeroLengthDBFile( final Name inName ) + throws APOCException + { + File theFile = new File( getLocalDatabaseTmpFilePath( inName ) ); + try + { + if ( theFile.exists() ) + { + theFile.delete(); + } + } + catch( Exception theException ) + { + throw new APOCException( theException ); + } + + theFile = new File ( getLocalDatabaseFilePath( inName ) ); + try + { + if ( theFile.exists() && theFile.length() == 0 ) + { + theFile.delete(); + } + } + catch( Exception theException ) + { + throw new APOCException( theException ); + } + } + + /* + * 6417522 - default bdb values ( 1000 )for max lockers etc. too small + * Adjusting the max. number of lockers dynamically ( based + * roughly on MaxClientConnections ) would require the ability + * to close & reopen the db environment and all database + * dynamically. That's not terribly easy ... at least for our + * current implementation. + * + * As an alternative and considering that additional locks etc. + * are really quite cheap ( in terms of memory usge ), have + * decided that a practical solution to running out of locks etc. + * is to set the max at a ( most likely ) unreachable value. + * The number of locks required per user connection seems to + * vary dependent on the platform but 12 is a reasonable + * generalisation. + * For the moment, I'm using a default value of 12000 for max. + * locks. This would allow approx. 1000 users to connect. It + * also has no significant impact on memory use. + */ + private void initLocks() + throws DbException + { + int theCount = DaemonConfig.getIntProperty( DaemonConfig.sMaxDbLocks ); + setLockMaxLockers( theCount ); + setLockMaxLocks( theCount ); + setLockMaxObjects( theCount ); + } + + private void openEnv() + throws APOCException + { + try + { + new DbEnv( 0 ).remove( sLDBHome, Db.DB_FORCE ); + open( sLDBHome, sDbEnvFlags, sDbEnvMode ); + } + catch( DbException theException ) + { + APOCLogger.throwing( "LocalDatabaseFactory", + "openEnv", + theException ); + throw new APOCException( theException ); + } + catch( FileNotFoundException theException ) + { + APOCLogger.throwing( "LocalDatabaseFactory", + "openEnv", + theException ); + throw new APOCException( theException ); + } + } + + private HashSet getDBList( final String inDBFileName ) + throws APOCException, DbException, FileNotFoundException + { + final Database theDatabase = new Database(sDbListDbName, + inDBFileName) ; + final HashSet theList = theDatabase.getDBList(); + theDatabase.close( 0 ); + return theList; + } + + public static String getLocalDatabaseFileName( final Name inName ) + { + return new StringBuffer(inName.getEntityType()) + .append(".") + .append(inName.getEntityName()).toString(); + } + + private static String getLocalDatabaseFilePath( final Name inName ) + { + return new StringBuffer( sLDBHome ) + .append( File.separatorChar ) + .append(getLocalDatabaseFileName(inName) ) + .toString(); + } + + private static String getLocalDatabaseTmpFilePath( final Name inName ) + { + return new StringBuffer( sLDBHome ) + .append( File.separatorChar ) + .append( s__dbPrefix ) + .append( getLocalDatabaseFileName( inName ) ) + .toString(); + } + + private HashSet removeDbFromDbList( final Name inName ) + throws APOCException, DbException, FileNotFoundException + { + final Database theDatabase = + new Database( sDbListDbName, getLocalDatabaseFileName( inName ) ); + /* + * 6417504 - ensure Db handle is closed to avoid leak + */ + HashSet theDBList = null; + try + { + theDBList = theDatabase.getDBList(); + if ( theDBList != null ) + { + theDBList.remove( inName.toString() ); + theDatabase.beginTransaction(); + theDatabase.putDBList( theDBList ); + theDatabase.endTransaction(); + } + } + finally + { + theDatabase.close( 0 ); + } + return theDBList; + } +} diff --git a/src/com/sun/apoc/daemon/localdatabase/SetDbt.java b/src/com/sun/apoc/daemon/localdatabase/SetDbt.java new file mode 100644 index 0000000..e06fe6c --- /dev/null +++ b/src/com/sun/apoc/daemon/localdatabase/SetDbt.java @@ -0,0 +1,96 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.localdatabase; + +import com.sleepycat.db.*; + +import java.nio.*; +import java.util.*; + +class SetDbt extends Dbt +{ + SetDbt() + { + set_flags( Db.DB_DBT_MALLOC ); + } + + SetDbt( final HashSet inValue ) + { + setApocData( inValue ); + set_flags( Db.DB_DBT_MALLOC ); + } + + void setApocData( final HashSet inValue ) + { + int theSize = 0; + Iterator theIterator = inValue.iterator(); + while ( theIterator.hasNext() ) + { + theSize += ( ( String )theIterator.next() ).length() + 1; + } + ByteBuffer theBuffer = ByteBuffer.allocate( theSize ); + theIterator = inValue.iterator(); + while ( theIterator.hasNext() ) + { + theBuffer + .put( ( ( String )theIterator.next() ).getBytes() ) + .put( ( byte )0 ); + } + theBuffer.flip(); + set_data( theBuffer.array() ); + set_size( theSize ); + } + + HashSet getApocData() + { + byte[] theByte = { 0 }; + String theString = new String( theByte ); + HashSet theData = null; + int theSize = get_size(); + if ( theSize > 0 ) + { + final StringTokenizer theTokenizer = + new StringTokenizer( + new String( get_data(), get_offset(), theSize ), + theString ); + theData = new HashSet(); + while ( theTokenizer.hasMoreTokens() ) + { + theData.add( theTokenizer.nextToken() ); + } + } + return theData; + } +} diff --git a/src/com/sun/apoc/daemon/localdatabase/StringDbt.java b/src/com/sun/apoc/daemon/localdatabase/StringDbt.java new file mode 100644 index 0000000..afd46da --- /dev/null +++ b/src/com/sun/apoc/daemon/localdatabase/StringDbt.java @@ -0,0 +1,70 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.localdatabase; + +import com.sleepycat.db.*; + +class StringDbt extends Dbt +{ + StringDbt() + { + set_flags( Db.DB_DBT_MALLOC ); + } + + StringDbt( final String inValue ) + { + setApocData( inValue ); + set_flags( Db.DB_DBT_MALLOC ); + } + + void setApocData( final String inValue ) + { + final byte[] theData = inValue.getBytes(); + set_data( theData ); + set_size( theData.length ); + } + + String getApocData() + { + String theData = null; + int theSize = get_size(); + + if ( theSize > 0 ) + { + theData = new String( get_data(), get_offset(), theSize ); + } + return theData; + } +} diff --git a/src/com/sun/apoc/daemon/localdatabase/Timestamp.java b/src/com/sun/apoc/daemon/localdatabase/Timestamp.java new file mode 100644 index 0000000..7faff34 --- /dev/null +++ b/src/com/sun/apoc/daemon/localdatabase/Timestamp.java @@ -0,0 +1,108 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.localdatabase; + +import java.util.*; + +public class Timestamp +{ + private static final TimeZone sUTC = TimeZone.getTimeZone( "UTC" ); + + public static final String sEpoch = "19700101000000Z"; + public static final long sEpochMillis = 0; + + public static String getTimestamp() + { + StringBuffer theBuffer = new StringBuffer( 15 ); + Calendar theCalendar = Calendar.getInstance( sUTC ); + theBuffer.append( theCalendar.get( Calendar.YEAR ) ); + padAppend( theBuffer, theCalendar.get( Calendar.MONTH ) + 1 ); + padAppend( theBuffer, theCalendar.get( Calendar.DAY_OF_MONTH ) ); + padAppend( theBuffer, theCalendar.get( Calendar.HOUR_OF_DAY ) ); + padAppend( theBuffer, theCalendar.get( Calendar.MINUTE ) ); + padAppend( theBuffer, theCalendar.get( Calendar.SECOND ) ); + theBuffer.append( "Z" ); + return theBuffer.toString(); + } + + public static String getTimestamp( long inMillis ) + { + StringBuffer theBuffer = new StringBuffer( 15 ); + Calendar theCalendar = Calendar.getInstance( sUTC ); + theCalendar.setTimeInMillis( inMillis ); + theBuffer.append( theCalendar.get( Calendar.YEAR ) ); + padAppend( theBuffer, theCalendar.get( Calendar.MONTH ) + 1 ); + padAppend( theBuffer, theCalendar.get( Calendar.DAY_OF_MONTH ) ); + padAppend( theBuffer, theCalendar.get( Calendar.HOUR_OF_DAY ) ); + padAppend( theBuffer, theCalendar.get( Calendar.MINUTE ) ); + padAppend( theBuffer, theCalendar.get( Calendar.SECOND ) ); + theBuffer.append( "Z" ); + return theBuffer.toString(); + } + + public static long getMillis( String inTimestamp ) + { + if ( inTimestamp == null || inTimestamp.compareTo( sEpoch ) == 0 ) + { + return sEpochMillis; + } + Calendar theCalendar = Calendar.getInstance( sUTC ); + theCalendar.set( + Integer.parseInt( inTimestamp.substring( 0, 4 ) ), + Integer.parseInt( inTimestamp.substring( 4, 6 ) ) - 1, + Integer.parseInt( inTimestamp.substring( 6, 8 ) ), + Integer.parseInt( inTimestamp.substring( 8, 10 ) ), + Integer.parseInt( inTimestamp.substring( 10, 12 ) ), + Integer.parseInt( inTimestamp.substring( 12, 14 ) ) ); + return theCalendar.getTimeInMillis(); + } + + public static boolean isNewer( String inTimestamp1, String inTimestamp2 ) + { + String theTimestamp1 = inTimestamp1.substring( 0, 14 ); + String theTimestamp2 = inTimestamp2.substring( 0, 14 ); + return Long.parseLong( theTimestamp1 ) > + Long.parseLong( theTimestamp2 ); + } + + private static void padAppend( StringBuffer inBuffer, int inValue ) + { + if ( inValue < 10 ) + { + inBuffer.append( 0 ); + } + inBuffer.append( inValue ); + } +} diff --git a/src/com/sun/apoc/daemon/localdatabase/UpdateItem.java b/src/com/sun/apoc/daemon/localdatabase/UpdateItem.java new file mode 100755 index 0000000..f3045fd --- /dev/null +++ b/src/com/sun/apoc/daemon/localdatabase/UpdateItem.java @@ -0,0 +1,75 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.localdatabase; + +import com.sun.apoc.spi.policies.*; + +import java.util.*; + +public class UpdateItem +{ + public static final int NOCHANGE = 0; + public static final int ADD = 1; + public static final int REMOVE = 2; + public static final int MODIFY = 3; + + private int mUpdateType; + private final String mComponentName; + private final Policy[] mPolicies; + + public UpdateItem() + { + mComponentName = null; + mPolicies = null; + } + + public UpdateItem( int inUpdateType, + final String inComponentName, + final Policy[] inPolicies ) + { + mUpdateType = inUpdateType; + mComponentName = inComponentName; + mPolicies = inPolicies; + } + + public int getUpdateType() { return mUpdateType; } + public final String getComponentName() { return mComponentName; } + public final Policy[] getPolicies() { return mPolicies; } + + public void setUpdateType( int inUpdateType ) + { + mUpdateType = inUpdateType; + } +} diff --git a/src/com/sun/apoc/daemon/localdatabase/VectorStringDbt.java b/src/com/sun/apoc/daemon/localdatabase/VectorStringDbt.java new file mode 100644 index 0000000..5ea9394 --- /dev/null +++ b/src/com/sun/apoc/daemon/localdatabase/VectorStringDbt.java @@ -0,0 +1,109 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.localdatabase; + +import com.sleepycat.db.*; + +import java.util.*; + +class VectorStringDbt extends Dbt +{ + VectorStringDbt() + { + super() ; + set_flags(Db.DB_DBT_MALLOC) ; + } + + VectorStringDbt(final Vector inValue) + { + super() ; + fillData(inValue) ; + set_flags(Db.DB_DBT_MALLOC) ; + } + + private void fillData(final Vector inValue) + { + Iterator theIterator = inValue.iterator() ; + int theTotalLength = 0 ; + + while (theIterator.hasNext()) + { + theTotalLength += ((String) theIterator.next()).length() ; + ++ theTotalLength ; // The intermediate 0 + } + byte [] theData = new byte [theTotalLength] ; + int theCurrentIndex = 0 ; + + theIterator = inValue.iterator() ; + while (theIterator.hasNext()) + { + byte [] theSource = ((String) theIterator.next()).getBytes() ; + + for (int i = 0 ; i < theSource.length ; ++ i) + { + theData [theCurrentIndex ++] = theSource [i] ; + } + theData [theCurrentIndex ++] = 0 ; + } + set_data(theData) ; + set_size(theTotalLength) ; + } + + Vector retrieveData() + { + Vector theData = null ; + int theSize = get_size() ; + + if (theSize > 0) + { + int theStart = 0 ; + int theEnd = 0 ; + byte [] theArray = get_data() ; + + theData = new Vector() ; + do + { + while (theEnd < theSize && theArray [theEnd] != 0) + { + ++ theEnd ; + } + theData.add(new String(theArray, theStart, theEnd - theStart)) ; + ++ theEnd ; + theStart = theEnd ; + } while (theEnd < theSize) ; + } + return theData ; + } +} diff --git a/src/com/sun/apoc/daemon/messaging/AddListenerMessage.java b/src/com/sun/apoc/daemon/messaging/AddListenerMessage.java new file mode 100644 index 0000000..bfc203e --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/AddListenerMessage.java @@ -0,0 +1,133 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; +import java.util.*; + +public class AddListenerMessage extends Message +{ + private Vector mComponentNames; + private String mClientData; + private int[] mExpectedSymbols = { APOCSymbols.sSymParamSessionId, + APOCSymbols.sSymUnknown }; + private boolean mIsValid = false; + + public AddListenerMessage() + { + super( APOCSymbols.sSymReqAddListener ); + } + + public boolean isValid() + { + return mIsValid; + } + + public String getClientData() { return mClientData; } + public Vector getComponentNames() { return mComponentNames; } + + protected void addParameter( final String inName, final String inValue ) + throws APOCException + { + switch ( APOCSymbols.getProtocolSymbol( inName ) ) + { + case APOCSymbols.sSymParamSessionId: + addSessionId( inValue ); + break; + + case APOCSymbols.sSymParamClientData: + addClientData( inValue ); + break; + + case APOCSymbols.sSymParamComponentName: + addComponentName( inValue ); + break; + + default: + throw new APOCException(); + } + } + + private void addSessionId( final String inSessionId ) + throws APOCException + { + checkSymbol( APOCSymbols.sSymParamSessionId ); + mSessionId = inSessionId; + setCheckSymbols( APOCSymbols.sSymParamClientData, + APOCSymbols.sSymParamComponentName ); + } + + private void addClientData( final String inClientData ) + throws APOCException + { + checkSymbol( APOCSymbols.sSymParamClientData ); + mClientData = inClientData; + setCheckSymbols( APOCSymbols.sSymParamComponentName ); + } + + private void addComponentName( final String inComponentName ) + throws APOCException + { + checkSymbol( APOCSymbols.sSymParamComponentName ); + if ( mComponentNames == null ) + { + mComponentNames = new Vector(); + mIsValid = true; + } + mComponentNames.add( inComponentName ); + } + + private void checkSymbol( final int inSymbol ) + throws APOCException + { + if ( mExpectedSymbols[ 0 ] == APOCSymbols.sSymUnknown || + ( mExpectedSymbols[ 0 ] != inSymbol && + mExpectedSymbols[ 1 ] != inSymbol ) ) + { + throw new APOCException(); + } + } + + private void setCheckSymbols( final int inSymbol ) + { + setCheckSymbols( inSymbol, APOCSymbols.sSymUnknown ); + } + + private void setCheckSymbols( final int inSymbol1, final int inSymbol2 ) + { + mExpectedSymbols[ 0 ] = inSymbol1; + mExpectedSymbols[ 1 ] = inSymbol2; + } +} diff --git a/src/com/sun/apoc/daemon/messaging/CreateSessionExtMessage.java b/src/com/sun/apoc/daemon/messaging/CreateSessionExtMessage.java new file mode 100644 index 0000000..571c337 --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/CreateSessionExtMessage.java @@ -0,0 +1,111 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ + +package com.sun.apoc.daemon.messaging ; + +import java.util.Hashtable ; + +import com.sun.apoc.daemon.apocd.Client ; + +import com.sun.apoc.daemon.misc.APOCException ; +import com.sun.apoc.daemon.misc.APOCSymbols ; + +public class CreateSessionExtMessage extends Message + implements CredentialsProviderMessage { + private String mUserId = null ; + private String mCredentials = null ; + private Hashtable mEntities = new Hashtable() ; + private int mExpectedSymbol = APOCSymbols.sSymParamUserId ; + private String mLastEntityType = null ; + private boolean mIsValid = false ; + + public CreateSessionExtMessage() { + super(APOCSymbols.sSymReqCreateSessionExt) ; + } + public boolean isValid() { return mIsValid ; } + public String getUserId() { return mUserId ; } + public String getCredentials() { return mCredentials ; } + public Hashtable getEntities() { return mEntities ; } + + protected void addParameter(final String aName, + final String aValue) throws APOCException { + switch (APOCSymbols.getProtocolSymbol(aName)) { + case APOCSymbols.sSymParamUserId: + setUserId(aValue) ; + break ; + case APOCSymbols.sSymParamCredentials: + setCredentials(aValue) ; + break ; + case APOCSymbols.sSymParamEntityType: + setEntityType(aValue) ; + break ; + case APOCSymbols.sSymParamEntityId: + setEntityId(aValue) ; + } + } + private void setUserId(final String aUserId) throws APOCException { + checkState(APOCSymbols.sSymParamUserId) ; + mUserId = aUserId ; + mExpectedSymbol = APOCSymbols.sSymParamCredentials ; + } + private void setCredentials( + final String aCredentials) throws APOCException { + checkState(APOCSymbols.sSymParamCredentials) ; + mCredentials = aCredentials ; + mExpectedSymbol = APOCSymbols.sSymParamEntityType ; + } + private void setEntityType(final String aEntityType) throws APOCException { + try { checkState(APOCSymbols.sSymParamEntityType) ; } + catch (APOCException exception) { + // Allow for skipping credentials + if (mExpectedSymbol != APOCSymbols.sSymParamCredentials) { + throw exception ; + } + } + if (mEntities.contains(aEntityType)) { throw new APOCException() ; } + mLastEntityType = aEntityType ; + mExpectedSymbol = APOCSymbols.sSymParamEntityId ; + } + private void setEntityId(final String aEntityId) throws APOCException { + checkState(APOCSymbols.sSymParamEntityId) ; + mEntities.put(mLastEntityType, aEntityId) ; + mIsValid = true ; + mExpectedSymbol = APOCSymbols.sSymParamEntityType ; + } + private void checkState(final int aSymbol) throws APOCException { + if (aSymbol != mExpectedSymbol) { throw new APOCException() ; } + } +} + diff --git a/src/com/sun/apoc/daemon/messaging/CreateSessionMessage.java b/src/com/sun/apoc/daemon/messaging/CreateSessionMessage.java new file mode 100644 index 0000000..3b85514 --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/CreateSessionMessage.java @@ -0,0 +1,134 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; + +public class CreateSessionMessage extends Message + implements CredentialsProviderMessage +{ + private String mUserId; + private String mEntityId; + private String mCredentials; + private int[] mExpectedSymbols= { APOCSymbols.sSymParamUserId, + APOCSymbols.sSymUnknown }; + private boolean mIsValid = false; + + public CreateSessionMessage() + { + super( APOCSymbols.sSymReqCreateSession ); + } + + public boolean isValid() + { + return mIsValid; + } + + public String getUserId() { return mUserId; } + public String getEntityId() { return mEntityId; } + public String getCredentials() { return mCredentials; } + + protected void addParameter( final String inName, final String inValue ) + throws APOCException + { + switch ( APOCSymbols.getProtocolSymbol( inName ) ) + { + case APOCSymbols.sSymParamUserId: + addUserId( inValue ); + break; + + case APOCSymbols.sSymParamEntityId: + addEntityId( inValue ); + break; + + case APOCSymbols.sSymParamCredentials: + addCredentials( inValue ); + break; + + default: + throw new APOCException(); + } + } + + private void addUserId( final String inUserId ) + throws APOCException + { + checkSymbol( APOCSymbols.sSymParamUserId ); + mUserId = inUserId; + setCheckSymbols( APOCSymbols.sSymParamEntityId, + APOCSymbols.sSymParamCredentials ); + mIsValid = true; + } + + private void addEntityId( final String inEntityId ) + throws APOCException + { + checkSymbol( APOCSymbols.sSymParamEntityId ); + mEntityId = inEntityId; + setCheckSymbols( APOCSymbols.sSymParamCredentials ); + } + + private void addCredentials( final String inCredentials ) + throws APOCException + { + checkSymbol( APOCSymbols.sSymParamCredentials ); + mCredentials = inCredentials; + setCheckSymbols( APOCSymbols.sSymUnknown ); + } + + private void checkSymbol( final int inSymbol ) + throws APOCException + { + if ( mExpectedSymbols[ 0 ] == APOCSymbols.sSymUnknown || + ( mExpectedSymbols[ 0 ] != inSymbol && + mExpectedSymbols[ 1 ] != inSymbol ) ) + { + throw new APOCException(); + } + } + + private void setCheckSymbols( final int inSymbol ) + { + setCheckSymbols( inSymbol, + APOCSymbols.sSymUnknown ); + } + + private void setCheckSymbols( final int inSymbol1, + final int inSymbol2 ) + { + mExpectedSymbols[ 0 ] = inSymbol1; + mExpectedSymbols[ 1 ] = inSymbol2; + } +} diff --git a/src/com/sun/apoc/daemon/messaging/CredentialsProviderMessage.java b/src/com/sun/apoc/daemon/messaging/CredentialsProviderMessage.java new file mode 100644 index 0000000..1815090 --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/CredentialsProviderMessage.java @@ -0,0 +1,41 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ + +package com.sun.apoc.daemon.messaging ; + +public interface CredentialsProviderMessage { + public String getCredentials() ; +} + diff --git a/src/com/sun/apoc/daemon/messaging/DestroySessionMessage.java b/src/com/sun/apoc/daemon/messaging/DestroySessionMessage.java new file mode 100644 index 0000000..f136497 --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/DestroySessionMessage.java @@ -0,0 +1,65 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; + +public class DestroySessionMessage extends Message +{ + private boolean mIsValid = false; + + public DestroySessionMessage() + { + super( APOCSymbols.sSymReqDestroySession ); + } + + public boolean isValid() + { + return mIsValid; + } + + protected void addParameter( final String inName, final String inValue ) + throws APOCException + { + if ( APOCSymbols.getProtocolSymbol( inName ) != + APOCSymbols.sSymParamSessionId || + mSessionId != null ) + { + throw new APOCException(); + } + mSessionId = inValue; + mIsValid = true; + } +} diff --git a/src/com/sun/apoc/daemon/messaging/ListMessage.java b/src/com/sun/apoc/daemon/messaging/ListMessage.java new file mode 100644 index 0000000..78e65c8 --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/ListMessage.java @@ -0,0 +1,65 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; + +public class ListMessage extends Message +{ + private boolean mIsValid = false; + + public ListMessage() + { + super( APOCSymbols.sSymReqList ); + } + + public boolean isValid() + { + return mIsValid; + } + + protected void addParameter( final String inName, final String inValue ) + throws APOCException + { + if ( APOCSymbols.getProtocolSymbol( inName ) != + APOCSymbols.sSymParamSessionId || + mSessionId != null ) + { + throw new APOCException(); + } + mSessionId = inValue; + mIsValid = true; + } +} diff --git a/src/com/sun/apoc/daemon/messaging/Message.java b/src/com/sun/apoc/daemon/messaging/Message.java new file mode 100644 index 0000000..90f1a9e --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/Message.java @@ -0,0 +1,80 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; + +import java.nio.ByteBuffer; + +public abstract class Message +{ + protected int mName; + protected String mSessionId; + + public int getName() { return mName; } + public String getSessionId() { return mSessionId; } + + protected Message( final int inName ) + { + mName = inName; + } + + protected abstract void addParameter( String inName, String inValue ) + throws APOCException; + + public abstract boolean isValid(); + + private static final byte [] sBindingHeader = + APOCSymbols.sContentLength.getBytes() ; + private static final int sBindingHeaderLen = sBindingHeader.length ; + + public ByteBuffer serialise() + { + final byte [] theContent = toString().getBytes() ; + final byte [] theContentLength = + String.valueOf(theContent.length).getBytes() ; + + return (ByteBuffer) ByteBuffer.allocate(sBindingHeaderLen + + theContentLength.length + + 2 + // "\r\n" + theContent.length) + .put(sBindingHeader) + .put(theContentLength) + .put((byte) '\r') + .put((byte) '\n') + .put(theContent) + .flip() ; + } +} diff --git a/src/com/sun/apoc/daemon/messaging/MessageFactory.java b/src/com/sun/apoc/daemon/messaging/MessageFactory.java new file mode 100644 index 0000000..1f99e91 --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/MessageFactory.java @@ -0,0 +1,113 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; + +public class MessageFactory +{ + public static Message createRequest( final String inMessageName ) + throws APOCException + { + Message theMessage; + switch ( APOCSymbols.getProtocolSymbol( inMessageName ) ) + { + case APOCSymbols.sSymReqRead: + theMessage = new ReadMessage(); + break; + + case APOCSymbols.sSymReqList: + theMessage = new ListMessage(); + break; + + case APOCSymbols.sSymReqAddListener: + theMessage = new AddListenerMessage(); + break; + + case APOCSymbols.sSymReqCreateSession: + theMessage = new CreateSessionMessage(); + break; + + case APOCSymbols.sSymReqCreateSessionExt: + theMessage = new CreateSessionExtMessage(); + break; + + case APOCSymbols.sSymReqDestroySession: + theMessage = new DestroySessionMessage(); + break; + + case APOCSymbols.sSymReqRemoveListener: + theMessage = new RemoveListenerMessage(); + break; + + default: + throw new APOCException(); + } + return theMessage; + } + + public static Message createResponse( final int inResponseType, + final String inSessionId, + final String inResponseMessage ) + { + Message theMessage = null; + switch ( inResponseType ) + { + case APOCSymbols.sSymRespSuccess: + case APOCSymbols.sSymRespInvalidRequest: + case APOCSymbols.sSymRespConnectionFailure: + case APOCSymbols.sSymRespAuthenticationFailure: + case APOCSymbols.sSymRespInvalidSessionId: + case APOCSymbols.sSymRespNoSuchComponent: + case APOCSymbols.sSymRespUnknownFailure: + case APOCSymbols.sSymRespSuccessContinueLocalAuth: + case APOCSymbols.sSymRespSuccessContinueSASLAuth: + theMessage = new Response( inResponseType, + inSessionId, + inResponseMessage ); + break; + + default: + break; + } + return theMessage; + } + + public static Message createNotification( final String inSessionId, + int inType ) + { + return new Notification( inSessionId, inType ); + } +} diff --git a/src/com/sun/apoc/daemon/messaging/Messenger.java b/src/com/sun/apoc/daemon/messaging/Messenger.java new file mode 100644 index 0000000..874f0bf --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/Messenger.java @@ -0,0 +1,91 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transport.*; + +import java.io.*; + +public class Messenger +{ + private ClientChannel mClientChannel; + private RequestReceiver mRequestReceiver = new RequestReceiver(); + + public Messenger() + throws APOCException + { + } + + public void setClientChannel( final ClientChannel inClientChannel ) + { + mClientChannel = inClientChannel; + } + + public Message receiveRequest() + throws APOCException + { + return receiveRequest( true ); + } + + public Message receiveRequest( boolean inSetBusy ) + throws APOCException + { + return mRequestReceiver.receiveRequest( mClientChannel ); + } + + public void sendResponse( final Message inResponse ) + { + sendResponse( inResponse, true ); + } + + public void sendResponse( final Message inResponse, boolean inSetIdle ) + { + try + { + if ( inSetIdle ) + { + mClientChannel.registerForSelection( true ); + } + mClientChannel.write( inResponse.serialise() ); + } + catch( Exception theException ) + { + APOCLogger.finest( "Msgr001" ); + APOCLogger.throwing( "Messenger", "sendResponse", theException ); + } + } + +} diff --git a/src/com/sun/apoc/daemon/messaging/Notification.java b/src/com/sun/apoc/daemon/messaging/Notification.java new file mode 100644 index 0000000..3518041 --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/Notification.java @@ -0,0 +1,119 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; +import java.util.*; + +public class Notification extends Message +{ + private String mComponentName; + private String mClientData; + + public Notification( final String inSessionId, + int inType ) + { + super( inType ); + mSessionId = inSessionId; + } + + public boolean isValid() + { + return true; + } + + public void setComponentName( final String inComponentName ) + { + mComponentName = inComponentName; + } + + public void setClientData( final String inClientData ) + { + mClientData = inClientData; + } + + public String toString() + { + StringBuffer theBuffer = + new StringBuffer() + .append( "<" ) + .append( APOCSymbols.getProtocolString( mName ) ) + .append( ">" ) + + .append( "<" ) + .append( APOCSymbols.sParamSessionId ) + .append( ">" ) + + .append( mSessionId ) + + .append( "</" ) + .append( APOCSymbols.sParamSessionId ) + .append( ">"); + + if ( mClientData != null ) + { + theBuffer.append( "<" ) + .append( APOCSymbols.sParamClientData ) + .append( ">" ) + + .append( mClientData ) + + .append( "</" ) + .append( APOCSymbols.sParamClientData ) + .append( ">" ); + } + + theBuffer.append( "<" ) + .append( APOCSymbols.sParamComponentName ) + .append( ">" ) + + .append( mComponentName ) + + .append( "</" ) + .append( APOCSymbols.sParamComponentName ) + .append( ">" ) + + .append( "</" ) + .append( APOCSymbols.getProtocolString( mName ) ) + .append( ">" ); + return theBuffer.toString(); + } + + protected void addParameter( String inName, String inValue ) + throws APOCException + { + throw new APOCException(); + } +} diff --git a/src/com/sun/apoc/daemon/messaging/ProtocolDeserialiser.java b/src/com/sun/apoc/daemon/messaging/ProtocolDeserialiser.java new file mode 100644 index 0000000..607e1ef --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/ProtocolDeserialiser.java @@ -0,0 +1,72 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; + +import java.io.*; +import java.nio.charset.*; +import org.xml.sax.*; +import org.xml.sax.helpers.*; +import javax.xml.parsers.*; + +class ProtocolDeserialiser +{ + private InputStream mInputStream; + private final XMLReader mXMLReader; + private final ProtocolHandler mHandler = + new ProtocolHandler(); + private static final SAXParserFactory sSAXParserFactory = + SAXParserFactory.newInstance(); + + public ProtocolDeserialiser() + throws SAXException, ParserConfigurationException + { + mXMLReader = sSAXParserFactory.newSAXParser().getXMLReader(); + mXMLReader.setContentHandler( mHandler ); + } + + public void setInputStream( final InputStream inInputStream ) + { + mInputStream = inInputStream; + } + + public Message deserialise() + throws IOException, SAXException + { + mXMLReader.parse( new InputSource( mInputStream ) ); + return mHandler.getMessage(); + } +} diff --git a/src/com/sun/apoc/daemon/messaging/ProtocolHandler.java b/src/com/sun/apoc/daemon/messaging/ProtocolHandler.java new file mode 100644 index 0000000..20d77e2 --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/ProtocolHandler.java @@ -0,0 +1,103 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; +import org.xml.sax.*; +import org.xml.sax.helpers.*; + +class ProtocolHandler extends DefaultHandler +{ + private Message mMessage; + private String mCurrentParamName; + + public Message getMessage() + { + return mMessage; + } + + public void characters( final char[] inCharArray, final int inStart, final int inLength ) + throws SAXException + { + if ( mMessage == null ) + { + throw new SAXException( new APOCException() ); + } + + try + { + mMessage.addParameter( mCurrentParamName, + new String( inCharArray, inStart, inLength ) ); + } + catch ( APOCException theException ) + { + throw new SAXException( theException ); + } + } + + public void startDocument() + { + init(); + } + + public void startElement( final String inURI, + final String inName, + final String inQName, + final Attributes inAttributes ) + throws SAXException + { + if ( mMessage == null ) + { + try + { + mMessage = MessageFactory.createRequest( inQName ); + } + catch( APOCException theException ) + { + throw new SAXException( theException ); + } + } + else + { + mCurrentParamName = inQName; + } + } + + private void init() + { + mMessage = null; + mCurrentParamName = null; + } +} diff --git a/src/com/sun/apoc/daemon/messaging/ProtocolUnbinder.java b/src/com/sun/apoc/daemon/messaging/ProtocolUnbinder.java new file mode 100644 index 0000000..36eb9f6 --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/ProtocolUnbinder.java @@ -0,0 +1,206 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transport.*; + +import java.io.*; +import java.nio.*; + +class ProtocolUnbinder extends InputStream implements ConfigEventListener +{ + private ClientChannel mClientChannel; + private final ByteBuffer mInputBuffer = ByteBuffer.allocate( 1024 ); + private int mContentLength; + private final StringBuffer mContentLengthBuffer = + new StringBuffer( sContentLengthValueSize ); + private long mAvailableByteCount; + + private static int sMaxRequestLengthMinimum= 4096; + private static Integer sMaxRequestLength = + new Integer( sMaxRequestLengthMinimum ); + private static final byte[] sContentLengthHeader = + APOCSymbols.sContentLength.getBytes(); + private static final int sContentLengthValueSize = 5; + + static + { + setMaxRequestLength(); + } + + public ProtocolUnbinder() + { + DaemonConfig.addConfigEventListener( this ); + } + + public void setClientChannel( final ClientChannel inClientChannel ) + { + mClientChannel = inClientChannel; + mAvailableByteCount = 0; + } + + public void onConfigEvent() + { + setMaxRequestLength(); + } + + public int read() + throws IOException + { + int theByte = -1; + if ( mContentLength-- > 0 ) + { + theByte = ( int )getByte(); + } + return theByte; + } + + public int read( final byte[] outBytes, final int inOffset, final int inByteCount ) + throws IOException + { + int theByteCount = 0; + while ( mContentLength > 0 && theByteCount < inByteCount ) + { + outBytes[ inOffset + theByteCount++ ] = getByte(); + mContentLength--; + } + return theByteCount > 0 ? theByteCount : -1; + } + + public InputStream unbind() + throws APOCException, IOException + { + mContentLength = getContentLength(); + if ( mContentLength == 0 || mContentLength > getMaxRequestLength() ) + { + throw new APOCException( APOCSymbols.sSymRespInvalidRequest ); + } + return this; + } + + private byte getByte() + throws IOException + { + if ( mAvailableByteCount == 0 ) + { + mInputBuffer.clear(); + mAvailableByteCount = mClientChannel.read( mInputBuffer ); + mInputBuffer.flip(); + } + mAvailableByteCount--; + return mInputBuffer.get(); + } + + private int getContentLength() + throws IOException + { + return hasContentHeader() ? readContentLength() : 0; + } + + private int getMaxRequestLength() + { + synchronized( sMaxRequestLength ) + { + return sMaxRequestLength.intValue(); + } + } + + private boolean hasContentHeader() + throws IOException + { + boolean hasContentHeader = true; + for ( int theIndex = 0; + theIndex < sContentLengthHeader.length; + theIndex ++ ) + { + if ( getByte() != sContentLengthHeader[ theIndex ] ) + { + hasContentHeader = false; + break; + } + } + return hasContentHeader; + } + + private int readContentLength() + throws IOException + { + + mContentLengthBuffer.delete( 0, sContentLengthValueSize ); + byte theByte = 0; + for ( int theIndex = 0 ; + theIndex < sContentLengthValueSize ; + theIndex ++ ) + { + if ( ( theByte = getByte() ) == '\r' ) + { + break; + } + else + { + mContentLengthBuffer.append( ( char )theByte ); + } + } + if ( theByte != '\r' ) + { + getByte(); // skip '\r' + } + getByte(); // skip '\n' + return Integer.parseInt( mContentLengthBuffer.toString() ); + } + + private static void setMaxRequestLength() + { + synchronized( sMaxRequestLength ) + { + int theMaxRequestLength = + DaemonConfig.getIntProperty( DaemonConfig.sMaxRequestSize ); + if ( theMaxRequestLength < sMaxRequestLengthMinimum ) + { + String theRequestSizes[] = + { + String.valueOf( theMaxRequestLength ), + String.valueOf( sMaxRequestLengthMinimum ), + String.valueOf( sMaxRequestLengthMinimum ) + }; + APOCLogger.warning( "Punb001", theRequestSizes ); + theMaxRequestLength = sMaxRequestLengthMinimum; + } + sMaxRequestLength = new Integer( theMaxRequestLength ); + } + } +} diff --git a/src/com/sun/apoc/daemon/messaging/ReadMessage.java b/src/com/sun/apoc/daemon/messaging/ReadMessage.java new file mode 100644 index 0000000..e7399f2 --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/ReadMessage.java @@ -0,0 +1,109 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; +import java.util.*; + +public class ReadMessage extends Message +{ + private Vector mComponentNames; + private int mExpectedSymbol = APOCSymbols.sSymParamSessionId; + private boolean mIsValid = false; + + public ReadMessage() + { + super( APOCSymbols.sSymReqRead ); + } + + public boolean isValid() + { + return mIsValid; + } + + public Vector getComponentNames() { return mComponentNames; } + + protected void addParameter( final String inName, final String inValue ) + throws APOCException + { + switch ( APOCSymbols.getProtocolSymbol( inName ) ) + { + case APOCSymbols.sSymParamSessionId: + addSessionId( inValue ); + break; + + case APOCSymbols.sSymParamComponentName: + addComponentName( inValue ); + break; + + default: + throw new APOCException(); + } + } + + private void addSessionId( final String inSessionId ) + throws APOCException + { + checkSymbol( APOCSymbols.sSymParamSessionId ); + mSessionId = inSessionId; + setCheckSymbol( APOCSymbols.sSymParamComponentName ); + } + + private void addComponentName( final String inComponentName ) + throws APOCException + { + checkSymbol( APOCSymbols.sSymParamComponentName ); + if ( mComponentNames == null ) + { + mComponentNames = new Vector(); + mIsValid = true; + } + mComponentNames.add( inComponentName ); + } + + private void checkSymbol( final int inSymbol ) + throws APOCException + { + if ( mExpectedSymbol != inSymbol ) + { + throw new APOCException(); + } + } + + private void setCheckSymbol( final int inSymbol ) + { + mExpectedSymbol = inSymbol; + } +} diff --git a/src/com/sun/apoc/daemon/messaging/RemoveListenerMessage.java b/src/com/sun/apoc/daemon/messaging/RemoveListenerMessage.java new file mode 100644 index 0000000..d50fd0c --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/RemoveListenerMessage.java @@ -0,0 +1,109 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; +import java.util.*; + +public class RemoveListenerMessage extends Message +{ + private Vector mComponentNames; + private int mExpectedSymbol = APOCSymbols.sSymParamSessionId; + private boolean mIsValid = false; + + public RemoveListenerMessage() + { + super( APOCSymbols.sSymReqRemoveListener ); + } + + public boolean isValid() + { + return mIsValid; + } + + public Vector getComponentNames() { return mComponentNames; } + + protected void addParameter( final String inName, final String inValue ) + throws APOCException + { + switch ( APOCSymbols.getProtocolSymbol( inName ) ) + { + case APOCSymbols.sSymParamSessionId: + addSessionId( inValue ); + break; + + case APOCSymbols.sSymParamComponentName: + addComponentName( inValue ); + break; + + default: + throw new APOCException(); + } + } + + private void addSessionId( final String inSessionId ) + throws APOCException + { + checkSymbol( APOCSymbols.sSymParamSessionId ); + mSessionId = inSessionId; + setCheckSymbol( APOCSymbols.sSymParamComponentName ); + } + + private void addComponentName( final String inComponentName ) + throws APOCException + { + checkSymbol( APOCSymbols.sSymParamComponentName ); + if ( mComponentNames == null ) + { + mComponentNames = new Vector(); + mIsValid = true; + } + mComponentNames.add( inComponentName ); + } + + private void checkSymbol( final int inSymbol ) + throws APOCException + { + if ( mExpectedSymbol != inSymbol ) + { + throw new APOCException(); + } + } + + private void setCheckSymbol( final int inSymbol ) + { + mExpectedSymbol = inSymbol; + } +} diff --git a/src/com/sun/apoc/daemon/messaging/RequestReceiver.java b/src/com/sun/apoc/daemon/messaging/RequestReceiver.java new file mode 100644 index 0000000..0781793 --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/RequestReceiver.java @@ -0,0 +1,92 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; +import com.sun.apoc.daemon.transport.*; + +import java.io.*; + +class RequestReceiver +{ + private ProtocolUnbinder mUnbinder; + private ProtocolDeserialiser mDeserialiser; + + public RequestReceiver() + throws APOCException + { + try + { + mUnbinder = new ProtocolUnbinder(); + mDeserialiser = new ProtocolDeserialiser(); + } + catch ( org.xml.sax.SAXException theException ) + { + throw new APOCException( theException ); + } + catch ( javax.xml.parsers.ParserConfigurationException theException ) + { + throw new APOCException( theException ); + } + } + + public Message receiveRequest( final ClientChannel inClientChannel ) + throws APOCException + { + Message theMessage; + try + { + mUnbinder.setClientChannel( inClientChannel ); + mDeserialiser.setInputStream( mUnbinder.unbind() ); + theMessage = mDeserialiser.deserialise(); + if ( ! theMessage.isValid() ) + { + throw new APOCException( APOCSymbols.sSymRespInvalidRequest ); + } + } + catch ( org.xml.sax.SAXException theException ) + { + APOCLogger.throwing( "RequestReceiver", + "receiveRequest", + theException ); + throw new APOCException( theException ); + } + catch ( IOException theException ) + { + throw new APOCException( theException ); + } + return theMessage; + } +} diff --git a/src/com/sun/apoc/daemon/messaging/Response.java b/src/com/sun/apoc/daemon/messaging/Response.java new file mode 100644 index 0000000..3c8f2de --- /dev/null +++ b/src/com/sun/apoc/daemon/messaging/Response.java @@ -0,0 +1,109 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.messaging; + +import com.sun.apoc.daemon.misc.*; +import java.util.*; + +public class Response extends Message +{ + private String mBody; + + public Response( final int inResponseType, + final String inSessionId, + final String inResponseMessage ) + { + super( inResponseType ); + setBody( inResponseType, inSessionId, inResponseMessage ); + } + + public boolean isValid() + { + return true; + } + + protected void addParameter( final String inName, final String inValue ) + throws APOCException + { + throw new APOCException(); + } + + public String toString() + { + return mBody; + } + + private void setBody( final int inResponseType, + final String inSessionId, + final String inResponseMessage ) + { + final String theResponseType = + APOCSymbols.getProtocolString( inResponseType ); + + final StringBuffer theBuffer = new StringBuffer() + .append( "<" ) + .append( theResponseType ) + .append( ">" ) + + .append( "<" ) + .append( APOCSymbols.sParamSessionId ) + .append( ">" ) + + .append( inSessionId ) + + .append( "</" ) + .append( APOCSymbols.sParamSessionId ) + .append( ">"); + + if ( inResponseMessage != null ) + { + theBuffer.append( "<" ) + .append( APOCSymbols.sParamMessage ) + .append( ">") + + .append( inResponseMessage ) + + .append( "</" ) + .append( APOCSymbols.sParamMessage ) + .append( ">"); + } + + theBuffer.append( "</" ) + .append( theResponseType ) + .append( ">" ); + + mBody = theBuffer.toString(); + } +} diff --git a/src/com/sun/apoc/daemon/misc/APOCAuthenticator.java b/src/com/sun/apoc/daemon/misc/APOCAuthenticator.java new file mode 100644 index 0000000..b275830 --- /dev/null +++ b/src/com/sun/apoc/daemon/misc/APOCAuthenticator.java @@ -0,0 +1,169 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.misc; + +import com.sun.apoc.daemon.config.*; + +import java.io.*; +import java.util.*; + +public class APOCAuthenticator +{ + public static final File sAuthDir = + new File( + new StringBuffer( + DaemonConfig.getStringProperty( DaemonConfig.sDataDir ) ) + .append( File.separatorChar ) + .append( ".auth" ) + .toString() ); + + private File mFile; + private String mFileName; + private byte[] mResponse; + + private static final Random sRandom = new Random(); + private static int sAuthBufferSize = 20; + + public APOCAuthenticator( final String inUserId ) + throws APOCException + { + final String theUserId = + inUserId != null ? inUserId : "<Daemon administrator>"; + APOCLogger.finest( "Auth001", theUserId ); + try + { + createAuthFile( inUserId ); + createAuthToken(); + } + catch( Exception theException ) + { + cleanup(); + APOCLogger.finest( "Auth003" ); + throw new APOCException( theException ); + } + } + + public void cleanup() + { + try + { + if ( mFile != null ) + { + mFile.delete(); + mFile = null; + } + } + catch( Exception theException ) + {} + } + + public static int getAuthBufferSize() { return sAuthBufferSize; } + + public byte[] getChallenge() + { + return mFileName.getBytes(); + } + + public void processResponse( final byte[] inResponse ) + throws APOCException + { + try + { + if ( inResponse == null || inResponse.length != sAuthBufferSize ) + { + APOCLogger.finest( "Auth003" ); + throw new APOCException(); + } + for ( int theIndex = 0; theIndex < sAuthBufferSize; theIndex ++ ) + { + if ( mResponse[ theIndex ] != inResponse[ theIndex ] ) + { + APOCLogger.finest( "Auth003" ); + throw new APOCException(); + } + } + APOCLogger.finest( "Auth002" ); + } + finally + { + cleanup(); + } + } + + private void createAuthFile( final String inUserId ) + throws Exception + { + long thePrefix = sRandom.nextLong(); + thePrefix = thePrefix < 0 ? -thePrefix : thePrefix; + mFile = + File.createTempFile( String.valueOf( thePrefix ), null, sAuthDir ); + mFile.deleteOnExit(); + mFileName = mFile.getAbsolutePath(); + if ( inUserId != null ) + { + FileAccess.chown( mFileName, inUserId ); + } + FileAccess.chmod( mFileName, 0600 ); + } + + private void createAuthToken() + throws Exception + { + final FileOutputStream theOutputStream = + new FileOutputStream( mFileName ); + long theValue = sRandom.nextLong(); + theValue = theValue < 0 ? -theValue : theValue; + final StringBuffer theStringBuffer = + new StringBuffer().append( theValue ); + int theLength = theStringBuffer.length(); + if ( theLength > sAuthBufferSize ) + { + theStringBuffer.delete( sAuthBufferSize + 1, theLength ); + } + else + if ( theLength < sAuthBufferSize ) + { + int theExtraCharacters = sAuthBufferSize - theLength; + for ( int theIndex = 0; theIndex < theExtraCharacters; theIndex ++ ) + { + theStringBuffer.append( ( int )0 ); + } + } + mResponse = theStringBuffer.toString().getBytes(); + theOutputStream.write( mResponse ); + theOutputStream.close(); + } + +} diff --git a/src/com/sun/apoc/daemon/misc/APOCException.java b/src/com/sun/apoc/daemon/misc/APOCException.java new file mode 100644 index 0000000..b84033a --- /dev/null +++ b/src/com/sun/apoc/daemon/misc/APOCException.java @@ -0,0 +1,98 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.misc; + +import com.sun.apoc.spi.*; + +public class APOCException extends Exception +{ + private int mCode = APOCSymbols.sSymRespUnknownFailure; + + public APOCException(){} + + public APOCException( final int inCode ) + { + this( inCode, null ); + } + + public APOCException( final Throwable inThrowable ) + { + this( APOCSymbols.sSymRespUnknownFailure, inThrowable ); + mCode = getCode( inThrowable ); + } + + public APOCException( final int inCode, final Throwable inThrowable ) + { + super( inThrowable ); + mCode = inCode; + } + + public int getCode() { return mCode; } + + private int getCode( final Throwable inThrowable ) + { + int theCode = APOCSymbols.sSymRespUnknownFailure; + if ( inThrowable != null ) + { + if ( inThrowable instanceof SPIException ) + { + theCode = getCode( ( SPIException )inThrowable ); + } + } + return theCode; + } + + private int getCode( final SPIException inException ) + { + int theCode = APOCSymbols.sSymRespUnknownFailure; + final String theStringCode = + inException.getLocalizedErrorMessageCode(); + if ( theStringCode != null ) + { + if ( theStringCode.compareTo( + SPIException.ERROR_OPEN_CONNECTION ) == 0 ) + { + theCode = APOCSymbols.sSymRespConnectionFailure; + } + else + if ( theStringCode.compareTo( + SPIException.ERROR_USER_INVALID ) == 0 ) + { + theCode = APOCSymbols.sSymRespAuthenticationFailure; + } + } + return theCode; + } +} diff --git a/src/com/sun/apoc/daemon/misc/APOCLogger.java b/src/com/sun/apoc/daemon/misc/APOCLogger.java new file mode 100644 index 0000000..cab6c00 --- /dev/null +++ b/src/com/sun/apoc/daemon/misc/APOCLogger.java @@ -0,0 +1,227 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.misc; + +import com.sun.apoc.daemon.config.*; + +import java.io.*; +import java.util.*; +import java.util.logging.*; + +public class APOCLogger +{ + private static final String sLoggerName = "com.sun.apoc.daemon"; + private static final String sLogDir = "/Logs"; + private static final String sLogFile = "/apocd.log"; + private static final Logger sLogger = + ConfigurableLogger.getLogger( sLoggerName, sLoggerName ); + private static final int sLimit = 1000000; + private static final int sCount = 5; + + static + { + try + { + final Handler theHandler = + createHandler( + DaemonConfig.getStringProperty( DaemonConfig.sDataDir ) ); + final Level theLevel = + Level.parse( + DaemonConfig.getStringProperty( DaemonConfig.sLogLevel ) ); + theHandler.setLevel( theLevel ); + theHandler.setFormatter( new SimpleFormatter() ); + + sLogger.addHandler( theHandler ); + sLogger.setLevel( theLevel ); + } + catch( Exception theException ) + { + theException.printStackTrace(); + } + } + + public static void config( final String inKey ) + { + sLogger.log( Level.CONFIG, inKey ); + } + + public static void config( final String inKey, final Object inParam ) + { + sLogger.log( Level.CONFIG, inKey, inParam ); + } + + public static void fine( final String inKey ) + { + sLogger.log( Level.FINE, inKey ); + } + + public static void fine( final String inKey, final Object inParam ) + { + sLogger.log( Level.FINE, inKey, inParam ); + } + + public static void finer( final String inKey ) + { + sLogger.log( Level.FINER, inKey ); + } + + public static void finer( final String inKey, final Object inParam ) + { + sLogger.log( Level.FINER, inKey, inParam ); + } + + public static void finest( final String inKey ) + { + sLogger.log( Level.FINEST, inKey ); + } + + public static void finest( final String inKey, final Object inParam ) + { + sLogger.log( Level.FINEST, inKey, inParam ); + } + + public static boolean isLoggable( final Level inLevel ) + { + return sLogger.isLoggable( inLevel ); + } + + public static void info( final String inKey ) + { + sLogger.log( Level.INFO, inKey ); + } + + public static void info( final String inKey, final Object inParam ) + { + sLogger.log( Level.INFO, inKey, inParam ); + } + + public static void severe( final String inKey ) + { + sLogger.log( Level.SEVERE, inKey ); + } + + public static void severe( final String inKey, final Object inParam ) + { + sLogger.log( Level.SEVERE, inKey, inParam ); + } + + public static void throwing( final String inClass, + final String inMethod, + final Throwable inThrowable ) + { + sLogger.throwing( inClass, inMethod, inThrowable ); + } + + public static void warning( final String inKey ) + { + sLogger.log( Level.WARNING, inKey ); + } + + public static void warning( final String inKey, final Object inParam ) + { + sLogger.log( Level.WARNING, inKey, inParam ); + } + + public static void warning( final String inKey, final Object[] inParams ) + { + sLogger.log( Level.WARNING, inKey, inParams ); + } + + private static Handler createHandler( final String inDataDir ) + { + Handler theHandler; + if ( needFileHandler() && inDataDir != null ) + { + final String theLogDir = + new StringBuffer( inDataDir ).append( sLogDir ).toString(); + createLogDir( theLogDir ); + try + { + theHandler = + new FileHandler( + new StringBuffer( theLogDir ) + .append( sLogFile ) + .toString(), + sLimit, + sCount, + true ); + } + catch( Exception theException ) + { + System.err.println("Warning:Failed to create log file handler"); + theHandler = new ConsoleHandler(); + } + } + else + { + theHandler = new ConsoleHandler(); + } + return theHandler; + } + + private static void createLogDir( final String inLogDir ) + { + final File theFile = new File( inLogDir ); + if ( ! theFile.exists() ) + { + if ( ! theFile.mkdirs() ) + { + System.err.println( "Warning: Cannot create Log directory '" + + inLogDir + "'" ); + } + } + else + { + if ( ! theFile.isDirectory() ) + { + System.err.println( "Warning: Log directory '" + + inLogDir + + "' is actually a file" ); + } + } + } + + private static boolean needFileHandler() + { + boolean needsFileHandler = false; + final String theHandler = DaemonConfig.getStringProperty( "handlers" ); + if ( theHandler == null || + theHandler.compareTo( "java.util.logging.FileHandler" ) == 0 ) + { + needsFileHandler = true; + } + return needsFileHandler; + } +} diff --git a/src/com/sun/apoc/daemon/misc/APOCSymbols.java b/src/com/sun/apoc/daemon/misc/APOCSymbols.java new file mode 100644 index 0000000..8e09528 --- /dev/null +++ b/src/com/sun/apoc/daemon/misc/APOCSymbols.java @@ -0,0 +1,246 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.misc; + +import java.util.*; + +public class APOCSymbols +{ + public static final int sSymUnknown = 0; + + + // Protocol Stuff + // Binding + public static final String sContentLength = "CONTENT-LENGTH:"; + + public static final int sSymContentLength = 1; + + // Message Names - Requests + public static final String sReqAddListener = "addListener"; + public static final String sReqCreateSession = "createSession"; + public static final String sReqDestroySession = "destroySession"; + public static final String sReqList = "list"; + public static final String sReqRead = "read"; + public static final String sReqRemoveListener = "removeListener"; + public static final String sReqCreateSessionExt = "createSessionExt"; + + public static final int sSymReqAddListener = 11; + public static final int sSymReqCreateSession = 12; + public static final int sSymReqDestroySession = 13; + public static final int sSymReqList = 14; + public static final int sSymReqRead = 15; + public static final int sSymReqRemoveListener = 16; + public static final int sSymReqCreateSessionExt = 17; + + // Message Names - Responses + public static final String sRespSuccess = "success"; + public static final String sRespInvalidRequest = + "invalidRequest"; + public static final String sRespConnectionFailure = + "connectionFailure"; + public static final String sRespAuthenticationFailure = + "authenticationFailure"; + public static final String sRespInvalidSessionId = + "invalidSessionId"; + public static final String sRespNoSuchComponent = + "noSuchComponent"; + public static final String sRespUnknownFailure = + "unknownFailure"; + public static final String sRespSuccessContinueLocalAuth = + "successContinueLocalAuth"; + public static final String sRespSuccessContinueSASLAuth = + "successContinueSASLAuth"; + + public static final int sSymRespSuccess = 20; + public static final int sSymRespInvalidRequest = 21; + public static final int sSymRespConnectionFailure = 22; + public static final int sSymRespAuthenticationFailure = 23; + public static final int sSymRespInvalidSessionId = 24; + public static final int sSymRespNoSuchComponent = 25; + public static final int sSymRespUnknownFailure = 26; + public static final int sSymRespSuccessContinueLocalAuth= 27; + public static final int sSymRespSuccessContinueSASLAuth = 28; + + // Message Names - Notification + public static final String sAddNotification = "addNotification"; + public static final String sRemoveNotification = "removeNotification"; + public static final String sModifyNotification = "modifyNotification"; + + public static final int sSymAddNotification = 30; + public static final int sSymRemoveNotification = 31; + public static final int sSymModifyNotification = 32; + + // Message Parameters + public static final String sParamUserId = "userId"; + public static final String sParamEntityId = "entityId"; + public static final String sParamCredentials = "credentials"; + public static final String sParamSessionId = "sessionId"; + public static final String sParamComponentName = "componentName"; + public static final String sParamClientData = "clientData"; + public static final String sParamMessage = "message"; + public static final String sParamVersion = "version"; + public static final String sParamServer = "server"; + public static final String sParamAuthType = "authType"; + public static final String sParamLayer = "layer"; + public static final String sParamEntityType = "entityType"; + + public static final int sSymParamUserId = 40; + public static final int sSymParamEntityId = 41; + public static final int sSymParamCredentials = 42; + public static final int sSymParamSessionId = 43; + public static final int sSymParamComponentName = 44; + public static final int sSymParamClientData = 45; + public static final int sSymParamMessage = 46; + public static final int sSymParamVersion = 47; + public static final int sSymParamServer = 48; + public static final int sSymParamAuthType = 49; + public static final int sSymParamLayer = 50; + public static final int sSymParamEntityType = 51; + + // Misc + public static final String sDBCreateFailed = + "Failed to create a db handle"; + public static final String sDBEnvCreateFailed = + "Failed to create a db environment handle"; + public static final String sCreateServerChannelFailed = + "Failed to create a server channel"; + + public static final int sSymDBCreateFailed = 60; + public static final int sSymDBEnvCreateFailed = 61; + public static final int sSymCreateServerChannelFailed = 62; + + private static final Hashtable sProtocolSyms = new Hashtable(); + private static final Hashtable sProtocolStrs = new Hashtable(); + + static + { + addEntries( sContentLength, + new Integer( sSymContentLength ) ); + addEntries( sReqAddListener, + new Integer( sSymReqAddListener ) ); + addEntries( sReqCreateSession, + new Integer( sSymReqCreateSession ) ); + addEntries( sReqDestroySession, + new Integer( sSymReqDestroySession ) ); + addEntries( sReqList, + new Integer( sSymReqList ) ); + addEntries( sReqRead, + new Integer( sSymReqRead ) ); + addEntries( sReqRemoveListener, + new Integer( sSymReqRemoveListener ) ); + addEntries( sReqCreateSessionExt, + new Integer( sSymReqCreateSessionExt ) ); + addEntries( sRespSuccess, + new Integer( sSymRespSuccess ) ); + addEntries( sRespInvalidRequest, + new Integer( sSymRespInvalidRequest ) ); + addEntries( sRespConnectionFailure, + new Integer( sSymRespConnectionFailure ) ); + addEntries( sRespAuthenticationFailure, + new Integer( sSymRespAuthenticationFailure ) ); + addEntries( sRespInvalidSessionId, + new Integer( sSymRespInvalidSessionId ) ); + addEntries( sRespNoSuchComponent, + new Integer( sSymRespNoSuchComponent ) ); + addEntries( sRespUnknownFailure, + new Integer( sSymRespUnknownFailure ) ); + addEntries( sRespSuccessContinueLocalAuth, + new Integer( sSymRespSuccessContinueLocalAuth ) ); + addEntries( sRespSuccessContinueSASLAuth, + new Integer( sSymRespSuccessContinueSASLAuth ) ); + addEntries( sAddNotification, + new Integer( sSymAddNotification ) ); + addEntries( sRemoveNotification, + new Integer( sSymRemoveNotification ) ); + addEntries( sModifyNotification, + new Integer( sSymModifyNotification ) ); + addEntries( sParamUserId, + new Integer( sSymParamUserId ) ); + addEntries( sParamEntityId, + new Integer( sSymParamEntityId ) ); + addEntries( sParamCredentials, + new Integer( sSymParamCredentials ) ); + addEntries( sParamSessionId, + new Integer( sSymParamSessionId ) ); + addEntries( sParamComponentName, + new Integer( sSymParamComponentName ) ); + addEntries( sParamClientData, + new Integer( sSymParamClientData ) ); + addEntries( sParamMessage, + new Integer( sSymParamMessage ) ); + addEntries( sParamVersion, + new Integer( sSymParamVersion ) ); + addEntries( sParamServer, + new Integer( sSymParamServer ) ); + addEntries( sParamAuthType, + new Integer( sSymParamAuthType ) ); + addEntries( sParamLayer, + new Integer( sSymParamLayer ) ); + addEntries( sParamEntityType, + new Integer( sSymParamEntityType ) ); + addEntries( sDBCreateFailed, + new Integer( sSymDBCreateFailed ) ); + addEntries( sDBEnvCreateFailed, + new Integer( sSymDBEnvCreateFailed ) ); + addEntries( sCreateServerChannelFailed, + new Integer( sSymCreateServerChannelFailed ) ); + } + + private static void addEntries( final String inProtocolString, + final Integer inProtocolSymbol ) + { + sProtocolSyms.put( inProtocolString, inProtocolSymbol ); + sProtocolStrs.put( inProtocolSymbol, inProtocolString ); + } + + public static int getProtocolSymbol( final String inString ) + { + int theSym = sSymUnknown; + if ( inString != null ) + { + final Integer theValue = ( Integer )sProtocolSyms.get( inString ); + if ( theValue != null ) + { + theSym = theValue.intValue(); + } + } + return theSym; + } + + public static String getProtocolString( final int inSymbol ) + { + return ( String )sProtocolStrs.get( new Integer( inSymbol ) ); + } +} diff --git a/src/com/sun/apoc/daemon/misc/ConfigurableLogger.java b/src/com/sun/apoc/daemon/misc/ConfigurableLogger.java new file mode 100644 index 0000000..8753741 --- /dev/null +++ b/src/com/sun/apoc/daemon/misc/ConfigurableLogger.java @@ -0,0 +1,72 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.misc; + +import com.sun.apoc.daemon.config.*; + +import java.util.logging.*; + +public class ConfigurableLogger extends Logger + implements ConfigEventListener +{ + protected ConfigurableLogger( String inLoggerName, + String inResourceBundleName ) + { + super( inLoggerName, inResourceBundleName ); + DaemonConfig.addConfigEventListener( this ); + } + + public static Logger getLogger( String inLoggerName, + String inResourceBundleName ) + { + return new ConfigurableLogger( inLoggerName, inResourceBundleName); + } + + public void onConfigEvent() + { + final Level theLevel = + Level.parse( + DaemonConfig.getStringProperty( DaemonConfig.sLogLevel ) ); + setLevel( theLevel ); + final Handler[] theHandlers = getHandlers(); + if ( theHandlers != null ) + { + for ( int theIndex = 0; theIndex < theHandlers.length; ++ theIndex ) + { + theHandlers[ theIndex ].setLevel( theLevel ); + } + } + } +} diff --git a/src/com/sun/apoc/daemon/misc/DaemonTimerTask.java b/src/com/sun/apoc/daemon/misc/DaemonTimerTask.java new file mode 100644 index 0000000..312bfa5 --- /dev/null +++ b/src/com/sun/apoc/daemon/misc/DaemonTimerTask.java @@ -0,0 +1,110 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.misc; + +import java.util.*; + +public class DaemonTimerTask +{ + private Runnable mRunnable; + private long mPeriod = 0; + private TimerTask mTimerTask = null; + private boolean mIsOneTime = false; + private static final Timer sTimer = new Timer( true ); + + public DaemonTimerTask( final Runnable inRunnable ) + { + mRunnable = inRunnable; + } + + public DaemonTimerTask( final Runnable inRunnable, boolean inIsOneTime ) + { + this( inRunnable ); + mIsOneTime = inIsOneTime; + } + + public void cancel() + { + setPeriod( -1 ); + } + + public long getPeriod() + { + return mPeriod; + } + + public boolean setPeriod( long inPeriod ) + { + boolean isChanged = false; + if ( inPeriod != mPeriod ) + { + mPeriod = inPeriod; + schedule(); + isChanged = true; + } + return isChanged; + } + + private void schedule() + { + if ( mPeriod > 0 ) + { + if ( mTimerTask != null ) + { + mTimerTask.cancel(); + } + mTimerTask = new Task(); + sTimer.schedule( mTimerTask, mPeriod, mPeriod ); + } + else + if ( mTimerTask != null ) + { + mTimerTask.cancel(); + mTimerTask = null; + } + } + + class Task extends TimerTask + { + public void run() + { + mRunnable.run(); + if ( mIsOneTime ) + { + cancel(); + } + } + } +} diff --git a/src/com/sun/apoc/daemon/misc/FileAccess.java b/src/com/sun/apoc/daemon/misc/FileAccess.java new file mode 100644 index 0000000..f3b3b02 --- /dev/null +++ b/src/com/sun/apoc/daemon/misc/FileAccess.java @@ -0,0 +1,42 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.misc; + +public class FileAccess +{ + public static native int chmod( final String inFileName, int inMode ); + public static native int chown( final String inFileName, + final String inUserName ); +} diff --git a/src/com/sun/apoc/daemon/misc/Name.java b/src/com/sun/apoc/daemon/misc/Name.java new file mode 100644 index 0000000..cc5f9be --- /dev/null +++ b/src/com/sun/apoc/daemon/misc/Name.java @@ -0,0 +1,128 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.misc; + +public class Name +{ + // Location + private static int sLocationLocal = 0; + private static int sLocationGlobal = 1; + + // Applicability + private static int sApplicabilityHost = 2; + private static int sApplicabilityUser = 3; + + // Entities + private static int sEntityLocalHost = 4; + private static int sEntityLocalUser = 5; + + private static int sUndefined = 6; + + private static final String sLocationLocalStr = "local"; + private static final String sLocationGlobalStr = "global"; + private static final String sApplicabilityHostStr = "host"; + private static final String sApplicabilityUserStr = "user"; + public static final String sEntityLocalHostStr = "localHost"; + public static final String sEntityLocalUserStr = "localUser"; + + public static final String sSep = "/"; + + public static final String sNames[] = + { + sLocationLocalStr, + sLocationGlobalStr, + sApplicabilityHostStr, + sApplicabilityUserStr, + sEntityLocalHostStr, + sEntityLocalUserStr + }; + + private String mUserName; + private String mEntityType; + private String mEntityName; + private boolean mIsLocal; + + public Name( final String inUserName, + final String inEntityType, + final String inEntityName, + boolean inIsLocal ) + { + mUserName = inUserName; + mEntityType = inEntityType; + mEntityName = inEntityName; + mIsLocal = inIsLocal; + } + public Name( final String inUserName, + final String inEntityType, + final String inEntityName, + final String inIsLocal ) + { + mUserName = inUserName ; + mEntityType = inEntityType ; + mEntityName = inEntityName ; + mIsLocal = inIsLocal.compareTo(sLocationLocalStr) == 0 ; + } + + public String getUserName() { return mUserName; } + + public String getEntityType() { return mEntityType; } + + public String getEntityName() { return mEntityName; } + + public String getLocation() + { + return sNames[ getLocationAsInt() ]; + } + + public int getLocationAsInt() + { + return mIsLocal ? sLocationLocal : sLocationGlobal; + } + + public boolean isLocal() { return mIsLocal; } + public boolean isGlobal() { return ! isLocal(); } + + public String toString() + { + return new StringBuffer(mUserName) + .append(sSep) + .append(mEntityType) + .append(sSep) + .append(mEntityName) + .append(sSep) + .append(getLocation()) + .toString() ; + } +} diff --git a/src/com/sun/apoc/daemon/properties/apocd.properties b/src/com/sun/apoc/daemon/properties/apocd.properties new file mode 100644 index 0000000..bdb350f --- /dev/null +++ b/src/com/sun/apoc/daemon/properties/apocd.properties @@ -0,0 +1,66 @@ +# +# The port used by the APOC daemon for client requests +# +#DaemonPort=3809 + +# +# The maximum number of client threads dictates the number of client requests +# which may be executed simultaneously. +# +#MaxClientThreads=5 + +# +# The maximum number of client connections allowed +# +#MaxClientConnections=50 + +# +# The maximum size of requests issued by clients +# +#MaxRequestSize=4096 + +# +# The interval ( in minutes ) between change detections for daemon config. +# data +# +#DaemonChangeDetectionInterval=10 + +# +# The interval ( in minutes ) between change detection for the local database +# +#ChangeDetectionInterval=60 + +# +# The delay ( in seconds ) between a user session creation and an initial +# change detection for that user ( if one is due ) +# +#InitialChangeDetectionDelay=10 + +# +# The local database garbage collection interval ( in minutes ) +# +#GarbageCollectionInterval=10080 + +# +# The length of time ( in minutes ) since last read, which non offline +# components will remain in the local database +# +#TimeToLive=10080 + +# +# Daemon Log level +# +#LogLevel=INFO + +# +# Whether or not local policy should be applied ( if available ) +#ApplyLocalPolicy=true + +# +# The number of seconds after which an uncompleted transaction will be +# cancelled. A minimum value of 1 second is imposed. +#TransactionTimeout=15 + +# +# The maximum number of Berkeley DB locks available +#MaxDatabaseLocks=12000 diff --git a/src/com/sun/apoc/daemon/properties/daemon.properties b/src/com/sun/apoc/daemon/properties/daemon.properties new file mode 100644 index 0000000..2d54129 --- /dev/null +++ b/src/com/sun/apoc/daemon/properties/daemon.properties @@ -0,0 +1,82 @@ +#com.sun.apoc.daemon.admin.AdminManager +Admr001=Admin manager started +Admr002=Admin manager stopped + +#com.sun.apoc.daemon.apocd.ClientManager +Clmr001=Client manager started +Clmr002=Client removed +Clmr003=Failed to resize thread pool +Clmr004=Change detection scheduled ( interval = {0} minutes ) +Clmr005=New client added +Clmr006=Change detection switched off +Clmr007=Client manager stopped + +#com.sun.apoc.daemon.apocd.Daemon +Dmon001=Daemon starting +Dmon002=Daemon finishing +Dmon003=Garbage collection scheduled ( interval = {0} minutes ) +Dmon004=Garbage collection switched off + +#com.sun.apoc.daemon.apocd.Session +Sess001=Creating new client session +Sess002=New client session created:\n{0}\n +Sess003=Client session ( sessionId = {0} ) closed + +#com.sun.apoc.daemon.config.DaemonConfig +Dcfg001=Daemon configuration:\n{0}\n + +#com.sun.apoc.daemon.messaging.Messenger +Msgr001=Failed to send response + +#com.sun.apoc.daemon.messaging.ProtocolUnbinder +Punb001=Configured value of MaxRequestSize, {0}, is less than the minimum allowed value ( {1} ). Adjusting MaxRequestsize to {1}. + +#com.sun.apoc.daemon.misc.APOCAuthenticator +Auth001=Authenticating user {0} +Auth002=Authentication successful +Auth003=Authentication failed + +#com.sun.apoc.daemon.transaction.AddListenerTransaction +Altn001=AddListener transaction started +Altn002=AddListener transaction completed + +#com.sun.apoc.daemon.transaction.ChangeDetectTransaction +Cdtn001=ChangeDetect transaction started +Cdtn002=ChangeDetect transaction completed +Cdtn003=Notification sent:\n{0}\n + +#com.sun.apoc.daemon.transaction.CreateSessionTransaction +Cstn001=CreateSession transaction started +Cstn002=CreateSession transaction completed + +#com.sun.apoc.daemon.transaction.DestroySessionTransaction +Dstn001=DestroySession transaction started +Dstn002=DestroySession transaction completed + +#com.sun.apoc.daemon.transaction.GarbageCollectTransaction +Gctn001=GarbageCollect transaction started +Gctn002=GarbageCollect transaction completed + +#com.sun.apoc.daemon.transaction.ListTransaction +Lstn001=List transaction started +Lstn002=List transaction completed + +#com.sun.apoc.daemon.transaction.ReadTransaction +Rdtn001=Read transaction started +Rdtn002=Read transaction completed + +#com.sun.apoc.daemon.transaction.RemoveListenerTransaction +Rltn001=RemoveListener transaction started +Rltn002=RemoveListener transaction completed + +#com.sun.apoc.daemon.transport.ChannelManager +Chmr001=Channel manager started +Chmr002=The maximum number of client connections ( {0} ) has been reached. No new client connections can be established at this time. +Chmr003=Channel manager stopped + +#com.sun.apoc.daemon.transport.ClientChannel +Clch001=Error while changing channel state ... closing channel +Clch002=Unexpected EOF while reading client channel + +#com.sun.apoc.daemon.transport.ServerChannel +Svch001=Error while accepting new client channel diff --git a/src/com/sun/apoc/daemon/properties/defaults.properties b/src/com/sun/apoc/daemon/properties/defaults.properties new file mode 100644 index 0000000..ae78be6 --- /dev/null +++ b/src/com/sun/apoc/daemon/properties/defaults.properties @@ -0,0 +1,83 @@ +# +# The port used by the APOC daemon for client requests +# +DaemonPort=3809 + +# +# The maximum number of client threads dictates the number of client requests +# which may be executed simultaneously. +# +MaxClientThreads=5 + +# +# The maximum number of client connections allowed +# +MaxClientConnections=50 + +# +# The maximum size of requests issued by clients +# +MaxRequestSize=4096 + +# +# The interval ( in minutes ) between change detections for daemon config. +# data +# +DaemonChangeDetectionInterval=10 + +# +# The interval ( in minutes ) between change detection for the local database +# +ChangeDetectionInterval=60 + +# +# The delay ( in seconds ) between a user session creation and an initial +# change detection for that user ( if one is due ) +# +InitialChangeDetectionDelay=10 + +# +# The local database garbage collection interval ( in minutes ) +# +GarbageCollectionInterval=10080 + +# +# The length of time ( in minutes ) since last read, which non offline +# components will remain in the local database +# +TimeToLive=10080 + +# +# The interval ( in minutes ) between detection and removal of idle threads +# +IdleThreadDetectionInterval=15 + +# +# The length of time ( in minutes ) a thread may remain idle before being +# removed +# +ThreadTimeToLive=5 + +# +# The length of time ( in milliseconds ) to wait before timing out a read on +# client connections +# +ConnectionReadTimeout=5000 + +# +# Daemon Log level +# +LogLevel=INFO + +# +# Whether or not local policy should be applied ( if available ) +ApplyLocalPolicy=true + +# +# The number of seconds after which an uncompleted transaction will be +# cancelled. A minimum value of 1 second is imposed. +TransactionTimeout=15 + +# +# The maximum number of Berkeley DB locks available +MaxDatabaseLocks=12000 diff --git a/src/com/sun/apoc/daemon/properties/os.properties.in b/src/com/sun/apoc/daemon/properties/os.properties.in new file mode 100644 index 0000000..b7e1485 --- /dev/null +++ b/src/com/sun/apoc/daemon/properties/os.properties.in @@ -0,0 +1,4 @@ +# +# The daemon data directory ... where databases, logs etc. are kept +# +DataDir=@APOC_DATADIR@ diff --git a/src/com/sun/apoc/daemon/properties/policymgr.properties b/src/com/sun/apoc/daemon/properties/policymgr.properties new file mode 100644 index 0000000..baeee3b --- /dev/null +++ b/src/com/sun/apoc/daemon/properties/policymgr.properties @@ -0,0 +1,9 @@ +#-----------------------------# +# Basic Configuration Example # +#-----------------------------# + +#PROVIDER_URL = ldap://server1.freedesktop.org:389/o=mySuffixDn +#AuthType=Anonymous +#AuthDn= +#Password= +#ConnectTimeout=1 diff --git a/src/com/sun/apoc/daemon/transaction/AddListenerTransaction.java b/src/com/sun/apoc/daemon/transaction/AddListenerTransaction.java new file mode 100644 index 0000000..e4a2522 --- /dev/null +++ b/src/com/sun/apoc/daemon/transaction/AddListenerTransaction.java @@ -0,0 +1,58 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transaction; + +import com.sun.apoc.daemon.apocd.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; + +class AddListenerTransaction extends Transaction +{ + public AddListenerTransaction( final Client inClient, + final Message inRequest ) + { + super( inClient, inRequest ); + } + + public void executeTransaction() + { + APOCLogger.finer( "Altn001" ); + mSession.addListeners( + ( ( AddListenerMessage )mRequest ).getComponentNames(), + ( ( AddListenerMessage )mRequest ).getClientData() ); + setResponse( APOCSymbols.sSymRespSuccess ); + APOCLogger.finer( "Altn002" ); + } +} diff --git a/src/com/sun/apoc/daemon/transaction/ChangeDetectTransaction.java b/src/com/sun/apoc/daemon/transaction/ChangeDetectTransaction.java new file mode 100644 index 0000000..0c545bf --- /dev/null +++ b/src/com/sun/apoc/daemon/transaction/ChangeDetectTransaction.java @@ -0,0 +1,128 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transaction; + +import com.sun.apoc.daemon.apocd.*; +import com.sun.apoc.daemon.localdatabase.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; + +import java.util.*; +import java.nio.*; + +public class ChangeDetectTransaction extends Transaction +{ + private ClientManager mClientManager; + private Cache mCache; + private UpdateAggregator mAggregator ; + private static final String[] sStringModel = new String[ 0 ]; + + public ChangeDetectTransaction( final ClientManager inClientManager, + final Cache inCache, + final UpdateAggregator inAggregator ) + { + super( null, null); + mClientManager = inClientManager; + mCache = inCache; + mAggregator = inAggregator ; + } + + protected void executeTransaction() + { + Session theSession = null; + try + { + APOCLogger.finer( "Cdtn001" ); + // + // getLockedSession will try to lock 1 of the Session instances + // associated with database to be refreshed. If successful, + // the returned Session instance should be safe to use ( i.e. it + // wont be closed by someone else ) for the duration of the + // transaction. If unsuccessful, all relevant Session objects + // are already closed or closing so we can skip the change + // detection + // + theSession = getLockedSession(); + if ( theSession != null ) + { + final ArrayList theResults = mCache.changeDetect(); + Session [] theSessions = mCache.getSessions(); + int nbResults = theResults.size() ; + + if ( nbResults > 0 ) + { + for (int theIndex = 0 ; theIndex < nbResults ; ++ theIndex) + { + mAggregator.addUpdate( + theSessions, + (UpdateItem) theResults.get(theIndex)) ; + } + } + } + APOCLogger.finer( "Cdtn002" ); + } + catch( Exception theException ) + { + APOCLogger.throwing( "ChangeDetectTransaction", + "execute", + theException ); + } + if ( theSession != null ) + { + theSession.unlock(); + } + } + + protected boolean needSession() { return false; } + + private Session getLockedSession() + { + Session theSession = null; + Session[] theSessions = mCache.getSessions(); + if ( theSessions != null ) + { + for ( int theIndex = 0; theIndex < theSessions.length; ++ theIndex ) + { + if ( theSessions[ theIndex ].lock() ) + { + theSession = theSessions[ theIndex ]; + break; + } + } + } + return theSession; + } + +} diff --git a/src/com/sun/apoc/daemon/transaction/CreateSessionExtTransaction.java b/src/com/sun/apoc/daemon/transaction/CreateSessionExtTransaction.java new file mode 100644 index 0000000..312bf52 --- /dev/null +++ b/src/com/sun/apoc/daemon/transaction/CreateSessionExtTransaction.java @@ -0,0 +1,76 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ + +package com.sun.apoc.daemon.transaction ; + +import com.sun.apoc.daemon.apocd.Client ; +import com.sun.apoc.daemon.apocd.Session ; +import com.sun.apoc.daemon.messaging.CreateSessionExtMessage ; +import com.sun.apoc.daemon.messaging.Message ; +import com.sun.apoc.daemon.misc.APOCException ; +import com.sun.apoc.daemon.misc.APOCLogger ; +import com.sun.apoc.daemon.misc.APOCSymbols ; + +class CreateSessionExtTransaction extends Transaction { + public CreateSessionExtTransaction(final Client aClient, + final Message aMessage) { + super(aClient, aMessage) ; + } + protected boolean needSession() { return false ; } + protected void executeTransaction() { + try { + APOCLogger.finer("Cstn001") ; + CreateSessionExtMessage message = + (CreateSessionExtMessage) mRequest ; + + mSession = new Session(mClient, message.getUserId(), + message.getEntities()) ; + mClient.addSession(mSession) ; + setResponse(APOCSymbols.sSymRespSuccess, mSession.getSessionId()) ; + APOCLogger.finer("Cstn002") ; + } + catch (APOCException exception) { + setResponse(exception.getCode()) ; + APOCLogger.throwing("CreateSessionExtTransaction", + "executeTransaction", exception) ; + } + catch (Exception exception) { + setResponse(APOCSymbols.sSymRespUnknownFailure) ; + APOCLogger.throwing("CreateSessionExtTransaction", + "executeTransaction", exception) ; + } + } +} + diff --git a/src/com/sun/apoc/daemon/transaction/CreateSessionTransaction.java b/src/com/sun/apoc/daemon/transaction/CreateSessionTransaction.java new file mode 100644 index 0000000..e759397 --- /dev/null +++ b/src/com/sun/apoc/daemon/transaction/CreateSessionTransaction.java @@ -0,0 +1,81 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transaction; + +import com.sun.apoc.daemon.apocd.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; + +class CreateSessionTransaction extends Transaction +{ + public CreateSessionTransaction( final Client inClient, + final Message inRequest ) + { + super( inClient, inRequest ); + } + + protected boolean needSession() { return false; } + + protected void executeTransaction() + { + try + { + APOCLogger.finer( "Cstn001" ); + final CreateSessionMessage theMessage = + ( CreateSessionMessage )mRequest; + mSession = new Session( mClient, + theMessage.getUserId(), + theMessage.getEntityId() ); + mClient.addSession( mSession ); + setResponse( APOCSymbols.sSymRespSuccess, + mSession.getSessionId() ); + APOCLogger.finer( "Cstn002" ); + } + catch ( APOCException theException ) + { + setResponse( theException.getCode() ); + APOCLogger.throwing( "CreateSessionTransaction", + "executeTransaction", + theException ); + } + catch ( Exception theException ) + { + setResponse( APOCSymbols.sSymRespUnknownFailure ); + APOCLogger.throwing( "CreateSessionTransaction", + "executeTransaction", + theException ); + } + } +} diff --git a/src/com/sun/apoc/daemon/transaction/DestroySessionTransaction.java b/src/com/sun/apoc/daemon/transaction/DestroySessionTransaction.java new file mode 100644 index 0000000..4167cea --- /dev/null +++ b/src/com/sun/apoc/daemon/transaction/DestroySessionTransaction.java @@ -0,0 +1,56 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transaction; + +import com.sun.apoc.daemon.apocd.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; + +class DestroySessionTransaction extends Transaction +{ + public DestroySessionTransaction( final Client inClient, + final Message inRequest ) + { + super( inClient, inRequest ); + } + + public void executeTransaction() + { + APOCLogger.finer( "Dstn001" ); + mClient.closeSession( mSession ); + setResponse( APOCSymbols.sSymRespSuccess ); + APOCLogger.finer( "Dstn002" ); + } +} diff --git a/src/com/sun/apoc/daemon/transaction/GarbageCollectTransaction.java b/src/com/sun/apoc/daemon/transaction/GarbageCollectTransaction.java new file mode 100644 index 0000000..4cf92a9 --- /dev/null +++ b/src/com/sun/apoc/daemon/transaction/GarbageCollectTransaction.java @@ -0,0 +1,79 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transaction; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.localdatabase.*; +import com.sun.apoc.daemon.misc.*; + +public class GarbageCollectTransaction extends Transaction +{ + private final Database mDatabase; + + public GarbageCollectTransaction( final Database inDatabase ) + { + super( null, null ); + mDatabase = inDatabase; + } + + protected void executeTransaction() + { + try + { + APOCLogger.finer( "Gctn001" ); + mDatabase.beginTransaction(); + boolean shouldCollect = + Timestamp.getMillis( mDatabase.getLastRead() ) <= + ( Timestamp.getMillis( Timestamp.getTimestamp() ) - + ( DaemonConfig.getIntProperty( DaemonConfig.sTimeToLive ) * + 60000 ) ); + mDatabase.endTransaction(); + mDatabase.close( 0 ); + if ( shouldCollect ) + { + LocalDatabaseFactory.getInstance().deleteDatabase( mDatabase ); + } + APOCLogger.finer( "Gctn002" ); + } + catch( Exception theException ) + { + APOCLogger.throwing( "GarbageCollectTransaction", + "execute", + theException ); + } + } + + protected boolean needSession() { return false; } +} diff --git a/src/com/sun/apoc/daemon/transaction/ListTransaction.java b/src/com/sun/apoc/daemon/transaction/ListTransaction.java new file mode 100644 index 0000000..404f0ae --- /dev/null +++ b/src/com/sun/apoc/daemon/transaction/ListTransaction.java @@ -0,0 +1,82 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transaction; + +import com.sun.apoc.daemon.apocd.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; + +import java.util.*; + +class ListTransaction extends Transaction +{ + public ListTransaction( final Client inClient, final Message inRequest ) + { + super( inClient, inRequest ); + } + + protected void executeTransaction() + { + APOCLogger.finer( "Lstn001" ); + StringBuffer theBuffer = null; + final Cache [] theCaches = mSession.getCaches(); + final HashSet theSet = new HashSet(); + + for (int theIndex = 0 ; theIndex < theCaches.length ; ++ theIndex) + { + theSet.addAll(theCaches [theIndex].list()); + } + if ( theSet != null && theSet.size() > 0 ) + { + final String[] theNames = + ( String[] )theSet.toArray( new String[ 0 ] ); + theBuffer = new StringBuffer(); + for ( int theIndex = 0; theIndex < theNames.length; theIndex ++) + { + theBuffer.append( "<" ) + .append( APOCSymbols.sParamComponentName ) + .append( ">" ) + .append( theNames[ theIndex ] ) + .append( "</" ) + .append( APOCSymbols.sParamComponentName ) + .append( ">" ); + } + } + APOCLogger.finer( "Lstn002" ); + setResponse( APOCSymbols.sSymRespSuccess, + mRequest.getSessionId(), + theBuffer != null ? theBuffer.toString() : "" ); + } +} diff --git a/src/com/sun/apoc/daemon/transaction/ReadTransaction.java b/src/com/sun/apoc/daemon/transaction/ReadTransaction.java new file mode 100644 index 0000000..44d0d07 --- /dev/null +++ b/src/com/sun/apoc/daemon/transaction/ReadTransaction.java @@ -0,0 +1,86 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transaction; + +import com.sun.apoc.daemon.apocd.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; + +import java.util.*; + +class ReadTransaction extends Transaction +{ + public ReadTransaction( final Client inClient, final Message inRequest ) + { + super( inClient, inRequest ); + } + + protected void executeTransaction() + { + APOCLogger.finer( "Rdtn001" ); + StringBuffer theBuffer = null; + final String theComponentName = + ( String )( ( ReadMessage )mRequest ) + .getComponentNames().elementAt( 0 ); + final Cache [] theCaches = mSession.getCaches(); + final ArrayList theResults = new ArrayList(); + + for (int theIndex = 0 ; theIndex < theCaches.length ; ++ theIndex) + { + theResults.addAll(theCaches [theIndex].read(theComponentName)); + } + if ( theResults.size() > 0 ) + { + theBuffer = new StringBuffer(); + final Iterator theIterator = theResults.iterator(); + while ( theIterator.hasNext() ) + { + CacheReadResult theResult = (CacheReadResult)theIterator.next(); + theBuffer.append( "<" ) + .append( APOCSymbols.sParamLayer ) + .append( "><![CDATA[" ) + .append( theResult.mTimestamp ) + .append( theResult.mData ) + .append( "]]></" ) + .append( APOCSymbols.sParamLayer ) + .append( ">" ); + } + } + APOCLogger.finer( "Rdtn002" ); + setResponse( APOCSymbols.sSymRespSuccess, + mRequest.getSessionId(), + theBuffer != null ? theBuffer.toString() : "" ); + } +} diff --git a/src/com/sun/apoc/daemon/transaction/RemoveListenerTransaction.java b/src/com/sun/apoc/daemon/transaction/RemoveListenerTransaction.java new file mode 100644 index 0000000..2d346c4 --- /dev/null +++ b/src/com/sun/apoc/daemon/transaction/RemoveListenerTransaction.java @@ -0,0 +1,57 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transaction; + +import com.sun.apoc.daemon.apocd.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; + +class RemoveListenerTransaction extends Transaction +{ + public RemoveListenerTransaction( final Client inClient, + final Message inRequest ) + { + super( inClient, inRequest ); + } + + public void executeTransaction() + { + APOCLogger.finer( "Rltn001" ); + mSession.removeListeners( + ( ( RemoveListenerMessage )mRequest ).getComponentNames() ); + setResponse( APOCSymbols.sSymRespSuccess ); + APOCLogger.finer( "Rltn002" ); + } +} diff --git a/src/com/sun/apoc/daemon/transaction/Transaction.java b/src/com/sun/apoc/daemon/transaction/Transaction.java new file mode 100644 index 0000000..59fee20 --- /dev/null +++ b/src/com/sun/apoc/daemon/transaction/Transaction.java @@ -0,0 +1,148 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transaction; + +import com.sun.apoc.daemon.apocd.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; + +import java.util.*; + +public abstract class Transaction +{ + protected final Client mClient; + protected Session mSession; + protected final Message mRequest; + protected Message mResponse; + private Thread mThread; + private Object mThreadLock = new Object(); + private long mStartTime; + + public Transaction( final Client inClient, final Message inRequest ) + { + mClient = inClient; + mRequest = inRequest; + if ( inClient != null && inRequest != null ) + { + mSession = inClient.getSession( mRequest.getSessionId() ); + } + } + + public Message execute() + { + if ( ! needSession() || mSession != null ) + { + try + { + beginTransaction(); + executeTransaction(); + endTransaction(); + } + catch( Exception theException ) + { + APOCLogger.throwing( "Transaction", "execute", theException ); + setResponse( APOCSymbols.sSymRespUnknownFailure ); + } + } + else + { + setResponse( APOCSymbols.sSymRespInvalidSessionId ); + } + return mResponse; + } + + public long getDuration() + { + return System.currentTimeMillis() - mStartTime; + } + + public void interrupt() + { + synchronized( mThreadLock ) + { + if ( mThread != null ) + { + mThread.interrupt(); + mThread = null; + } + } + } + + protected boolean needSession() + { + return true; + } + + protected void beginTransaction() + { + mStartTime = System.currentTimeMillis(); + setThread( Thread.currentThread() ); + TransactionFactory.getInstance().addTransaction( this ); + } + protected abstract void executeTransaction(); + protected void endTransaction() + { + setThread( null ); + TransactionFactory.getInstance().removeTransaction( this ); + } + + protected void setResponse( final int inResponseType ) + { + setResponse( inResponseType, mRequest.getSessionId(), null ); + } + + protected void setResponse( final int inResponseType, + final String inSessionId ) + { + setResponse( inResponseType, inSessionId, null ); + } + + protected void setResponse( final int inResponseType, + final String inSessionId, + final String inResponseMessage ) + { + mResponse = MessageFactory.createResponse( inResponseType, + inSessionId, + inResponseMessage ); + } + + private void setThread( final Thread inThread ) + { + synchronized( mThreadLock ) + { + mThread = inThread; + } + } +} diff --git a/src/com/sun/apoc/daemon/transaction/TransactionFactory.java b/src/com/sun/apoc/daemon/transaction/TransactionFactory.java new file mode 100644 index 0000000..3418d7b --- /dev/null +++ b/src/com/sun/apoc/daemon/transaction/TransactionFactory.java @@ -0,0 +1,181 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transaction; + +import com.sun.apoc.daemon.apocd.*; +import com.sun.apoc.daemon.localdatabase.*; +import com.sun.apoc.daemon.messaging.*; +import com.sun.apoc.daemon.misc.*; + +import java.util.*; + +public class TransactionFactory +{ + + private static TransactionFactory sInstance; + private static final Transaction[] sTransactionModel = + new Transaction[ 0 ]; + //private static long sTransactionTimeout = 30000; + private static long sTransactionTimeout = 10000; + private final HashSet mTransactions = new HashSet(); + private final DaemonTimerTask mTransactionInterrupter = + new DaemonTimerTask( new TransactionInterrupter() ); + + public void addTransaction( final Transaction inTransaction ) + { + synchronized( mTransactions ) + { + if ( mTransactions.size() == 0 ) + { + mTransactionInterrupter.setPeriod( sTransactionTimeout ); + } + mTransactions.add( inTransaction ); + } + } + + public ChangeDetectTransaction createChangeDetectTransaction( + final ClientManager inClientManager, + final Cache inCache, + final UpdateAggregator inAggregator ) + { + return new ChangeDetectTransaction( inClientManager, + inCache, inAggregator ); + } + + public GarbageCollectTransaction createGarbageCollectTransaction( + final Database inDatabase ) + { + return new GarbageCollectTransaction( inDatabase ); + } + + public Transaction createTransaction( final Client inClient, + final Message inMessage ) + { + Transaction theTransaction = null; + switch ( inMessage.getName() ) + { + case APOCSymbols.sSymReqRead: + theTransaction = new ReadTransaction( inClient, inMessage ); + break; + + case APOCSymbols.sSymReqAddListener: + theTransaction = + new AddListenerTransaction( inClient, inMessage ); + break; + + case APOCSymbols.sSymReqCreateSession: + theTransaction = + new CreateSessionTransaction( inClient, inMessage ); + break; + + case APOCSymbols.sSymReqCreateSessionExt: + theTransaction = + new CreateSessionExtTransaction( inClient, inMessage ); + break; + + case APOCSymbols.sSymReqDestroySession: + theTransaction = + new DestroySessionTransaction( inClient, inMessage ); + break; + + case APOCSymbols.sSymReqRemoveListener: + theTransaction = + new RemoveListenerTransaction( inClient, inMessage ); + break; + + case APOCSymbols.sSymReqList: + theTransaction = + new ListTransaction( inClient, inMessage ); + break; + + default: + break; + } + return theTransaction; + } + + public static TransactionFactory getInstance() + { + if ( sInstance == null ) + { + sInstance = new TransactionFactory(); + } + return sInstance; + } + + public void removeTransaction( final Transaction inTransaction ) + { + synchronized( mTransactions ) + { + if ( mTransactions.size() == 1 ) + { + mTransactionInterrupter.cancel(); + } + mTransactions.remove( inTransaction ); + } + } + + private TransactionFactory(){} + + class TransactionInterrupter implements Runnable + { + public void run() + { + synchronized( mTransactions ) + { + Transaction[] theTransactions = null; + if ( mTransactions.size() > 0 ) + { + theTransactions = + ( Transaction[] )mTransactions.toArray( sTransactionModel); + } + if ( theTransactions != null && theTransactions.length > 0 ) + { + for ( int theIndex = 0; + theIndex < theTransactions.length; + ++ theIndex ) + { + if ( theTransactions[ theIndex ].getDuration() > + sTransactionTimeout ) + { + theTransactions[ theIndex ].interrupt(); + removeTransaction( theTransactions[ theIndex ] ); + } + } + } + } + } + } +} diff --git a/src/com/sun/apoc/daemon/transport/ChannelManager.java b/src/com/sun/apoc/daemon/transport/ChannelManager.java new file mode 100644 index 0000000..f550350 --- /dev/null +++ b/src/com/sun/apoc/daemon/transport/ChannelManager.java @@ -0,0 +1,414 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transport; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.misc.*; + +import java.io.*; +import java.net.*; +import java.nio.*; +import java.nio.channels.*; +import java.util.*; +import java.util.logging.*; + +public class ChannelManager extends Thread implements ConfigEventListener +{ + private Selector mSelector; + private ServerSocketChannel mChannel; + private final HashSet mRegisteringChannels = + new HashSet(); + private final HashSet mDeRegisteringChannels = + new HashSet(); + private final Object mLock = new Object(); + private int mMaxClientChannels = + DaemonConfig.getIntProperty( DaemonConfig.sMaxClientConnections ); + private final HashSet mClientChannelEventListeners = new HashSet(); + private int mChannelCount = 0; + private boolean mTerminate = false; + private static final byte sReject = 0; + private static final byte[] sAcceptByte = { 1 }; + private static final ByteBuffer sAccept = + ( ByteBuffer )ByteBuffer.wrap( sAcceptByte ); + + public ChannelManager() + throws APOCException + { + try + { + initThread(); + initChannel(); + DaemonConfig.addConfigEventListener( this ); + } + catch( IOException theException ) + { + throw new APOCException( + APOCSymbols.sSymCreateServerChannelFailed, + theException ); + } + } + + public void addClientChannelEventListener( + final ClientChannelEventListener inListener ) + { + if ( inListener != null ) + { + synchronized( mClientChannelEventListeners ) + { + mClientChannelEventListeners.add( inListener ); + } + } + } + + public void closeClientChannels() + { + final Set theKeys = mSelector.keys(); + if ( theKeys != null ) + { + final Iterator theIterator = theKeys.iterator(); + while ( theIterator.hasNext() ) + { + final SelectionKey theKey = + ( SelectionKey )theIterator.next(); + if ( theKey.isValid() ) + { + try + { + theKey.channel().close(); + } + catch( IOException theException ) + {} + } + } + } + } + + public void closeChannels() + { + closeClientChannels(); + closeServerChannel(); + } + + public void onConfigEvent() + { + setMaxClientChannels(); + } + + public void removeClientChannelEventListener( + final ClientChannelEventListener inListener ) + { + if ( inListener != null ) + { + synchronized( mClientChannelEventListeners ) + { + mClientChannelEventListeners.remove( inListener ); + } + } + } + + public void run() + { + APOCLogger.fine( "Chmr001" ); + while ( ! shouldTerminate() ) + { + try + { + selectChannels(); + registerChannels(); + } + catch( Exception theException ) + { + APOCLogger.throwing( "ChannelManager", "run", theException ); + break; + } + } + APOCLogger.fine( "Chmr003" ); + } + + public void terminate() + { + synchronized( mLock ) + { + mTerminate = true; + } + mSelector.wakeup(); + } + + void closeClientChannel( final ClientChannel inChannel ) + { + inChannel.close(); + notifyClosed( inChannel ); + synchronized( mLock ) + { + -- mChannelCount; + } + } + + void registerForSelection( final ClientChannel inChannel,boolean inRegister) + { + final HashSet theSet = inRegister ? + mRegisteringChannels : mDeRegisteringChannels; + synchronized( theSet ) + { + theSet. add( inChannel.getSocketChannel().keyFor( mSelector ) ); + mSelector.wakeup(); + try + { + theSet.wait(); + } + catch( Exception theException ) + {} + } + } + + private void acceptableKey( final SelectionKey inKey ) + { + SocketChannel theSocketChannel = null; + try + { + theSocketChannel = + ( ( ServerSocketChannel )inKey.channel() ).accept(); + if ( ! testMaxChannels() && theSocketChannel != null ) + { + try + { + theSocketChannel.socket() + .getOutputStream().write( sReject ); + theSocketChannel.close(); + } + catch( Exception theException ){} + return; + } + if ( theSocketChannel. + socket(). + getInetAddress(). + isLoopbackAddress() ) + { + theSocketChannel.configureBlocking( false ); + final SelectionKey theClientKey = + theSocketChannel.register( + mSelector, + SelectionKey.OP_READ ); + ClientChannel theClientChannel = + new ClientChannel( theSocketChannel, this ); + theClientKey.attach( theClientChannel ); + synchronized( mLock ) + { + ++ mChannelCount; + } + theClientChannel.write( sAccept ); + sAccept.flip(); + } + } + catch( IOException theException ) + { + if ( theSocketChannel != null ) + { + try + { + theSocketChannel.close(); + } + catch( Exception ignore ) + {} + } + APOCLogger.throwing( "ChannelManager", + "acceptableKey", + theException ); + } + } + + private void closeServerChannel() + { + try + { + mSelector.close(); + mChannel.close(); + } + catch( IOException theException ) + { + APOCLogger.throwing( "ClientManager", "close", theException ); + } + } + + private int getMaxClientChannels() + { + synchronized( mLock ) + { + return mMaxClientChannels; + } + } + + private void initChannel() + throws IOException + { + mSelector = Selector.open(); + mChannel = ServerSocketChannel.open(); + mChannel.configureBlocking( false ); + mChannel.socket().bind( + new InetSocketAddress( + DaemonConfig.getIntProperty( DaemonConfig.sDaemonPort ) ) ); + mChannel.register( mSelector, SelectionKey.OP_ACCEPT ); + } + + private void initThread() + { + setName( "ChannelManager" ); + setDaemon( true ); + } + + private void notifyClosed( final ClientChannel inClientChannel ) + { + final Iterator theIterator = mClientChannelEventListeners.iterator(); + while ( theIterator.hasNext() ) + { + ( ( ClientChannelEventListener )theIterator.next() ).onClosed( + inClientChannel ); + } + } + + private void notifyPending( final ClientChannel inClientChannel ) + { + final Iterator theIterator = mClientChannelEventListeners.iterator(); + while ( theIterator.hasNext() ) + { + ( ( ClientChannelEventListener )theIterator.next() ).onPending( + inClientChannel ); + } + } + + private void readableKey( final SelectionKey inKey ) + { + inKey.interestOps( + inKey.interestOps() & + ( ~ SelectionKey.OP_READ ) ); + notifyPending( ( ClientChannel )inKey.attachment() ); + } + + private void registerChannels() + { + synchronized( mRegisteringChannels ) + { + if ( mRegisteringChannels.size() > 0 ) + { + final Iterator theIterator = mRegisteringChannels.iterator(); + while ( theIterator.hasNext() ) + { + final SelectionKey theKey = + ( SelectionKey )theIterator.next(); + theKey.interestOps( theKey.interestOps() | + SelectionKey.OP_READ ); + } + mRegisteringChannels.clear(); + mRegisteringChannels.notifyAll(); + } + } + synchronized( mDeRegisteringChannels ) + { + if ( mDeRegisteringChannels.size() > 0 ) + { + final Iterator theIterator = mDeRegisteringChannels.iterator(); + while ( theIterator.hasNext() ) + { + final SelectionKey theKey = + ( SelectionKey )theIterator.next(); + theKey.interestOps( theKey.interestOps() & + ( ~ SelectionKey.OP_READ ) ); + } + } + mDeRegisteringChannels.clear(); + mDeRegisteringChannels.notifyAll(); + } + } + + private void selectChannels() + throws IOException + { + if ( mSelector.select() > 0 ) + { + final Iterator theIterator = mSelector.selectedKeys().iterator(); + while ( theIterator.hasNext() ) + { + final SelectionKey theKey = ( SelectionKey )theIterator.next(); + theIterator.remove(); + if ( theKey.isAcceptable() ) + { + acceptableKey( theKey ); + } + if ( theKey.isReadable() ) + { + readableKey( theKey ); + } + } + } + } + + private void setMaxClientChannels() + { + synchronized( mLock ) + { + mMaxClientChannels = + DaemonConfig.getIntProperty( + DaemonConfig.sMaxClientConnections ); + } + mSelector.wakeup(); + } + + private boolean shouldTerminate() + { + synchronized( mLock ) + { + return mTerminate; + } + } + + private boolean testMaxChannels() + { + boolean bMoreChannelsAllowed = false; + int theMaxClientChannels = getMaxClientChannels(); + if ( theMaxClientChannels > 0 ) + { + synchronized( mLock ) + { + bMoreChannelsAllowed = theMaxClientChannels > mChannelCount; + } + } + if ( ! bMoreChannelsAllowed ) + { + APOCLogger.warning( "Chmr002", + String.valueOf( theMaxClientChannels ) ); + } + return bMoreChannelsAllowed; + } +} diff --git a/src/com/sun/apoc/daemon/transport/ClientChannel.java b/src/com/sun/apoc/daemon/transport/ClientChannel.java new file mode 100644 index 0000000..87ae738 --- /dev/null +++ b/src/com/sun/apoc/daemon/transport/ClientChannel.java @@ -0,0 +1,150 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transport; + +import com.sun.apoc.daemon.config.*; +import com.sun.apoc.daemon.misc.*; + +import java.io.*; +import java.net.*; +import java.nio.*; +import java.nio.channels.*; +import java.util.*; + +public class ClientChannel +{ + private SocketChannel mChannel; + private ChannelManager mManager = null; + + private static int sSoTimeout = + DaemonConfig.getIntProperty( DaemonConfig.sConnectionReadTimeout ); + + public ClientChannel( final SocketChannel inChannel, + final ChannelManager inManager ) + throws IOException + { + this( inChannel ); + mManager = inManager; + } + + public ClientChannel( final SocketChannel inChannel ) + throws IOException + { + initChannel( inChannel ); + } + + public SocketChannel getSocketChannel() { return mChannel; } + + public void registerForSelection( boolean inRegister ) + { + mManager.registerForSelection( this, inRegister ); + } + + public long read( final ByteBuffer outBuffer ) + throws IOException + { + long theByteCount = 0; + while ( theByteCount == 0 ) + { + try + { + theByteCount = mChannel.read( outBuffer ); + if ( theByteCount == 0 ) + { + Thread.currentThread().yield(); + } + } + catch( IOException theException ) + { + theByteCount = -1; + break; + } + } + if ( theByteCount == -1 ) + { + APOCLogger.finest( "Clch002" ); + if ( mManager != null ) + { + mManager.closeClientChannel( this ); + } + throw new IOException(); + } + return theByteCount; + } + + public void write( final ByteBuffer inBuffer ) + { + try + { + while ( inBuffer.hasRemaining() ) + { + mChannel.write( inBuffer ); + } + } + catch( IOException theException ) + { + APOCLogger.throwing( "ClientChannel", "write", theException ); + if ( mManager != null ) + { + mManager.closeClientChannel( this ); + } + } + } + + public void close() + { + try + { + if ( mChannel != null ) + { + mChannel.close(); + mChannel = null; + } + } + catch( Exception theException ) + { + APOCLogger.throwing( "ClientChannel", "close", theException ); + } + } + + private void initChannel( final SocketChannel inChannel ) + throws IOException + { + mChannel = inChannel; + final Socket theSocket = mChannel.socket(); + theSocket.setSoLinger( false, 0 ); + theSocket.setSoTimeout( sSoTimeout ); + } +} diff --git a/src/com/sun/apoc/daemon/transport/ClientChannelEventListener.java b/src/com/sun/apoc/daemon/transport/ClientChannelEventListener.java new file mode 100644 index 0000000..dfef31c --- /dev/null +++ b/src/com/sun/apoc/daemon/transport/ClientChannelEventListener.java @@ -0,0 +1,41 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either + * the GNU General Public License Version 2 only ("GPL") or + * the Common Development and Distribution License("CDDL") + * (collectively, the "License"). You may not use this file + * except in compliance with the License. You can obtain a copy + * of the License at www.sun.com/CDDL or at COPYRIGHT. See the + * License for the specific language governing permissions and + * limitations under the License. When distributing the software, + * include this License Header Notice in each file and include + * the License file at /legal/license.txt. If applicable, add the + * following below the License Header, with the fields enclosed + * by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * If you wish your version of this file to be governed by + * only the CDDL or only the GPL Version 2, indicate your + * decision by adding "[Contributor] elects to include this + * software in this distribution under the [CDDL or GPL + * Version 2] license." If you don't indicate a single choice + * of license, a recipient has the option to distribute your + * version of this file under either the CDDL, the GPL Version + * 2 or to extend the choice of license to its licensees as + * provided above. However, if you add GPL Version 2 code and + * therefore, elected the GPL Version 2 license, then the + * option applies only if the new code is made subject to such + * option by the copyright holder. + */ +package com.sun.apoc.daemon.transport; + +public interface ClientChannelEventListener +{ + public void onPending( ClientChannel inClientChannel ); + public void onClosed( ClientChannel inClientChannel ); +} |