masonjm     2004/08/08 22:03:09

  Modified:    src/conf/webapp Domain.xml
               .        build.xml
  Added:       src/share/org/apache/slide/cluster
                        ClusterCacheRefresher.java
               lib      jakarta-slide-webdavlib-2.1b1.jar
  Log:
  (Semi)working cluster notification support.
  
  Revision  Changes    Path
  1.66      +17 -0     jakarta-slide/src/conf/webapp/Domain.xml
  
  Index: Domain.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/src/conf/webapp/Domain.xml,v
  retrieving revision 1.65
  retrieving revision 1.66
  diff -u -r1.65 -r1.66
  --- Domain.xml        5 Aug 2004 14:47:24 -0000       1.65
  +++ Domain.xml        9 Aug 2004 05:03:09 -0000       1.66
  @@ -344,6 +344,23 @@
                   <indexer classname="org.apache.slide.search.LoggingIndexer" 
synchronous="false" uri="/files/articles" />
               </configuration>
           </listener>
  +        
  +             <!-- Uncomment for cluster support. Be sure to local-host and 
repository-host -->
  +             <!--
  +             <listener classname="org.apache.slide.cluster.ClusterCacheRefresher">
  +                     <configuration>
  +                             <node local-host="local.host.domain"
  +                                   local-port="4444"
  +                                       repository-host="remote.host.domain"
  +                                       repository-port="8080"
  +                                       repository-protocol="http"
  +                                       username="root"
  +                                       password="root"
  +                                       base-uri="/files/"
  +                             />
  +                     </configuration>
  +             </listener>
  +             -->
   
           <listener classname="org.apache.slide.macro.MacroPropertyUpdater">
             <!-- Listener that updates some properties if resources are 
  
  
  
  1.1                  
jakarta-slide/src/share/org/apache/slide/cluster/ClusterCacheRefresher.java
  
  Index: ClusterCacheRefresher.java
  ===================================================================
  /*
   *  Copyright 1999-2004 The Apache Software Foundation 
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   *
   */
  package org.apache.slide.cluster;
  
  import java.util.Enumeration;
  import java.util.EventListener;
  import java.util.Iterator;
  import java.util.Map;
  
  import org.apache.commons.httpclient.Credentials;
  import org.apache.commons.httpclient.UsernamePasswordCredentials;
  import org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory;
  import org.apache.commons.httpclient.protocol.Protocol;
  import org.apache.commons.httpclient.protocol.SSLProtocolSocketFactory;
  import org.apache.slide.authenticate.CredentialsToken;
  import org.apache.slide.common.Domain;
  import org.apache.slide.common.NamespaceAccessToken;
  import org.apache.slide.common.SlideToken;
  import org.apache.slide.common.SlideTokenImpl;
  import org.apache.slide.common.Uri;
  import org.apache.slide.store.ExtendedStore;
  import org.apache.slide.store.Store;
  import org.apache.slide.util.conf.Configurable;
  import org.apache.slide.util.conf.Configuration;
  import org.apache.slide.util.conf.ConfigurationException;
  import org.apache.slide.util.logger.Logger;
  import org.apache.webdav.lib.NotificationListener;
  import org.apache.webdav.lib.Subscriber;
  import org.apache.webdav.lib.methods.DepthSupport;
  
  /**
   * <h3>Description</h3>
   * <p>
   * When configured properly this class will register with one or more external
   * Slide instances and listen for changes. Upon notification of a change this
   * class will cause the cache of the local Slide instance to be refreshed for
   * the changed object.
   * </p>
   * <h3>Usage</h3>
   * <p>
   * Add the following to your Domain.xml inside the &lt;events&gt; node.
   * </p>
   * <pre>
   *    &lt;listener classname="org.apache.slide.cluster.ClusterCacheRefresher"&gt;
   *            &lt;configuration&gt;
   *                    &lt;node local-host="local.host.domain"
   *                          local-port="4444"
   *                              repository-host="remote.host.domain"
   *                              repository-port="8080"
   *                              repository-protocol="http"
   *                              username="root"
   *                              password="root"
   *                    /&gt;
   *            &lt;/configuration&gt;
   *    &lt;/listener&gt;
   *  </pre>
   * <p>
   * There should be one &lt;node&gt; element for each node in the cluster,
   * <b>except</b> for the current node. ClusterCacheRefresher should not be
   * configured to listen to itself except for testing purposes.
   * </p>
   * <h3>&lt;node&gt; attributes</h3>
   * <table>
   *    <tr>
   *            <th>Attribute Name</th>
   *            <th>Required?</th>
   *            <th>Default Value</th>
   *            <th>Description</th>
   *    </tr>
   *    <tr>
   *            <td>local-host</td>
   *            <td>yes</td>
   *            <td>none</td>
   *            <td>A network-accessible name or ip-address where the remote Slide 
instance can reach <b>this server.</b></td>
   *    </tr>
   *    <tr>
   *            <td>local-port</td>
   *            <td>yes</td>
   *            <td>none</td>
   *            <td>A port number ClusterCacheRefresher can use to listen for 
notifications. <b>Must be unique.</b></td>
   *    </tr>
   *    <tr>
   *            <td>repository-host</td>
   *            <td>yes</td>
   *            <td>none</td>
   *            <td>A network-accessible name or ip-address of the remote Slide 
instance to monitor.</td>
   *    </tr>
   *    <tr>
   *            <td>repository-port</td>
   *            <td>yes</td>
   *            <td>none</td>
   *            <td>The port the remote Slide instance is running on.</td>
   *    </tr>
   *    <tr>
   *            <td>repository-protocol</td>
   *            <td>no</td>
   *            <td>http</td>
   *            <td>The protocol the remote Slide instance is using. Must be one of 
"http" or "https".</td>
   *    </tr>
   *    <tr>
   *            <td>username</td>
   *            <td>no</td>
   *            <td>none</td>
   *            <td>The username to use to connect to the remote Slide instance.</td>
   *    </tr>
   *    <tr>
   *            <td>password</td>
   *            <td>no</td>
   *            <td>none</td>
   *            <td>The password that goes with the username.</td>
   *    </tr>
   *    <tr>
   *            <td>repository-domain</td>
   *            <td>no</td>
   *            <td>/slide</td>
   *            <td>The context path of the remote Slide instance.</td>
   *    </tr>
   *    <tr>
   *            <td>poll-interval</td>
   *            <td>no</td>
   *            <td>60000</td>
   *            <td>The number of milliseconds to wait between polling the remote 
Slide instance for any changes. Polling for changes is a backup only, so this value 
can be set fairly high.</td>
   *    </tr>
   *    <tr>
   *            <td>udp</td>
   *            <td>no</td>
   *            <td>true</td>
   *            <td>Must be "true" or "false". Indicates whether to use udp or tcp to 
listen for notifications.</td>
   *    </tr>
   *    <tr>
   *            <td>base-uri</td>
   *            <td>no</td>
   *            <td>/</td>
   *            <td>The base path to monitor for changes. Will be appended to the 
repository-domain.</td>
   *    </tr>
   *    <tr>
   *            <td>subscription-lifetime</td>
   *            <td>no</td>
   *            <td>3600</td>
   *            <td>The number of seconds a subscription should last. Subscriptions 
are automatically refreshed. Do not set this value too high.</td>
   *    </tr>
   *    <tr>
   *            <td>notification-delay</td>
   *            <td>no</td>
   *            <td>0</td>
   *            <td>Number of seconds the remote Slide instance should wait before 
sending a notification of a change.</td>
   *    </tr>
   * </table>
   */
  public class ClusterCacheRefresher implements Subscriber, EventListener, 
Configurable {
        protected static final String LOG_CHANNEL = 
ClusterCacheRefresher.class.getName();
        
        protected NotificationListener listener;
  
        public ClusterCacheRefresher() {
                Domain.log("Creating ClusterCacheRefresher", LOG_CHANNEL, Logger.INFO);
        }
  
        public void notify(String uri, Map information) {
                // FIXME: need a better way to get the right namespace
                NamespaceAccessToken nat = Domain.accessNamespace( new 
org.apache.slide.authenticate.SecurityToken(this), "slide" );
                Iterator keys = information.keySet().iterator();
                while ( keys.hasNext() ) {
                        String key = keys.next().toString();
                        if ( "uri".equals( key ) ) {
                                Uri theUri = nat.getUri( new SlideTokenImpl(new 
CredentialsToken("")),information.get(key).toString());
                                Store store = theUri.getStore();
                                if ( store instanceof ExtendedStore ) {
                                        Domain.log( "Resetting cache for " + theUri, 
LOG_CHANNEL, Logger.INFO );
                                        
((ExtendedStore)store).removeObjectFromCache(theUri);
                                }
                                store = theUri.getParentUri().getStore();
                                if ( store instanceof ExtendedStore ) {
                                        Domain.log( "Resetting cache for " + 
theUri.getParentUri(), LOG_CHANNEL, Logger.INFO );
                                        
((ExtendedStore)store).removeObjectFromCache(theUri.getParentUri());
                                }
                        }
                }
        }
  
        public void configure(Configuration configuration) throws 
ConfigurationException {
                
                Domain.log("Configuring ClusterCacheRefresher", LOG_CHANNEL, 
Logger.INFO);
                
                Enumeration nodes = configuration.getConfigurations("node");
                while ( nodes.hasMoreElements() ) {
                        Configuration node = (Configuration)nodes.nextElement();
                        
                        final String host = node.getAttribute("local-host");
                        final int port = node.getAttributeAsInt("local-port");
                        final String repositoryHost = 
node.getAttribute("repository-host");
                        final int repositoryPort = 
node.getAttributeAsInt("repository-port");
                        String repositoryProtocolString = 
node.getAttribute("repository-protocol", "http");
                        final Protocol protocol;
                        if ( "http".equals(repositoryProtocolString) ) {
                                protocol = new Protocol( "http", new 
DefaultProtocolSocketFactory(), 80 );
                        } else if ( "https".equals(repositoryProtocolString) ) {
                                protocol = new Protocol( "https", new 
SSLProtocolSocketFactory(), 443 );
                        } else {
                                throw new ConfigurationException("Unknown 
repository-protocol: " + repositoryProtocolString + ". Must be \"http\" or 
\"https\".", configuration);
                        }
                        String username = node.getAttribute("username", "");
                        String password = node.getAttribute("password", "");
                        final Credentials credentials = new 
UsernamePasswordCredentials( username, password );
                        final String repositoryDomain = 
node.getAttribute("repository-domain", "/slide");
                        final int pollInterval = 
node.getAttributeAsInt("poll-interval", 60000);
                        final boolean udp = node.getAttributeAsBoolean("udp", true);
                        final String uri = node.getAttribute("base-uri", "/");
  //                    int depth = DepthSupport.DEPTH_INFINITY;
                        final int depth = 1;
                        final int lifetime = 
node.getAttributeAsInt("subscription-lifetime", 3600);
                        final int notificationDelay = 
node.getAttributeAsInt("notification-delay", 0);
                        final Subscriber subscriber = this;
                        
  //                    System.out.println( "\n## Creating NotificationListener" );
                        
                        listener = new NotificationListener( host, port, 
repositoryHost, repositoryPort, protocol, credentials, repositoryDomain, pollInterval, 
udp);
                        
  //                    System.out.println( "listener created" );
                                                
                        Thread t = new Thread( new Runnable() {
                                
                                private boolean first = true;
                                
                                public void run() {
                                        
                                        try {
                                                if ( first ) {
                                                        // Delay on startup to let 
server finish starting.
                                                        // FIXME: This should not be 
necessary when NotificationListener stops freezing
                                                        first = false;
                                                        Thread.sleep(3000);
                                                        Domain.log( "Registering 
cluster subscriptions", LOG_CHANNEL, Logger.INFO );
                                                } else {
                                                        Thread.sleep(lifetime*1000-60);
                                                }
                                        } catch (InterruptedException e) {
                                                // TODO Auto-generated catch block
                                                e.printStackTrace();
                                        }
                                        
  //                                    System.out.println( "creating update 
subscriber");
                                        
                                        
listener.subscribe("Update",uri,depth,lifetime,notificationDelay,subscriber,credentials);
                                        
  //                                    System.out.println( "creating update/newmember 
subscriber" );
                                        
                                        
listener.subscribe("Update/newmember",uri,depth,lifetime,notificationDelay,subscriber,credentials);
                                        
  //                                    System.out.println("creating delete 
subscriber");
                                        
                                        
listener.subscribe("Delete",uri,depth,lifetime,notificationDelay,subscriber,credentials);
                                        
  //                                    System.out.println( "creating move subscriber" 
);
                                        
                                        
listener.subscribe("Move",uri,depth,lifetime,notificationDelay,subscriber,credentials);
                                }
                        });
                        t.setDaemon(true);
                        t.start();
                }
        }
  
  }
  
  
  
  1.1                  jakarta-slide/lib/jakarta-slide-webdavlib-2.1b1.jar
  
        <<Binary file>>
  
  
  1.228     +4 -1      jakarta-slide/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-slide/build.xml,v
  retrieving revision 1.227
  retrieving revision 1.228
  diff -u -r1.227 -r1.228
  --- build.xml 5 Aug 2004 14:53:44 -0000       1.227
  +++ build.xml 9 Aug 2004 05:03:09 -0000       1.228
  @@ -47,7 +47,8 @@
       <property name="xml-im-exporter.jar" value="${lib.dir}/xml-im-exporter1.1.jar"/>
       <property name="commons-transaction.jar" 
value="${lib.dir}/commons-transaction-20040805.jar"/>
       <property name="commons-codec.jar" value="${lib.dir}/commons-codec-1.3.jar"/>
  -         <!-- =================================================================== 
-->
  +     <property name="jakarta-slide-webdavlib.jar" 
value="${lib.dir}/jakarta-slide-webdavlib-2.1b1.jar"/>
  +    <!-- =================================================================== -->
       <!-- Produced jars Properties                                            -->
       <!-- =================================================================== -->
       <property name="slide-kernel.jar" value="slide-kernel-${version}.jar"/>
  @@ -115,6 +116,8 @@
           <pathelement location="${ehcache.jar}"/>
           <pathelement location="${commons-transaction.jar}"/>
           <pathelement location="${commons-codec.jar}"/>
  +        <pathelement location="${commons-httpclient.jar}"/>
  +     <pathelement location="${jakarta-slide-webdavlib.jar}"/>
       </path>
       <path id="stores.classpath">
           <pathelement location="${xmlapi.jar}"/>
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to