001: /*--------------------------------------------------------------------------*
002: | Copyright (C) 2006 Christopher Kohlhaas |
003: | |
004: | This program is free software; you can redistribute it and/or modify |
005: | it under the terms of the GNU General Public License as published by the |
006: | Free Software Foundation. A copy of the license has been included with |
007: | these distribution in the COPYING file, if not go to www.fsf.org |
008: | |
009: | As a special exception, you are granted the permissions to link this |
010: | program with every library, which license fulfills the Open Source |
011: | Definition as published by the Open Source Initiative (OSI). |
012: *--------------------------------------------------------------------------*/
013: package org.rapla.storage;
014:
015: import java.text.ParseException;
016: import java.util.ArrayList;
017: import java.util.Collection;
018: import java.util.Comparator;
019: import java.util.Date;
020: import java.util.HashMap;
021: import java.util.HashSet;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.Locale;
025: import java.util.Map;
026: import java.util.Set;
027: import java.util.SortedSet;
028: import java.util.TreeSet;
029:
030: import org.rapla.components.util.Assert;
031: import org.rapla.components.util.iterator.NestedIterator;
032: import org.rapla.entities.Category;
033: import org.rapla.entities.EntityNotFoundException;
034: import org.rapla.entities.RaplaType;
035: import org.rapla.entities.User;
036: import org.rapla.entities.configuration.Preferences;
037: import org.rapla.entities.domain.Allocatable;
038: import org.rapla.entities.domain.Appointment;
039: import org.rapla.entities.domain.AppointmentStartComparator;
040: import org.rapla.entities.domain.Period;
041: import org.rapla.entities.domain.Reservation;
042: import org.rapla.entities.dynamictype.Attribute;
043: import org.rapla.entities.dynamictype.DynamicType;
044: import org.rapla.entities.internal.CategoryImpl;
045: import org.rapla.entities.storage.EntityResolver;
046: import org.rapla.entities.storage.RefEntity;
047: import org.rapla.entities.storage.internal.SimpleIdentifier;
048: import org.rapla.framework.RaplaException;
049:
050: public class LocalCache implements EntityResolver {
051: Map passwords = new HashMap();
052:
053: Map entities;
054: Set dynamicTypes;
055: Set users;
056: Set resources;
057: Set reservations;
058: Set periods;
059:
060: Set categories;
061: Set appointments;
062: Set attributes;
063:
064: Set preferences;
065:
066: Map entityMap;
067: Map enities;
068:
069: Locale locale;
070:
071: // Index for start and end dates
072: TreeSet appointmentsStart;
073:
074: class IdComparator implements Comparator {
075: public int compare(Object o1, Object o2) {
076: SimpleIdentifier id1 = (SimpleIdentifier) ((RefEntity) o1)
077: .getId();
078: SimpleIdentifier id2 = (SimpleIdentifier) ((RefEntity) o2)
079: .getId();
080: if (id1.getKey() == id2.getKey())
081: return 0;
082: return (id1.getKey() < id2.getKey()) ? -1 : 1;
083: }
084: }
085:
086: private CategoryImpl super Category = new CategoryImpl();
087:
088: public LocalCache(Locale locale) {
089: this .locale = locale;
090: super Category.setId(LocalCache.SUPER_CATEGORY_ID);
091: super Category.setKey("supercategory");
092:
093: entityMap = new HashMap();
094: entities = new HashMap();
095: // top-level-entities
096: reservations = new TreeSet(new IdComparator());
097: periods = new TreeSet(new IdComparator());
098: users = new TreeSet(new IdComparator());
099: resources = new TreeSet(new IdComparator());
100: dynamicTypes = new TreeSet(new IdComparator());
101:
102: // non-top-level-entities with exception of one super-category
103: categories = new HashSet();
104: appointments = new HashSet();
105: preferences = new HashSet();
106: attributes = new HashSet();
107:
108: entityMap.put(DynamicType.TYPE, dynamicTypes);
109: entityMap.put(Attribute.TYPE, attributes);
110: entityMap.put(Category.TYPE, categories);
111: entityMap.put(Allocatable.TYPE, resources);
112: entityMap.put(User.TYPE, users);
113: entityMap.put(Period.TYPE, periods);
114: entityMap.put(Reservation.TYPE, reservations);
115: entityMap.put(Appointment.TYPE, appointments);
116: entityMap.put(Preferences.TYPE, preferences);
117:
118: appointmentsStart = new TreeSet(
119: new AppointmentStartComparator());
120: initSuperCategory();
121: }
122:
123: /** @return true if the entity has been removed and false if the entity was not found*/
124: public boolean remove(RefEntity entity) {
125: RaplaType raplaType = entity.getRaplaType();
126: Set entitySet = (Set) entityMap.get(raplaType);
127: boolean bResult = true;
128: if (entitySet != null) {
129: if (entities.get(entity.getId()) != null)
130: bResult = false;
131: if (entity.getId() == null)
132: return false;
133:
134: if (Appointment.TYPE.equals(raplaType)) {
135: removeAppointment(entity);
136: }
137:
138: entities.remove(entity.getId());
139: entitySet.remove(entity);
140: } else {
141: throw new RuntimeException(
142: "UNKNOWN TYPE. Can't remove object:"
143: + entity.getRaplaType());
144: }
145: return bResult;
146: }
147:
148: public void put(RefEntity entity) {
149: Assert.notNull(entity);
150: RaplaType raplaType = entity.getRaplaType();
151: Object id = entity.getId();
152: if (id == null)
153: throw new IllegalStateException("ID can't be null");
154:
155: Set entitySet = (Set) entityMap.get(raplaType);
156: if (entitySet != null) {
157:
158: if (Appointment.TYPE.equals(raplaType)) {
159: removeAppointment(entity);
160: appointmentsStart.add(entity);
161: }
162: entities.put(id, entity);
163: entitySet.remove(entity);
164: entitySet.add(entity);
165: } else {
166: throw new RuntimeException(
167: "UNKNOWN TYPE. Can't store object in cache: "
168: + entity.getRaplaType());
169: }
170: }
171:
172: public RefEntity get(Object id) {
173: if (id == null)
174: throw new RuntimeException("id is null");
175: return (RefEntity) entities.get(id);
176: }
177:
178: private void removeAppointment(RefEntity entity) {
179: if (appointments.remove(entity)) {
180: // start date could have been changed, so we probably won't find it with a binary search
181: if (!appointmentsStart.remove(entity)) {
182: Iterator it = appointmentsStart.iterator();
183: while (it.hasNext())
184: if (entity.equals(it.next())) {
185: it.remove();
186: break;
187: }
188: }
189: }
190: }
191:
192: public SortedSet getAppointments(User user, Date start, Date end) {
193: SortedSet appointmentSet = new TreeSet(
194: new AppointmentStartComparator());
195: Iterator it;
196: if (end != null) {
197: // all appointments that start before the enddate
198: it = appointmentsStart.headSet(end).iterator();
199: //it = appointments.values().iterator();
200: } else {
201: it = appointmentsStart.iterator();
202: }
203:
204: while (it.hasNext()) {
205: Appointment appointment = (Appointment) it.next();
206: // test if appointment end before the start-date
207: if (end != null && appointment.getStart().after(end))
208: break;
209:
210: // Ignore appointments without a reservation
211: if (appointment.getReservation() == null)
212: continue;
213:
214: if (!appointment.overlaps(start, end, false))
215: continue;
216: if (user == null || user.equals(appointment.getOwner())) {
217: appointmentSet.add(appointment);
218: }
219: }
220: return appointmentSet;
221: }
222:
223: public List getReservations(User user, Date start, Date end) {
224: HashSet reservationSet = new HashSet();
225: Iterator it = getAppointments(user, start, end).iterator();
226: while (it.hasNext()) {
227: Appointment appointment = (Appointment) it.next();
228: reservationSet.add(appointment.getReservation());
229: }
230: return new ArrayList(reservationSet);
231: }
232:
233: public Collection getCollection(RaplaType type) {
234: Set entities = (Set) entityMap.get(type);
235:
236: if (Period.TYPE.equals(type)) {
237: entities = new TreeSet(entities);
238: }
239:
240: if (entities != null) {
241: return entities;
242: } else {
243: throw new RuntimeException(
244: "UNKNOWN TYPE. Can't get collection: " + type);
245: }
246: }
247:
248: public Iterator getIterator(RaplaType type) throws RaplaException {
249: Set entities = (Set) entityMap.get(type);
250: if (entities != null) {
251: return entities.iterator();
252: }
253: throw new RaplaException("Can't get iterator for " + type);
254: }
255:
256: public void clearAll() {
257: passwords.clear();
258: Iterator it = entityMap.values().iterator();
259: while (it.hasNext()) {
260: ((Set) it.next()).clear();
261: }
262: appointmentsStart.clear();
263: entities.clear();
264: initSuperCategory();
265:
266: }
267:
268: private void initSuperCategory() {
269: entities.put(LocalCache.SUPER_CATEGORY_ID, super Category);
270: super Category.setReadOnly(false);
271: categories.add(super Category);
272: Category[] childs = super Category.getCategories();
273: for (int i = 0; i < childs.length; i++) {
274: super Category.removeCategory(childs[i]);
275: }
276: }
277:
278: public static Object SUPER_CATEGORY_ID = new SimpleIdentifier(
279: Category.TYPE, 0);
280:
281: public CategoryImpl getSuperCategory() {
282: return (CategoryImpl) get(SUPER_CATEGORY_ID);
283: }
284:
285: public Collection getAttributeList(Category category) {
286: HashSet result = new HashSet();
287: Iterator it = attributes.iterator();
288: while (it.hasNext()) {
289: Attribute attribute = (Attribute) it.next();
290: if (((RefEntity) attribute)
291: .isRefering((RefEntity) category))
292: result.add(attribute);
293: }
294: return result;
295: }
296:
297: public Collection getDynamicTypeList(Category category) {
298: HashSet result = new HashSet();
299: Iterator it = getAttributeList(category).iterator();
300: while (it.hasNext()) {
301: result.add(((Attribute) it.next()).getDynamicType());
302: }
303: return result;
304: }
305:
306: public Collection getReferers(RaplaType raplaType, RefEntity object) {
307: ArrayList result = new ArrayList();
308: Iterator it = getCollection(raplaType).iterator();
309: while (it.hasNext()) {
310: RefEntity referer = (RefEntity) it.next();
311: if (referer != null && referer.isRefering(object)) {
312: result.add(referer);
313: }
314: }
315: return result;
316: }
317:
318: public User getUser(String username) {
319: Iterator it = users.iterator();
320: while (it.hasNext()) {
321: User user = (User) it.next();
322: if (user.getUsername().equals(username))
323: return user;
324: }
325: return null;
326: }
327:
328: public Preferences getPreferences(User user) {
329: Iterator it = preferences.iterator();
330: while (it.hasNext()) {
331: Preferences pref = (Preferences) it.next();
332: if (user == null && pref.getOwner() == null) {
333: return pref;
334: }
335: if (user != null && pref.getOwner() != null
336: && user.equals(pref.getOwner())) {
337: return pref;
338: }
339:
340: }
341: return null;
342: }
343:
344: static public Object getId(RaplaType type, String str)
345: throws ParseException {
346: if (str == null)
347: throw new ParseException("Id string for " + type
348: + " can't be null", 0);
349:
350: int index = str.lastIndexOf("_") + 1;
351: if (index > str.length())
352: throw new ParseException("invalid rapla-id '" + str + "'",
353: index);
354: try {
355: return new SimpleIdentifier(type, Integer.parseInt(str
356: .substring(index)));
357: } catch (NumberFormatException ex) {
358: throw new ParseException("invalid rapla-id '" + str + "'",
359: index);
360: }
361: }
362:
363: public DynamicType getDynamicType(String elementKey) {
364: Iterator it = dynamicTypes.iterator();
365: while (it.hasNext()) {
366: DynamicType dt = (DynamicType) it.next();
367: if (dt.getElementKey().equals(elementKey))
368: return dt;
369: }
370: return null;
371: }
372:
373: public Iterator getVisibleEntities() {
374: return new NestedIterator(entityMap.keySet().iterator()) {
375: public Iterator getNestedIterator(Object key) {
376: RaplaType raplaType = (RaplaType) key;
377: if (Reservation.TYPE.equals(raplaType)
378: || Appointment.TYPE.equals(raplaType))
379: return null;
380: Set set = (Set) entityMap.get(key);
381: return set.iterator();
382: }
383: };
384: }
385:
386: public Iterator getAllEntities() {
387: return new NestedIterator(entityMap.keySet().iterator()) {
388: public Iterator getNestedIterator(Object raplaType) {
389: Set set = (Set) entityMap.get(raplaType);
390: return set.iterator();
391: }
392: /*
393: public Object next() {
394: Object obj = super.next();
395: System.out.println(obj);
396: return obj;
397: }
398: */
399: };
400: }
401:
402: // Implementation of EntityResolver
403: public RefEntity resolve(Object id) throws EntityNotFoundException {
404: if (!(id instanceof SimpleIdentifier))
405: new EntityNotFoundException("Unknown identifier class: "
406: + id.getClass()
407: + ". Only the SimpleIdentier class is supported.");
408: RefEntity entity = (RefEntity) get(id);
409:
410: if (entity == null)
411: throw new EntityNotFoundException("Object for id ["
412: + id.toString() + "] not found");
413: return entity;
414: }
415:
416: public String getPassword(Object userId) {
417: return (String) passwords.get(userId);
418: }
419:
420: public void putPassword(Object userId, String password) {
421: passwords.put(userId, password);
422: }
423:
424: public void putAll(Collection list) {
425: Iterator it = list.iterator();
426: while (it.hasNext()) {
427: put((RefEntity) it.next());
428: }
429:
430: }
431:
432: }
|