You are viewing a plain text version of this content. The canonical link for it is here.
Posted to slide-dev@jakarta.apache.org by st...@apache.org on 2004/07/01 20:29:57 UTC

cvs commit: jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/observation DispatchAction.java EventConsumer.java EventDispatcher.java EventFilter.java EventImpl.java

stefan      2004/07/01 11:29:57

  Added:       proposals/jcrri/src/org/apache/slide/jcr/core/observation
                        DispatchAction.java EventConsumer.java
                        EventDispatcher.java EventFilter.java
                        EventImpl.java
  Log:
  jcrri
  
  Revision  Changes    Path
  1.1                  jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/observation/DispatchAction.java
  
  Index: DispatchAction.java
  ===================================================================
  /*
   * $Id: DispatchAction.java,v 1.1 2004/07/01 18:29:57 stefan Exp $
   *
   * Copyright 2002-2004 Day Management AG, Switzerland.
   *
   * Licensed under the Day RI License, Version 2.0 (the "License"),
   * as a reference implementation of the following specification:
   *
   *   Content Repository API for Java Technology, revision 0.13
   *        <http://www.jcp.org/en/jsr/detail?id=170>
   *
   * You may not use this file except in compliance with the License.
   * You may obtain a copy of the License files at
   *
   *     http://www.day.com/content/en/licenses/day-ri-license-2.0
   *     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.jcr.core.observation;
  
  import java.util.Collection;
  
  /**
   * The <code>DispatchAction</code> class is a simple struct that defines what
   * <code>EventState</code>s should be dispatched to which
   * <code>EventConsumer</code>s.
   *
   * @author Marcel Reutegger
   * @version $Revision: 1.1 $, $Date: 2004/07/01 18:29:57 $
   */
  class DispatchAction {
  
      /** The collection of <code>EventState</code>s */
      final EventStateCollection eventStates;
  
      /**
       * <code>EventStates</code> are dispatched to these
       * <code>EventConsumer</code>s.
       */
      final Collection eventConsumers;
  
      /**
       * Creates a new <code>DispatchAction</code> struct with
       * <code>eventStates</code> and <code>eventConsumers</code>.
       */
      DispatchAction(EventStateCollection eventStates, Collection eventConsumers) {
          this.eventStates = eventStates;
          this.eventConsumers = eventConsumers;
      }
  }
  
  
  
  1.1                  jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/observation/EventConsumer.java
  
  Index: EventConsumer.java
  ===================================================================
  /*
   * $Id: EventConsumer.java,v 1.1 2004/07/01 18:29:57 stefan Exp $
   *
   * Copyright 2002-2004 Day Management AG, Switzerland.
   *
   * Licensed under the Day RI License, Version 2.0 (the "License"),
   * as a reference implementation of the following specification:
   *
   *   Content Repository API for Java Technology, revision 0.13
   *        <http://www.jcp.org/en/jsr/detail?id=170>
   *
   * You may not use this file except in compliance with the License.
   * You may obtain a copy of the License files at
   *
   *     http://www.day.com/content/en/licenses/day-ri-license-2.0
   *     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.jcr.core.observation;
  
  import javax.jcr.observation.EventListener;
  import javax.jcr.observation.EventIterator;
  
  /**
   * The <code>EventConsumer</code> class combines the {@link
   * javax.jcr.observation.EventListener} with the implementation of specified
   * filter for the listener: {@link EventFilter}.
   * <p>
   * Collections of {@link EventState} objects will be dispatched to {@link
   * #consumeEvents}.
   *
   * @author Marcel Reutegger
   * @version $Revision: 1.1 $, $Date: 2004/07/01 18:29:57 $
   */
  class EventConsumer {
  
      /** The userId part of this <code>EventConsumer</code>. */
      private final String userId;
  
      /** The listener part of this <code>EventConsumer</code>. */
      private final EventListener listener;
  
      /** The <code>EventFilter</code> for this <code>EventConsumer</code>. */
      private final EventFilter filter;
  
      /** cached hash code value */
      private int hashCode;
  
      /**
       * An <code>EventConsumer</code> consists of a <code>userId</code> which
       * refers to the user id of the <code>Ticket</code>, the attached
       * <code>EventListener</code> and an <code>EventFilter</code>.
       *
       * @param userId the user id taken from the <code>Ticket</code>.
       * @param listener the actual <code>EventListener</code> to call back.
       * @param filter only pass an <code>Event</code> to the listener
       * if the <code>EventFilter</code> allows the <code>Event</code>.
       *
       * @exception NullPointerException if <code>userId</code>,
       *  <code>listener</code> or <code>filter</code> is<code>null</code>.
       */
      EventConsumer(String userId, EventListener listener, EventFilter filter) {
          if (userId == null) throw new NullPointerException("userId");
          if (listener == null) throw new NullPointerException("listener");
          if (filter == null) throw new NullPointerException("filter");
  
          this.userId = userId;
          this.listener = listener;
          this.filter = filter;
      }
  
      /**
       * Returns the userId of the <code>Ticket</code> that is associated
       * with this <code>EventConsumer</code>.
       * @return the userId of this <code>EventConsumer</code>.
       */
      String getUserId() {
          return userId;
      }
  
      /**
       * Returns the <code>EventListener</code> that is associated with this
       * <code>EventConsumer</code>.
       *
       * @return the <code>EventListener</code> of this <code>EventConsumer</code>.
       */
      EventListener getEventListener() {
          return listener;
      }
  
      /**
       * Dispatches the events to the <code>EventListener</code>.
       * @param events a collection of {@link EventState}s
       *   to dispatch.
       */
      void consumeEvents(EventStateCollection events) {
          // check if filtered iterator has at least one event
          EventIterator it = new FilteredEventIterator(events, filter);
          if (it.hasNext()) {
              listener.onEvent(it);
          } else {
              // otherwise skip this listener
          }
      }
  
      /**
       * Returns <code>true</code> if this <code>EventConsumer</code>
       * is equal to some other object, <code>false</code> otherwise.
       * <p>
       * Two <code>EventConsumer</code>s are considered equal if
       * they refer to the same user id and the <code>EventListener</code>s
       * they reference are equal. Note that the <code>EventFilter</code> is
       * ignored in this check.
       *
       * @param obj the reference object with which to compare.
       * @return <code>true</code> if this <code>EventConsumer</code>
       *  is equal the other <code>EventConsumer</code>.
       */
      public boolean equals(Object obj) {
          if (this == obj) {
              return true;
          }
          if (obj instanceof EventConsumer) {
              EventConsumer other = (EventConsumer)obj;
              return userId.equals(other.userId)
                      && listener.equals(other.listener);
          }
          return false;
      }
  
      /**
       * Returns the hash code for this <code>EventConsumer</code>.
       * @return the hash code for this <code>EventConsumer</code>.
       */
      public int hashCode() {
          if (hashCode == 0) {
              hashCode = userId.hashCode() ^ listener.hashCode();
          }
          return hashCode;
      }
  }
  
  
  
  1.1                  jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/observation/EventDispatcher.java
  
  Index: EventDispatcher.java
  ===================================================================
  /*
   * $Id: EventDispatcher.java,v 1.1 2004/07/01 18:29:57 stefan Exp $
   *
   * Copyright 2002-2004 Day Management AG, Switzerland.
   *
   * Licensed under the Day RI License, Version 2.0 (the "License"),
   * as a reference implementation of the following specification:
   *
   *   Content Repository API for Java Technology, revision 0.13
   *        <http://www.jcp.org/en/jsr/detail?id=170>
   *
   * You may not use this file except in compliance with the License.
   * You may obtain a copy of the License files at
   *
   *     http://www.day.com/content/en/licenses/day-ri-license-2.0
   *     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.jcr.core.observation;
  
  /**
   * The <code>EventDispatcher</code> interface defines a single method {@link
   * #dispatchEvents}, through this method a collection of {@link EventState}
   * instances is dispatched to registered {@link javax.jcr.observation.EventListener}s.
   *
   * @author Marcel Reutegger
   * @version $Revision: 1.1 $, $Date: 2004/07/01 18:29:57 $
   */
  public interface EventDispatcher {
  
      /**
       * Dispatches the {@link EventStateCollection events} to all
       * registered {@link javax.jcr.observation.EventListener}s.
       *
       * @param events the {@link EventState}s to dispatch.
       */
      public void dispatchEvents(EventStateCollection events);
  }
  
  
  
  1.1                  jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/observation/EventFilter.java
  
  Index: EventFilter.java
  ===================================================================
  /*
   * $Id: EventFilter.java,v 1.1 2004/07/01 18:29:57 stefan Exp $
   *
   * Copyright 2002-2004 Day Management AG, Switzerland.
   *
   * Licensed under the Day RI License, Version 2.0 (the "License"),
   * as a reference implementation of the following specification:
   *
   *   Content Repository API for Java Technology, revision 0.13
   *        <http://www.jcp.org/en/jsr/detail?id=170>
   *
   * You may not use this file except in compliance with the License.
   * You may obtain a copy of the License files at
   *
   *     http://www.day.com/content/en/licenses/day-ri-license-2.0
   *     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.jcr.core.observation;
  
  import org.apache.slide.jcr.core.ItemManager;
  import org.apache.slide.jcr.core.NodeId;
  import org.apache.slide.jcr.core.TicketImpl;
  
  import javax.jcr.*;
  import javax.jcr.access.AccessDeniedException;
  import javax.jcr.nodetype.NodeType;
  
  /**
   * The <code>EventFilter</code> class implement the filter logic based
   * on the tickets access rights and the specified filter rules.
   *
   * @author Marcel Reutegger
   * @version $Revision: 1.1 $, $Date: 2004/07/01 18:29:57 $
   */
  class EventFilter {
  
      static final EventFilter BLOCK_ALL = new BlockAllFilter();
  
      /** The ItemManager of the ticket */
      private final ItemManager itemMgr;
  
      /** The ticket this EventFilter belongs to. */
      private final TicketImpl ticket;
  
      /**
       * This <code>EventFilter</code> should only allow events with the
       * specified types.
       */
      private final long eventTypes;
  
      /** Only allow Items with the specified <code>absPath</code> */
      private final String absPath;
  
      /**
       * If <code>isDeep</code> is <code>true</code> also Items under <code>absPath</code>
       * are allowed.
       */
      private final boolean isDeep;
  
      /**
       * Only allow Nodes with the specified <code>uuids</code>.
       */
      private final String[] uuids;
  
      /**
       * Only allow Nodes with the specified {@link javax.jcr.nodetype.NodeType}s.
       */
      private final NodeType[] nodeTypes;
  
      /**
       * If <code>noLocal</code> is true this filter will block events from
       * the ticket that registerd this filter.
       */
      private final boolean noLocal;
  
      /**
       * Creates a new <code>EventFilter</code> instance.
       *
       * @param itemMgr    the <code>ItemManager</code> of the <code>ticket</code>.
       * @param ticket     the <code>Ticket</code> that registered the {@link
       *                   javax.jcr.observation.EventListener}.
       * @param eventTypes only allow specified {@link javax.jcr.observation.EventType}s.
       * @param absPath    only allow {@link javax.jcr.Item} with
       *                   <code>absPath</code>.
       * @param isDeep     if <code>true</code> also allow events for {@link
       *                   Item}s below <code>absPath</code>.
       * @param uuids      only allow events for {@link javax.jcr.Node}s with
       *                   specified UUIDs. If <code>null</code> is passed no
       *                   restriction regarding UUID is applied.
       * @param nodeTypes  only allow events for specified {@link
       *                   javax.jcr.nodetype.NodeType}s. If <code>null</code> no
       *                   node type restriction is applied.
       * @param noLocal    if <code>true</code> no events are allowed that were
       *                   created from changes related to the <code>Ticket</code>
       *                   that registered the {@link javax.jcr.observation.EventListener}.
       */
      EventFilter(ItemManager itemMgr,
                  TicketImpl ticket, 
                  long eventTypes,
                  String absPath,
                  boolean isDeep,
                  String[] uuids,
                  NodeType[] nodeTypes,
                  boolean noLocal) {
  
          this.itemMgr = itemMgr;
          this.ticket = ticket;
          this.eventTypes = eventTypes;
          this.absPath = absPath;
          this.isDeep = isDeep;
          this.uuids = uuids;
          this.noLocal = noLocal;
          this.nodeTypes = nodeTypes;
      }
  
      /**
       * Returns the <code>Ticket</code> associated with this
       * <code>EventFilter</code>.
       *
       * @return the <code>Ticket</code> associated with this
       *         <code>EventFilter</code>.
       */
      TicketImpl getTicket() {
          return ticket;
      }
  
      /**
       * Returns the <code>ItemManager</code> associated with this
       * <code>EventFilter</code>.
       *
       * @return the <code>ItemManager</code> associated with this
       *         <code>EventFilter</code>.
       */
      ItemManager getItemManager() {
          return itemMgr;
      }
  
      /**
       * Returns <code>true</code> if this <code>EventFilter</code> does not allow
       * the specified <code>EventState</code>; <code>false</code> otherwise.
       *
       * @param eventState the <code>EventState</code> in question.
       * @return <code>true</code> if this <code>EventFilter</code> blocks the
       *         <code>EventState</code>.
       *
       * @throws RepositoryException if an error occurs while checking.
       */
      boolean blocks(EventState eventState) throws RepositoryException {
          // first do cheap checks
  
          // check event type
          long type = eventState.getType();
          if ((eventTypes & type) == 0) {
              return true;
          }
  
          // check for ticket local changes
          if (noLocal && ticket.getUserId().equals(eventState.getUserId())) {
              // listener does not wish to get local events
              return true;
          }
  
          // check UUIDs
          String parentUUID = eventState.getParentUUID();
          if (uuids != null) {
              boolean match = false;
              for (int i = 0; i < uuids.length && !match; i++) {
                  match |= parentUUID.equals(uuids[i]);
              }
              if (!match) {
                  return true;
              }
          }
  
          Node parent = null;
          try {
              parent = (Node)itemMgr.getItem(new NodeId(eventState.getParentUUID()));
          } catch (AccessDeniedException e) {
              return true;
          }
  
          // check node types
          if (nodeTypes != null) {
              boolean match = false;
              for (int i = 0; i < nodeTypes.length && !match; i++) {
                  match |= parent.isNodeType(nodeTypes[i].getName());
              }
              if (!match) {
                  return true;
              }
          }
  
          // check path
          StringIterator paths = parent.getPaths();
          boolean match = false;
          while (paths.hasNext() && !match) {
              match |= (isDeep) ? paths.nextString().startsWith(absPath)
                      : paths.nextString().equals(absPath);
          }
  
          return !match;
      }
  
      /**
       * This class implements an <code>EventFilter</code> that blocks
       * all {@link EventState}s.
       */
      private static final class BlockAllFilter extends EventFilter {
  
          /**
           * Creates a new <code>BlockAllFilter</code>.
           */
          BlockAllFilter() {
              super(null, null, 0, null, true, null, null, true);
          }
  
          /**
           * Always return <code>true</code>.
           * @return always <code>true</code>.
           */
          boolean blocks(EventState eventState) {
              return true;
          }
      }
  
  }
  
  
  
  1.1                  jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/observation/EventImpl.java
  
  Index: EventImpl.java
  ===================================================================
  /*
   * $Id: EventImpl.java,v 1.1 2004/07/01 18:29:57 stefan Exp $
   *
   * Copyright 2002-2004 Day Management AG, Switzerland.
   *
   * Licensed under the Day RI License, Version 2.0 (the "License"),
   * as a reference implementation of the following specification:
   *
   *   Content Repository API for Java Technology, revision 0.13
   *        <http://www.jcp.org/en/jsr/detail?id=170>
   *
   * You may not use this file except in compliance with the License.
   * You may obtain a copy of the License files at
   *
   *     http://www.day.com/content/en/licenses/day-ri-license-2.0
   *     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.jcr.core.observation;
  
  import org.apache.slide.jcr.core.TicketImpl;
  import org.apache.slide.jcr.core.ItemManager;
  import org.apache.slide.jcr.core.NodeId;
  import org.apache.log4j.Logger;
  
  import javax.jcr.observation.Event;
  import javax.jcr.Node;
  import javax.jcr.RepositoryException;
  import javax.jcr.Ticket;
  
  /**
   * Implementation of the {@link javax.jcr.observation.Event} interface.
   *
   * @author Marcel Reutegger
   * @version $Revision: 1.1 $
   */
  final class EventImpl implements Event {
  
      /** Logger instance for this class */
      private static final Logger log = Logger.getLogger(EventImpl.class);
  
      /**
       * The ticket of the {@link javax.jcr.observation.EventListener} this
       * event will be delivered to.
       */
      private final TicketImpl ticket;
  
      /**
       * The <code>ItemManager</code> of the ticket.
       */
      private final ItemManager itemMgr;
  
      /** The shared {@link EventState} object. */
      private final EventState eventState;
  
      /** Cached String value of this <code>Event</code> instance. */
      private String stringValue;
  
      /**
       * Creates a new {@link javax.jcr.observation.Event} instance based on an
       * {@link EventState eventState}.
       *
       * @param ticket     the ticket of the registerd <code>EventListener</code>
       *                   where this <code>Event</code> will be delivered to.
       * @param itemMgr    the <code>ItemManager</code> of the above
       *                   <code>Ticket</code>.
       * @param eventState the underlying <code>EventState</code>.
       */
      EventImpl(TicketImpl ticket, ItemManager itemMgr, EventState eventState) {
          this.ticket = ticket;
          this.itemMgr = itemMgr;
          this.eventState = eventState;
      }
  
      /**
       * @see Event#getType()
       */
      public long getType() {
          return eventState.getType();
      }
  
      /**
       * @see Event#getParentNode()
       */
      public Node getParentNode() throws RepositoryException {
          return (Node)itemMgr.getItem(new NodeId(eventState.getParentUUID()));
      }
  
      /**
       * @see Event#getChildItemName()
       */
      public String getChildItemName() throws RepositoryException {
          return eventState.getChildItemQName().toJCRName(ticket);
      }
  
      /**
       * @see Event#getUserId()
       */
      public String getUserId() {
          return eventState.getUserId();
      }
  
      /**
       * Returns a String representation of this <code>Event</code>.
       * @return a String representation of this <code>Event</code>.
       */
      public String toString() {
          if (stringValue == null) {
              StringBuffer sb = new StringBuffer();
              sb.append("Event: Path: ");
              try {
                  sb.append(getParentNode().getPath());
              } catch (RepositoryException e) {
                  log.error("Exception retrieving path: " + e);
                  sb.append("[Error retrieving path]");
              }
              sb.append(", ").append(EventState.valueOf(getType())).append(": ");
              try {
                  sb.append(getChildItemName());
              } catch (RepositoryException e) {
                  log.error("Exception retrieving child item name: " + e);
                  sb.append("[Error retrieving child item name]");
              }
              sb.append(", UserId: ").append(getUserId());
              stringValue = sb.toString();
          }
          return stringValue;
      }
  
      /**
       * @see Object#hashCode()
       */
      public int hashCode() {
          return eventState.hashCode() ^ ticket.getUserId().hashCode();
      }
  
      /**
       * Returns <code>true</code> if this <code>Event</code> is equal to another
       * object.
       * <p/>
       * Two <code>Event</code> instances are equal if their respective
       * <code>EventState</code> instances are equal and both <code>Event</code>
       * instances are intended for the same <code>Ticket</code> that registerd
       * the <code>EventListener</code>.
       *
       * @param obj the reference object with which to compare.
       * @return <code>true</code> if this <code>Event</code> is equal to another
       *         object.
       */
      public boolean equals(Object obj) {
          if (this == obj) {
              return true;
          }
          if (obj instanceof EventImpl) {
              EventImpl other = (EventImpl)obj;
              return this.eventState.equals(other.eventState)
                      // FIXME rather use ticket.equals(other.ticket) ?
                      && this.ticket.getUserId().equals(other.ticket.getUserId());
          }
          return false;
      }
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: slide-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: slide-dev-help@jakarta.apache.org