001: /*
002: * Bossa Workflow System
003: *
004: * $Id: ResourceRegistry.java,v 1.14 2004/01/29 21:24:37 gdvieira Exp $
005: *
006: * Copyright (C) 2003,2004 OpenBR Sistemas S/C Ltda.
007: *
008: * This file is part of Bossa.
009: *
010: * Bossa is free software; you can redistribute it and/or modify it
011: * under the terms of version 2 of the GNU General Public License as
012: * published by the Free Software Foundation.
013: *
014: * This program is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017: * General Public License for more details.
018: *
019: * You should have received a copy of the GNU General Public
020: * License along with this program; if not, write to the
021: * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
022: * Boston, MA 02111-1307, USA.
023: */
024:
025: package com.bigbross.bossa.resource;
026:
027: import java.io.Serializable;
028: import java.util.ArrayList;
029: import java.util.HashMap;
030: import java.util.Iterator;
031: import java.util.List;
032: import java.util.Map;
033:
034: import com.bigbross.bossa.Bossa;
035: import com.bigbross.bossa.BossaException;
036:
037: /**
038: * This class stores registered resources. <p>
039: *
040: * @author <a href="http://www.bigbross.com">BigBross Team</a>
041: */
042: public class ResourceRegistry implements Serializable {
043:
044: private String id;
045:
046: private ResourceRegistry super Context;
047:
048: private Map resources;
049:
050: private Map contexts;
051:
052: /**
053: * Creates a new empty resource registry. <p>
054: *
055: * @param id the id of this registry.
056: */
057: public ResourceRegistry(String id) {
058: this .id = id;
059: this .super Context = null;
060: this .resources = new HashMap();
061: this .contexts = new HashMap();
062: }
063:
064: /**
065: * Returns the id of this registry. <p>
066: *
067: * @return the id of this registry.
068: */
069: public String getId() {
070: return id;
071: }
072:
073: /**
074: * Sets a context as the super context of this registry. <p>
075: *
076: * @param context the super context.
077: */
078: public void setSuperContext(ResourceRegistry context) {
079: this .super Context = context;
080: }
081:
082: /**
083: * Returns the super context of this registry. <p>
084: *
085: * @return the super context of this registry.
086: */
087: public ResourceRegistry getSuperContext() {
088: return super Context;
089: }
090:
091: /**
092: * Returns the top level resource registry, the resource manager. <p>
093: *
094: * @return the resource manager, <code>null</code> if the root registry
095: * is not a resource manager.
096: */
097: ResourceManager getResourceManager() {
098: if (super Context == null) {
099: return null;
100: } else {
101: return super Context.getResourceManager();
102: }
103: }
104:
105: /**
106: * Returns the bossa engine this resource registry is part, if any. <p>
107: *
108: * @return the bossa engine this resource registry is part,
109: * <code>null</code> if not part of a bossa engine.
110: */
111: Bossa getBossa() {
112: if (getResourceManager() != null) {
113: return getResourceManager().getBossa();
114: } else {
115: return null;
116: }
117: }
118:
119: /**
120: * Returns the global id of this registry. This is the id that allows
121: * the retrieval of this registry from the resource manager. <p>
122: *
123: * @return the resource manager.
124: */
125: String getGlobalId() {
126: if (super Context == null) {
127: return getId();
128: } else {
129: return super Context.getGlobalId() + "." + getId();
130: }
131: }
132:
133: /**
134: * Registers this resource registry in the resource manager, if it
135: * exists. If this registry contains sub contexts, they will be
136: * registered also. <p>
137: *
138: * @return <code>true</code> if there is a resource manager and this
139: * registry was succesfully registered or if there is no
140: * resource manager,
141: * <code>false</code> if there is already a registry with the
142: * same global id in the resource manager.
143: */
144: private boolean registerInResourceManager() {
145: ResourceManager resourceManager = getResourceManager();
146: if (resourceManager == null) {
147: return true;
148: }
149: if (!resourceManager.addRegistry(this )) {
150: return false;
151: }
152: Iterator i = contexts.values().iterator();
153: while (i.hasNext()) {
154: if (!((ResourceRegistry) i.next())
155: .registerInResourceManager()) {
156: return false;
157: }
158: }
159: return true;
160: }
161:
162: /**
163: * Unregisters this resource registry in the resource manager, if it
164: * exists. If this registry contains sub contexts, they will be
165: * unregistered also. <p>
166: *
167: * @return <code>true</code> if there is a resource manager and this
168: * registry was succesfully unregistered or if there is no
169: * resource manager,
170: * <code>false</code> if the global id of this registry was
171: * not found in the resource manager.
172: */
173: private boolean unregisterInResourceManager() {
174: ResourceManager resourceManager = getResourceManager();
175: if (resourceManager == null) {
176: return true;
177: }
178: if (!resourceManager.removeRegistry(this )) {
179: return false;
180: }
181: Iterator i = contexts.values().iterator();
182: while (i.hasNext()) {
183: if (!((ResourceRegistry) i.next())
184: .unregisterInResourceManager()) {
185: return false;
186: }
187: }
188: return true;
189: }
190:
191: /**
192: * Returns the resource with the given id. <p>
193: *
194: * @param id the resource id.
195: * @return the <code>Resource</code> object,
196: * <code>null</code> if there is no resource with this id.
197: */
198: public Resource getResource(String id) {
199: return (Resource) resources.get(id);
200: }
201:
202: /**
203: * Returns all registered resources. <p>
204: *
205: * @return a list of all resources registered.
206: */
207: public List getResources() {
208: ArrayList resourceList = new ArrayList();
209: resourceList.addAll(resources.values());
210: return resourceList;
211: }
212:
213: /**
214: * Creates a new resource in this registry. <p>
215: *
216: * @param id the id of the resource to be created.
217: * @return the created <code>Resource</code> object,
218: * <code>null</code> if there is already a resource with this id.
219: * @exception PersistenceException if an error occours when making the
220: * execution of this method persistent.
221: */
222: public Resource createResource(String id) throws BossaException {
223: ResourceTransaction createTransaction = new CreateResource(id);
224: return (Resource) getBossa().execute(createTransaction);
225: }
226:
227: /**
228: * Creates a new resource in this registry. <p>
229: *
230: * This method does not create a transaction in the prevalent system. The
231: * execution of this method will not be persistent unless it is called
232: * inside an appropriate transaction. <p>
233: *
234: * @param id the id of the resource to be created.
235: * @param notify if this operation should be notified.
236: * @return the created <code>Resource</code> object,
237: * <code>null</code> if there is already a resource with this id.
238: */
239: public Resource createResourceImpl(String id, boolean notify) {
240: if ((id != null) && !resources.containsKey(id)) {
241: Resource resource = new Resource(this , id);
242: resources.put(id, resource);
243: if (notify) {
244: ResourceEvents queue = new ResourceEvents();
245: queue.newSingleResourceEvent(getBossa(),
246: ResourceEvents.ID_CREATE_RESOURCE, resource);
247: queue.notifyAll(getBossa());
248: }
249: return resource;
250: } else {
251: return null;
252: }
253: }
254:
255: /**
256: * Removes a resource from this registry. <p>
257: *
258: * @param resource the resource to be removed.
259: * @return <code>true</code> if the resource was removed,
260: * <code>false</code> if the resource was not found.
261: * @exception PersistenceException if an error occours when making the
262: * execution of this method persistent.
263: */
264: public boolean removeResource(Resource resource)
265: throws BossaException {
266: ResourceTransaction removeTransaction = new RemoveResource(
267: resource);
268: return ((Boolean) getBossa().execute(removeTransaction))
269: .booleanValue();
270: }
271:
272: /**
273: * Removes a resource from this registry. <p>
274: *
275: * This method does not create a transaction in the prevalent system. The
276: * execution of this method will not be persistent unless it is called
277: * inside an appropriate transaction. <p>
278: *
279: * @param resource the resource to be removed.
280: * @param notify if this operation should be notified.
281: * @return <code>true</code> if the resource was removed,
282: * <code>false</code> if the resource was not found.
283: */
284: public boolean removeResourceImpl(Resource resource, boolean notify) {
285: if (resources.remove(resource.getId()) != null) {
286: clearReferences(resource, notify);
287: if (notify) {
288: ResourceEvents queue = new ResourceEvents();
289: queue.newSingleResourceEvent(getBossa(),
290: ResourceEvents.ID_REMOVE_RESOURCE, resource);
291: queue.notifyAll(getBossa());
292: }
293: return true;
294: } else {
295: return false;
296: }
297: }
298:
299: /**
300: * Removes any direct reference to a resource from all resources in
301: * this registry. <p>
302: *
303: * @param resource the resource to be removed.
304: * @param notify if removals triggered by this operation should be notified.
305: */
306: private void clearReferences(Resource resource, boolean notify) {
307: Iterator i = resources.values().iterator();
308: while (i.hasNext()) {
309: ((Resource) i.next()).removeImpl(resource, notify);
310: }
311: i = contexts.values().iterator();
312: while (i.hasNext()) {
313: ((ResourceRegistry) i.next()).clearReferences(resource,
314: notify);
315: }
316: }
317:
318: /**
319: * Registers another resource registry as a sub context of this resource
320: * registry. All entries in the sub context are expected to possibly
321: * depend on the entries of this registry, and are notified of resource
322: * removals. <p>
323: *
324: * Also, if this registry tree is rooted at a resource manager, the
325: * registry tree being registered is put in the global registry index.
326: * <p>
327: *
328: * @param context the sub context.
329: * @return <code>true</code> if the sub context was added,
330: * <code>false</code> if the sub context was already present.
331: */
332: public boolean registerSubContext(ResourceRegistry context) {
333: if (!contexts.containsKey(context.getId())) {
334: context.setSuperContext(this );
335: if (context.registerInResourceManager()) {
336: contexts.put(context.getId(), context);
337: return true;
338: } else {
339: context.setSuperContext(null);
340: }
341: }
342: return false;
343: }
344:
345: /**
346: * Returns the registered sub context with the given id. <p>
347: *
348: * @param id the sub context id.
349: * @return the sub context,
350: * <code>null</code> if the sub context was not found.
351: */
352: ResourceRegistry getSubContext(String id) {
353: return (ResourceRegistry) contexts.get(id);
354: }
355:
356: /**
357: * Remove the provided registry from the list of registered sub contexts
358: * of this registry. <p>
359: *
360: * Also, if this registry tree is rooted at a resource manager, the
361: * registry tree being removed is removed from the global registry index.
362: * <p>
363: *
364: * @param context the sub context.
365: * @return <code>true</code> if the sub context was removed,
366: * <code>false</code> if the sub context was not found.
367: */
368: public boolean removeSubContext(ResourceRegistry context) {
369: ResourceRegistry myContext = (ResourceRegistry) contexts
370: .get(context.getId());
371: if (myContext != null) {
372: myContext.unregisterInResourceManager();
373: myContext.setSuperContext(null);
374: contexts.remove(myContext.getId());
375: return true;
376: } else {
377: return false;
378: }
379: }
380:
381: /**
382: * Compiles a resource expression. <p>
383: *
384: * It uses this <code>ResourceManager</code> to link the resources in
385: * the expression.
386: *
387: * @param expression the resource expression to be compiled.
388: * @return a <code>Expression</code> representing the compiled resource
389: * expression.
390: */
391: public Expression compile(String expression) {
392: return Expression.compile(this, expression);
393: }
394: }
|