001: /*
002: * $Header: /export/home/cvsroot/MyPersonalizerRepository/MyPersonalizer/Subsystems/Admin/Sources/es/udc/mypersonalizer/admin/http/controller/actions/prototypes/util/ServicePrototypeSessionManager.java,v 1.1.1.1 2004/03/25 12:08:38 fbellas Exp $
003: * $Revision: 1.1.1.1 $
004: * $Date: 2004/03/25 12:08:38 $
005: *
006: * =============================================================================
007: *
008: * Copyright (c) 2003, The MyPersonalizer Development Group
009: * (http://www.tic.udc.es/~fbellas/mypersonalizer/index.html) at
010: * University Of A Coruna
011: * All rights reserved.
012: *
013: * Redistribution and use in source and binary forms, with or without
014: * modification, are permitted provided that the following conditions are met:
015: *
016: * - Redistributions of source code must retain the above copyright notice,
017: * this list of conditions and the following disclaimer.
018: *
019: * - Redistributions in binary form must reproduce the above copyright notice,
020: * this list of conditions and the following disclaimer in the documentation
021: * and/or other materials provided with the distribution.
022: *
023: * - Neither the name of the University Of A Coruna nor the names of its
024: * contributors may be used to endorse or promote products derived from
025: * this software without specific prior written permission.
026: *
027: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
028: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
029: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
030: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
031: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
032: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
033: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
034: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
035: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
036: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
037: * POSSIBILITY OF SUCH DAMAGE.
038: *
039: */
040:
041: package es.udc.mypersonalizer.admin.http.controller.actions.prototypes.util;
042:
043: import java.util.Collection;
044: import java.util.ArrayList;
045: import java.util.Iterator;
046:
047: import javax.servlet.http.HttpServletRequest;
048: import javax.servlet.http.HttpSession;
049:
050: import es.udc.mypersonalizer.kernel.model.properties.Property;
051: import es.udc.mypersonalizer.kernel.model.properties.CompoundProperty;
052: import es.udc.mypersonalizer.kernel.model.properties.PropertyStructure;
053: import es.udc.mypersonalizer.kernel.model.actions.ActionProcessorSingleton;
054: import es.udc.mypersonalizer.kernel.util.exceptions.InternalErrorException;
055: import es.udc.mypersonalizer.kernel.util.exceptions.ModelException;
056: import es.udc.mypersonalizer.kernel.util.exceptions.InstanceNotFoundException;
057: import es.udc.mypersonalizer.kernel.model.repository.interfaces.ServicePrototype;
058:
059: import es.udc.mypersonalizer.admin.model.types.prototypes.CommitChangesInServicePrototypesEvent;
060: import es.udc.mypersonalizer.admin.http.controller.actions.prototypes.util.ServicePrototypeStatus;
061:
062: /**
063: * This class is a controller facade that implements the access to the
064: * prototypes in the session controlling the prototypes status and having the
065: * responsability of commit the changes to the prototypes to database.
066: * <p>
067: * The key for a protoype status stored in session is the service (prototype)
068: * identifier, but with a special prefix added.
069: *
070: * @author Abel Iago Toral Quiroga
071: * @see ServicePrototypeStatus
072: * @since 1.0
073: */
074: public class ServicePrototypeSessionManager {
075:
076: /** A constant prefix for service prototype objects stored in session. */
077: private static final String SERVICE_PROTOTYPE_SESSION_PREFIX = "es.udc.mypersonalizer.admin.servicePrototypeStatus.";
078:
079: /**
080: * Controls if the session has been initialized with all prototypes in
081: * database. If false, the first time a prototype is requested, the session
082: * cache will be filled with all prototypes in only one query.
083: */
084: private static boolean sessionInitialized = false;
085:
086: private ServicePrototypeSessionManager() {
087: }
088:
089: /**
090: * Finds and returns a prototype. If the prototype is not in session this
091: * method will look for the prototype in database and will add it to
092: * session.
093: * @param request the current request.
094: * @param prototypeIdentifier the <code>serviceIdentifier</code>.
095: * @throws InternalErrorException if an error ocurred.
096: * @return a <code>ServicePrototype</code> representing the current
097: * prototype or null if the prototype does not exist.
098: * @see ServicePrototypeStatus
099: */
100: public static ServicePrototype findServicePrototype(
101: HttpServletRequest request, String prototypeIdentifier)
102: throws InternalErrorException {
103:
104: ServicePrototypeStatus prototypeStatus = findServicePrototypeStatus(
105: request, prototypeIdentifier);
106:
107: ServicePrototype prototype = null;
108: if (prototypeStatus != null) {
109: prototype = prototypeStatus.getPrototype();
110: }
111:
112: return prototype;
113: }
114:
115: /**
116: * Checks a prototype for update. If the prototype is checked to
117: * create status it will not be modified, else it will be checked to
118: * to update status.
119: * @param request the current request.
120: * @param prototypeIdentifier the <code>serviceIdentifier</code>.
121: * @param newPrototype the modified service prototype.
122: * @throws InternalErrorException if prototype does not exist or another
123: * severe error ocurs
124: * @see ServicePrototypeStatus
125: */
126: public static void updateServicePrototype(
127: HttpServletRequest request, String prototypeIdentifier,
128: ServicePrototype newPrototype)
129: throws InternalErrorException {
130:
131: ServicePrototypeStatus prototypeStatus = findServicePrototypeStatus(
132: request, prototypeIdentifier);
133:
134: if (prototypeStatus == null) {
135: throw new InternalErrorException(
136: new InstanceNotFoundException(prototypeIdentifier,
137: ServicePrototype.class.getName()));
138: } else {
139: prototypeStatus.setPrototype(newPrototype);
140: prototypeStatus.setStatus(ServicePrototypeStatus.MODIFIED);
141: }
142: }
143:
144: /**
145: * Resets a service prototype (only its personalization property, not
146: * its buttons state property), to an empty one (with 0 values).
147: * @param request the http request.
148: * @param prototypeIdentifier the <code>serviceIdentifier.
149: * @throws InternalErrorException if a severe error eccured.
150: */
151: public static void resetServicePrototype(
152: HttpServletRequest request, String prototypeIdentifier)
153: throws InternalErrorException {
154:
155: ServicePrototype currentServicePrototype = findServicePrototypeStatusInSession(
156: request, prototypeIdentifier).getPrototype();
157:
158: Property emptyPrototypeProperty = createEmptyProperty(prototypeIdentifier);
159:
160: currentServicePrototype
161: .setServiceProperty(emptyPrototypeProperty);
162:
163: updateServicePrototype(request, prototypeIdentifier,
164: currentServicePrototype);
165: }
166:
167: /**
168: * Finds all modified prototypes and returns a Collection with their
169: * <code>ServicePrototypeStatus</code>.
170: * @param request the current request.
171: * @return A Collection of <code>ServicePrototypeStatus</code> objects,
172: * one by each modified service prototype.
173: * @throws InternalErrorException if an error ocurred while retriving
174: * modified prototypes
175: * @see ServicePrototypeStatus
176: */
177: public static Collection getAllModifiedServicePrototypesStatus(
178: HttpServletRequest request) throws InternalErrorException {
179:
180: Collection modifiedServicePrototypesStatus = new ArrayList();
181:
182: Collection allServicePrototypeStatus = findAllServicePrototypesStatus(request);
183:
184: Iterator allServicePrototypeStatusIterator = allServicePrototypeStatus
185: .iterator();
186:
187: while (allServicePrototypeStatusIterator.hasNext()) {
188:
189: ServicePrototypeStatus serviceProtoypeStatus = (ServicePrototypeStatus) allServicePrototypeStatusIterator
190: .next();
191:
192: if (serviceProtoypeStatus.getStatus() == ServicePrototypeStatus.MODIFIED) {
193: modifiedServicePrototypesStatus
194: .add(serviceProtoypeStatus);
195: }
196: }
197:
198: return modifiedServicePrototypesStatus;
199: }
200:
201: /**
202: * Finds and returns a protoype status. If the prototype is not in session
203: * this method will look for the prototype in database and will add it to
204: * session.
205: * @param request the current request.
206: * @param prototypeIdentifier the serviceIdentifier.
207: * @return a <code> ServicePrototypeStatus</code> object if the prototype
208: * exists or null if it does not.
209: * @throws InternalErrorException if a error ocurred
210: * @see ServicePrototypeStatus
211: */
212: public static ServicePrototypeStatus findServicePrototypeStatus(
213: HttpServletRequest request, String prototypeIdentifier)
214: throws InternalErrorException {
215:
216: /* First try to find it in the current session */
217: ServicePrototypeStatus servicePrototypeStatus = findServicePrototypeStatusInSession(
218: request, prototypeIdentifier);
219:
220: /* If failed, try to retrive the prototype from database */
221: if (servicePrototypeStatus == null) {
222: ServicePrototype servicePrototype = null;
223: try {
224: ActionProcessorSingleton actionProcessor = ActionProcessorSingleton
225: .getInstance();
226:
227: servicePrototype = (ServicePrototype) actionProcessor
228: .execute("FindServicePrototypeAction",
229: prototypeIdentifier);
230: } catch (ModelException e) {
231: throw new InternalErrorException(e);
232: }
233:
234: /* Hook prototype to current session */
235: addServicePrototype(request, prototypeIdentifier,
236: servicePrototype,
237: ServicePrototypeStatus.NOT_MODIFIED);
238: servicePrototypeStatus = findServicePrototypeStatusInSession(
239: request, prototypeIdentifier);
240: }
241:
242: return servicePrototypeStatus;
243: }
244:
245: /**
246: * Commit changes to a set of prototypes to database.
247: * @param request the current request.
248: * @param prototypesIdentifiers the services identfiers whose prototypes
249: * will be commited.
250: * @throws InternalErrorException if an error ocurred.
251: */
252: public static void commit(HttpServletRequest request,
253: Collection prototypesIdentifiers)
254: throws InternalErrorException {
255:
256: /* Get selected prototypes to commit from session */
257: Collection protoypesToCommit = new ArrayList();
258: Iterator iterator = prototypesIdentifiers.iterator();
259:
260: while (iterator.hasNext()) {
261:
262: String prototypeIdentifier = (String) iterator.next();
263:
264: ServicePrototypeStatus prototypeStatus = findServicePrototypeStatusInSession(
265: request, prototypeIdentifier);
266:
267: if (prototypeStatus == null) {
268: throw new InternalErrorException(new Exception(
269: "Couldn't find prototype identified by "
270: + prototypeIdentifier
271: + " in current session"));
272: } else {
273: protoypesToCommit.add(prototypeStatus.getPrototype());
274: }
275: }
276:
277: /* Do commit */
278: try {
279:
280: ActionProcessorSingleton actionProcessor = ActionProcessorSingleton
281: .getInstance();
282:
283: actionProcessor.execute(
284: "CommitChangesInServicePrototypesAction",
285: new CommitChangesInServicePrototypesEvent(
286: protoypesToCommit));
287:
288: } catch (ModelException e) {
289: throw new InternalErrorException(e);
290: }
291:
292: /* Commited, so set the commited prototypes to NOT_MODIFIED status */
293: Iterator commitedPrototypes = prototypesIdentifiers.iterator();
294: while (commitedPrototypes.hasNext()) {
295:
296: String prototypeIdentifier = (String) commitedPrototypes
297: .next();
298:
299: ServicePrototypeStatus prototypeStatus = findServicePrototypeStatusInSession(
300: request, prototypeIdentifier);
301:
302: prototypeStatus
303: .setStatus(ServicePrototypeStatus.NOT_MODIFIED);
304: }
305: }
306:
307: /**
308: * Finds and returns all service prototype status.
309: * This method also initializes the session cache with all service
310: * prototypes the first time it is called using the
311: * <code>initializeCache()</code> method.
312: * This method also ensures that only prototypes of currently existing
313: * services are mantained in session.
314: * @return a <code>Collection</code> with all service prototypes status.
315: * @throws InternalErrorException if a severe error occured.
316: */
317: public static Collection findAllServicePrototypesStatus(
318: HttpServletRequest request) throws InternalErrorException {
319:
320: try {
321:
322: /* This will fill the session cache with all the prototypes the
323: first time this method is called, so the code after this
324: will work faster in next calls. */
325: if (!sessionInitialized) {
326: initializeSession(request);
327: }
328:
329: /*
330: * Only show those that are in database
331: */
332:
333: /* Get all service identifiers */
334: Collection serviceIdentifiers = (Collection) ActionProcessorSingleton
335: .getInstance().execute(
336: "FindAllServiceIdentifiersAction", "");
337:
338: Iterator serviceIdentifiersIterator = serviceIdentifiers
339: .iterator();
340:
341: /* Get all services prototypes status */
342: Collection servicePrototypesStatus = new ArrayList();
343: while (serviceIdentifiersIterator.hasNext()) {
344:
345: String serviceIdentifier = (String) serviceIdentifiersIterator
346: .next();
347:
348: ServicePrototypeStatus currentServicePrototypeStatus = findServicePrototypeStatus(
349: request, serviceIdentifier);
350:
351: servicePrototypesStatus
352: .add(currentServicePrototypeStatus);
353: }
354:
355: /* Remove those service protoypes that aren't in database */
356:
357: return servicePrototypesStatus;
358:
359: } catch (Exception e) {
360: throw new InternalErrorException(e);
361: }
362: }
363:
364: /**
365: * Retrieves all service prototypes. (Only "real" services).
366: * Uses <code>FindAllServicePrototypesAction</code> model action
367: * to retrive all from database.
368: * @return a <code>Collection</code> of <code>ServicePrototype</code>
369: * objects with all service prototypes.
370: * @throws InternalErrorException if a severe error occured.
371: */
372: private static Collection findAllServicePrototypes()
373: throws InternalErrorException {
374:
375: /* Retrive all service prototypes */
376: Collection allServicePrototypes = null;
377: try {
378: allServicePrototypes = (Collection) ActionProcessorSingleton
379: .getInstance().execute(
380: "FindAllServicePrototypesAction", "");
381: } catch (ModelException e) {
382: throw new InternalErrorException(e);
383: }
384:
385: return allServicePrototypes;
386: }
387:
388: /**
389: * Gets (and creates if neccesary) a <code>HttpSession</code> object.
390: * @param request the current request.
391: * @return a <code>HttpSession</code> object.
392: * @see ServicePrototypeStatus
393: */
394: private static HttpSession getSession(HttpServletRequest request) {
395: return request.getSession(true);
396: }
397:
398: /**
399: * Looks for a prototype status in the current session.
400: * @param request the current request.
401: * @param prototypeIdentifier the service identifier.
402: * @return a <code>ServicePrototypeStatus</code> object or null if there
403: * is not a prototype status for the service in the currrent session.
404: * @see ServicePrototypeStatus
405: */
406: private static ServicePrototypeStatus findServicePrototypeStatusInSession(
407: HttpServletRequest request, String prototypeIdentifier) {
408:
409: HttpSession session = getSession(request);
410: return getPrototypeStatusFromSession(session,
411: prototypeIdentifier);
412: }
413:
414: /**
415: * Adds a prototype to session checked to a specific status.
416: * @param request the current request.
417: * @param prototypeIdentifier the service identifier.
418: * @param prototype the prototype for this service.
419: * @param status the status for this prototype.
420: * @see ServicePrototypeStatus
421: */
422: private static void addServicePrototype(HttpServletRequest request,
423: String prototypeIdentifier, ServicePrototype prototype,
424: int status) {
425:
426: HttpSession session = getSession(request);
427: ServicePrototypeStatus servicePrototypeStatus = new ServicePrototypeStatus(
428: prototype, prototypeIdentifier, status);
429: setPrototypeStatusInSession(session, prototypeIdentifier,
430: servicePrototypeStatus);
431: }
432:
433: /**
434: * Adds a prototype status to session or updates its value. The prototype
435: * status key in session will have
436: * <code>SERVICE_PROTOTYPE_SESSION_PREFIX</code> prefix.
437: * @param session The session.
438: * @param prototypeIdentifier the service identifier whose prototype is
439: * going to be added or updated.
440: * @param value The prototype status.
441: */
442: private static void setPrototypeStatusInSession(
443: HttpSession session, String prototypeIdentifier,
444: ServicePrototypeStatus value) {
445:
446: session.setAttribute(SERVICE_PROTOTYPE_SESSION_PREFIX
447: + prototypeIdentifier, value);
448: }
449:
450: /**
451: * Retrives a prototype status from session. This method will add
452: * <code>SERVICE_PROTOTYPE_SESSION_PREFIX</code> prefix to the prototype
453: * identifier to find it.
454: * @param session The session.
455: * @param prototypeIdentifier the service identifier whose prototype is
456: * going to be finded.
457: * @return The prototype status or null if it is not found.
458: */
459: private static ServicePrototypeStatus getPrototypeStatusFromSession(
460: HttpSession session, String prototypeIdentifier) {
461:
462: Object sessionObject = session
463: .getAttribute(SERVICE_PROTOTYPE_SESSION_PREFIX
464: + prototypeIdentifier);
465:
466: /* Be sure this object is a protoype status */
467: ServicePrototypeStatus sessionObjectAsStatus = null;
468: if (sessionObject instanceof ServicePrototypeStatus) {
469: sessionObjectAsStatus = (ServicePrototypeStatus) sessionObject;
470: }
471:
472: return sessionObjectAsStatus;
473: }
474:
475: /**
476: * Retrives all "real" service prototypes from database, then creates
477: * their status in session. This method is called the first time that
478: * a user requests a prototype.
479: * @param request the http request.
480: * @throws InternalErrorException if a severe error occured.
481: */
482: private static void initializeSession(HttpServletRequest request)
483: throws InternalErrorException {
484:
485: try {
486: /* Get all "real" service prototypes */
487: Iterator servicePrototypes = findAllServicePrototypes()
488: .iterator();
489:
490: /* Initialize their status in session */
491: while (servicePrototypes.hasNext()) {
492: ServicePrototype servicePrototype = (ServicePrototype) servicePrototypes
493: .next();
494: addServicePrototype(request, servicePrototype
495: .getIdentifier(), servicePrototype,
496: ServicePrototypeStatus.NOT_MODIFIED);
497: }
498:
499: sessionInitialized = true;
500: } catch (Exception e) {
501: throw new InternalErrorException(e);
502: }
503: }
504:
505: /**
506: * Creates an empty (with 0 values) root property for a service prototype.
507: * Used to reset a prototype.
508: * @param prototypeIdentifier the service identifier.
509: * @return an "empty" property.
510: */
511: private static Property createEmptyProperty(
512: String prototypeIdentifier) throws InternalErrorException {
513:
514: return (new CompoundProperty(prototypeIdentifier,
515: new PropertyStructure[0]));
516:
517: }
518: }
|