View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6    * See the AUTHORS.txt file in the distribution for a full listing of 
7    * individual contributors. 
8    *
9    * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10   * is licensed to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   *
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23   */
24  package org.modeshape.graph.request;
25  
26  import java.io.Serializable;
27  import java.util.concurrent.CountDownLatch;
28  import java.util.concurrent.atomic.AtomicBoolean;
29  import org.modeshape.graph.GraphI18n;
30  import org.modeshape.graph.connector.RepositoryConnection;
31  
32  /**
33   * The abstract base class for all classes representing requests to be executed against a {@link RepositoryConnection}.
34   */
35  public abstract class Request implements Serializable {
36  
37      private static final long serialVersionUID = 1L;
38  
39      private Throwable error;
40      private AtomicBoolean cancelled = new AtomicBoolean(false);
41      private final AtomicBoolean frozen = new AtomicBoolean(false);
42      private transient CountDownLatch freezingLatch = null;
43  
44      protected Request() {
45      }
46  
47      public void setLatchForFreezing( CountDownLatch latch ) {
48          checkNotFrozen();
49          this.freezingLatch = latch;
50      }
51  
52      /**
53       * Set the error for this request.
54       * 
55       * @param error the error to be associated with this request, or null if this request is to have no error
56       * @throws IllegalStateException if the request is frozen
57       */
58      public void setError( Throwable error ) {
59          checkNotFrozen();
60          this.error = error;
61      }
62  
63      /**
64       * Return whether there is an error associated with this request
65       * 
66       * @return true if there is an error, or false otherwise
67       */
68      public boolean hasError() {
69          return this.error != null;
70      }
71  
72      /**
73       * Get the error associated with this request, if there is such an error.
74       * 
75       * @return the error, or null if there is none
76       */
77      public Throwable getError() {
78          return error;
79      }
80  
81      /**
82       * Check whether this request has been cancelled. Although it is a recommendation that the result of this method be followed
83       * wherever possible, it is not required to immediately stop processing the request if this method returns <code>true</code>.
84       * For example, if processing is almost complete, it may be appropriate to simply finish processing the request.
85       * <p>
86       * This method is safe to be called by different threads.
87       * </p>
88       * 
89       * @return true if this request has been cancelled, or false otherwise.
90       */
91      public boolean isCancelled() {
92          return cancelled.get();
93      }
94  
95      /**
96       * Set the cancelled state of this request. All requests are initially marked as not cancelled. Note that this is designed so
97       * that the same {@link AtomicBoolean} instance can be passed to multiple requests, allowing a single flag to dictate the
98       * cancelled state of all of those requests.
99       * <p>
100      * So, by default, each request should already be set up to not be cancelled, so for most cases this method does not need to
101      * be called at all. This method should be called when this flag is to be shared among multiple requests, usually when the
102      * requests are being initialized or assembled.
103      * </p>
104      * 
105      * @param cancelled the new (potentially shared) cancelled state for the request; may not be null
106      */
107     /*package*/void setCancelledFlag( AtomicBoolean cancelled ) {
108         assert cancelled != null;
109         this.cancelled = cancelled;
110     }
111 
112     /**
113      * Get this request's cancelled flag.
114      * 
115      * @return the cancelled flag
116      */
117     /*package*/AtomicBoolean getCancelledFlag() {
118         return cancelled;
119     }
120 
121     /**
122      * Cancel this request. After this method is called, the {@link #isCancelled() cancellation flag} is set, and any current or
123      * future processing of the request may be affected by the cancellation. (Note however, that processors may choose to not
124      * respect this request.)
125      * <p>
126      * This method is safe to be called by different threads.
127      * </p>
128      * 
129      * @throws IllegalStateException if the request is frozen
130      */
131     public void cancel() {
132         checkNotFrozen();
133         this.cancelled.set(true);
134     }
135 
136     /**
137      * Return whether this request only reads information.
138      * 
139      * @return true if this request reads information, or false if it requests that the repository content be changed in some way
140      */
141     public abstract boolean isReadOnly();
142 
143     /**
144      * Determine whether this request has been frozen, preventing any further updates.
145      * 
146      * @return true if the request has been frozen, or false otherwise
147      */
148     public boolean isFrozen() {
149         return frozen.get();
150     }
151 
152     /**
153      * Freeze this request to prevent any further modification. This method does nothing if the request is already frozen.
154      * 
155      * @return true if this request was frozen, or false if it was already frozen
156      */
157     public boolean freeze() {
158         if (frozen.compareAndSet(false, true)) {
159             // Was not already frozen, so decrement the latch (atomically)
160             CountDownLatch latch = this.freezingLatch;
161             if (latch != null) latch.countDown();
162             return true;
163         }
164         return false;
165     }
166 
167     /**
168      * Utility method to check that the request is not frozen, and if it is to throw an {@link IllegalStateException}.
169      * 
170      * @throws IllegalStateException if the request is frozen
171      */
172     protected void checkNotFrozen() throws IllegalStateException {
173         if (frozen.get()) {
174             throw new IllegalStateException(GraphI18n.requestIsFrozenAndMayNotBeChanged.text(this));
175         }
176     }
177 
178     /**
179      * Returns the type of the request
180      * 
181      * @return the type of the request
182      */
183     public abstract RequestType getType();
184 }