/* * Licensed Materials - Property of Perforce Software, Inc. * © Copyright Perforce Software, Inc. 2014, 2021 * © Copyright IBM Corp. 2009, 2014 * © Copyright ILOG 1996, 2009 * All Rights Reserved. * * Note to U.S. Government Users Restricted Rights: * The Software and Documentation were developed at private expense and * are "Commercial Items" as that term is defined at 48 CFR 2.101, * consisting of "Commercial Computer Software" and * "Commercial Computer Software Documentation", as such terms are * used in 48 CFR 12.212 or 48 CFR 227.7202-1 through 227.7202-4, * as applicable. */ package database; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import ilog.views.gantt.IlvActivity; import ilog.views.gantt.IlvConstraint; import ilog.views.gantt.IlvConstraintType; import ilog.views.gantt.IlvGanttModel; import ilog.views.gantt.IlvGanttModelUtil; import ilog.views.gantt.IlvReservation; import ilog.views.gantt.IlvResource; import ilog.views.gantt.IlvTimeInterval; /** * <code>GanttModelDBROWrapper</code> simulates a read-only database of * scheduling data by wrapping an existing * {@link ilog.views.gantt.IlvGanttModel}. The supplied Gantt data model is * fully traversed to create simulated database lookup keys for each activity, * resource, constraint, and reservation. This class supports relational queries * on the data through the <code>GanttDBRO</code> interface. */ public class GanttModelDBROWrapper implements GanttDBRO { // ========================================= // Class Constants // ========================================= /** * Log ID. */ public static final String logID = "GanttDB"; // ========================================= // Instance Variables // ========================================= /** * The underlying data model. */ private IlvGanttModel ganttData; /** * The simulated database latency, in milliseconds. */ private long delay; /** * The monitor that serializes access to the <code>doQueryDelay()</code> * method. */ private Object delayLock; // ========================================= // Instance Construction and Initialization // ========================================= /** * Creates a new <code>GanttModelDBROWrapper</code> using the data from the * specified Gantt data model. */ public GanttModelDBROWrapper(IlvGanttModel data) { delay = 0; delayLock = new Object(); ganttData = data; initDBKeys(); } /** * Computes and stores all the database lookup keys. */ private void initDBKeys() { initActivityKeys(); initResourceKeys(); initReservationKeys(); initConstraintKeys(); } /** * Implements a delay that simulates the latency of performing a real database * query. */ private void doQueryDelay() { if (delay > 0) { // Synchronized so multiple threads must wait for each other to do their // delay. This simulates a single database connection accessed from // multiple threads. synchronized (delayLock) { try { Thread.sleep(delay); } catch (InterruptedException e) { } } } } /** * Returns the delay, in milliseconds, that simulates database access latency. */ public long getLatency() { return delay; } /** * Sets the delay, in milliseconds, that simulates database access latency. */ public void setLatency(long delay) { this.delay = delay; } // ========================================= // Activities // ========================================= /** * Lookup table of activities, keyed by their lookup key. */ private Map<String, IlvActivity> activities; /** * Reverse lookup table of activity keys, keyed by the activity. */ private Map<IlvActivity, String> activityKeys; /** * The next assignable activity key value. */ private long nextActivityKey = 0; /** * Computes and stores the activity lookup keys. */ private void initActivityKeys() { activities = new HashMap<String, IlvActivity>(); activityKeys = new HashMap<IlvActivity, String>(); for (Iterator<IlvActivity> i = IlvGanttModelUtil.activityPreorderIterator(ganttData); i.hasNext();) { IlvActivity a = i.next(); String key = "Act" + (nextActivityKey++); activities.put(key, a); activityKeys.put(a, key); } } /** * Returns a descriptive string for the activity specified by its lookup key. */ protected String activityString(String key) { IlvActivity a = activities.get(key); StringBuffer buf = new StringBuffer(); buf.append('['); buf.append(key); buf.append(','); if (a == null) buf.append("???"); else { buf.append('"'); buf.append(a.getName()); buf.append('"'); } buf.append(']'); return buf.toString(); } /** * Returns the lookup key for the root activity or <code>null</code> if there * are no activities. */ Override public String queryRootActivityKey() { IlvActivity root = ganttData.getRootActivity(); String key = (root == null) ? null : activityKeys.get(root); Logger.getLogger(logID).log(Level.INFO, "[DB] Query root activity key: {0}", key); doQueryDelay(); return key; } /** * Returns the <code>Activity</code> record for the activity specified by its * lookup key. */ Override public GanttDBRO.ActivityRecord queryActivity(String key) { IlvActivity a = activities.get(key); ActivityRec arec; if (a == null) { arec = null; } else { arec = new ActivityRec(key, a.getID(), a.getName(), a.getStartTime(), a.getEndTime()); } Logger.getLogger(logID).log(Level.INFO, "[DB] Query activity properties: {0}", activityString(key)); doQueryDelay(); return arec; } /** * Returns the lookup key for the parent of the specified parent activity. If * the activity is the root activity, then it has no parent and this method * will return <code>null</code>. */ Override public String queryActivityParent(String key) { IlvActivity a = activities.get(key); String parentKey; if (a == null) { parentKey = null; } else { IlvActivity parent = ganttData.getParentActivity(a); if (parent == null) parentKey = null; else parentKey = activityKeys.get(parent); } String[] logParams = { activityString(key), activityString(parentKey) }; Logger.getLogger(logID).log(Level.INFO, "[DB] Query parent key of activity: {0}, parent={1}", logParams); doQueryDelay(); return parentKey; } /** * Returns an array of lookup keys for the children of the specified parent * activity. */ Override public String[] queryActivityChildren(String key) { IlvActivity a = activities.get(key); String[] childKeys; if (a == null) { childKeys = new String[0]; } else { childKeys = new String[ganttData.getChildActivityCount(a)]; for (int i = 0; i < childKeys.length; i++) { childKeys[i] = activityKeys.get(ganttData.getChildActivity(a, i)); } } Logger.getLogger(logID).log(Level.INFO, "[DB] Query child keys of activity: {0}", activityString(key)); doQueryDelay(); return childKeys; } public static class ActivityRec implements GanttDBRO.ActivityRecord { private String key; private String name; private String id; private Date start; private Date end; private ActivityRec(String key, String id, String name, Date start, Date end) { this.key = key; this.id = id; this.name = name; this.start = start; this.end = end; } Override public String getKey() { return key; } Override public String getName() { return name; } Override public String getID() { return id; } Override public Date getStart() { return start; } Override public Date getEnd() { return end; } } // ========================================= // Resources // ========================================= /** * Lookup table of resources, keyed by their lookup key. */ private Map<String, IlvResource> resources; /** * Reverse lookup table of resource keys, keyed by the resource. */ private Map<IlvResource, String> resourceKeys; /** * The next assignable resource key value. */ private long nextResourceKey = 0; /** * Computes and stores the resource lookup keys. */ private void initResourceKeys() { resources = new HashMap<String, IlvResource>(); resourceKeys = new HashMap<IlvResource, String>(); for (Iterator<IlvResource> i = IlvGanttModelUtil.resourcePreorderIterator(ganttData); i.hasNext();) { IlvResource a = i.next(); String key = "Res" + (nextResourceKey++); resources.put(key, a); resourceKeys.put(a, key); } } /** * Returns a descriptive string for the resource specified by its lookup key. */ protected String resourceString(String key) { IlvResource r = resources.get(key); StringBuffer buf = new StringBuffer(); buf.append('['); buf.append(key); buf.append(','); if (r == null) buf.append("???"); else { buf.append('"'); buf.append(r.getName()); buf.append('"'); } buf.append(']'); return buf.toString(); } /** * Returns the lookup key for the root resource or <code>null</code> if there * are no resources. */ Override public String queryRootResourceKey() { IlvResource root = ganttData.getRootResource(); String key = (root == null) ? null : resourceKeys.get(root); Logger.getLogger(logID).log(Level.INFO, "[DB] Query root resource key: {0}", key); doQueryDelay(); return key; } /** * Returns the <code>Resource</code> record for the resource specified by its * lookup key. */ Override public GanttDBRO.ResourceRecord queryResource(String key) { IlvResource r = resources.get(key); ResourceRec rrec; if (r == null) { rrec = null; } else { rrec = new ResourceRec(key, r.getID(), r.getName(), r.getQuantity()); } Logger.getLogger(logID).log(Level.INFO, "[DB] Query resource properties: {0}", resourceString(key)); doQueryDelay(); return rrec; } /** * Returns the lookup key for the parent of the specified parent resource. If * the resource is the root resource, then it has no parent and this method * will return <code>null</code>. */ Override public String queryResourceParent(String key) { IlvResource r = resources.get(key); String parentKey; if (r == null) { parentKey = null; } else { IlvResource parent = ganttData.getParentResource(r); if (parent == null) parentKey = null; else parentKey = resourceKeys.get(parent); } String[] logParams = { resourceString(key), resourceString(parentKey) }; Logger.getLogger(logID).log(Level.INFO, "[DB] Query parent key of resource: {0}, parent={1}", logParams); doQueryDelay(); return parentKey; } /** * Returns an array of lookup keys for the children of the specified parent * resource. */ Override public String[] queryResourceChildren(String key) { IlvResource r = resources.get(key); String[] childKeys; if (r == null) { childKeys = new String[0]; } else { childKeys = new String[ganttData.getChildResourceCount(r)]; for (int i = 0; i < childKeys.length; i++) { childKeys[i] = resourceKeys.get(ganttData.getChildResource(r, i)); } } Logger.getLogger(logID).log(Level.INFO, "[DB] Query child keys of resource: {0}", resourceString(key)); doQueryDelay(); return childKeys; } public static class ResourceRec implements GanttDBRO.ResourceRecord { private String key; private String name; private String id; private float quantity; private ResourceRec(String key, String id, String name, float qty) { this.key = key; this.id = id; this.name = name; this.quantity = qty; } Override public String getKey() { return key; } Override public String getName() { return name; } Override public String getID() { return id; } Override public float getQuantity() { return quantity; } } // ========================================= // Reservations // ========================================= /** * Lookup table of reservations, keyed by their lookup key. */ private Map<String, IlvReservation> reservations; /** * Reverse lookup table of reservation keys, keyed by the reservation. */ private Map<IlvReservation, String> reservationKeys; /** * The next assignable reservation key value. */ private long nextReservationKey = 0; /** * Computes and stores the reservation lookup keys. */ private void initReservationKeys() { reservations = new HashMap<String, IlvReservation>(); reservationKeys = new HashMap<IlvReservation, String>(); for (Iterator<IlvReservation> i = ganttData.reservationIterator(); i.hasNext();) { IlvReservation r = i.next(); String key = "Rsn" + (nextReservationKey++); reservations.put(key, r); reservationKeys.put(r, key); } } /** * Returns a descriptive string for the reservation specified by its lookup * key. */ protected String reservationString(String key) { IlvReservation r = reservations.get(key); String activityKey = activityKeys.get(r.getActivity()); String resourceKey = resourceKeys.get(r.getResource()); StringBuffer buf = new StringBuffer(); buf.append('['); buf.append(key); buf.append(','); buf.append(activityString(activityKey)); buf.append(','); buf.append(resourceString(resourceKey)); buf.append(']'); return buf.toString(); } /** * Returns an array of reservation lookup keys derived from all the * reservations that are traversed by the specified reservation iterator of * the underlying data model. */ private String[] getReservationKeys(Iterator<IlvReservation> reservationIter) { List<String> keyList = new ArrayList<String>(); while (reservationIter.hasNext()) { IlvReservation reservation = reservationIter.next(); String key = reservationKeys.get(reservation); keyList.add(key); } String[] keyArray = new String[keyList.size()]; keyList.toArray(keyArray); return keyArray; } /** * Returns an array of lookup keys for all the reservations. */ Override public String[] queryReservations() { String[] reservationKeys = getReservationKeys(ganttData.reservationIterator()); Logger.getLogger(logID).log(Level.INFO, "[DB] Query all reservation keys"); doQueryDelay(); return reservationKeys; } /** * Returns an array of lookup keys for all the reservations that are * associated with an activity, specified by its lookup key. */ Override public String[] queryReservationsForActivity(String activityKey) { IlvActivity activity = activities.get(activityKey); String[] reservationKeys = getReservationKeys(ganttData.reservationIterator(activity)); Logger.getLogger(logID).log(Level.INFO, "[DB] Query reservation keys for activity: {0}", activityString(activityKey)); doQueryDelay(); return reservationKeys; } /** * Returns an array of lookup keys for all the reservations that are * associated with a resource, specified by its lookup key. */ Override public String[] queryReservationsForResource(String resourceKey) { IlvResource resource = resources.get(resourceKey); String[] reservationKeys = getReservationKeys(ganttData.reservationIterator(resource)); Logger.getLogger(logID).log(Level.INFO, "[DB] Query reservation keys for resource: {0}", resourceString(resourceKey)); doQueryDelay(); return reservationKeys; } /** * Returns an array of lookup keys for all the reservations that are * associated with a resource, specified by its lookup key, and that intersect * the specified time range. */ Override public String[] queryReservationsForResource(String resourceKey, Date start, Date end) { IlvResource resource = resources.get(resourceKey); IlvTimeInterval interval = new IlvTimeInterval(start, end); String[] reservationKeys = getReservationKeys(ganttData.reservationIterator(resource, interval)); Object[] logParams = { resourceString(resourceKey), start, end }; Logger.getLogger(logID).log(Level.INFO, "[DB] Query reservation keys for resource: {0}, time span: {1} - {2}", logParams); doQueryDelay(); return reservationKeys; } /** * Returns the <code>Reservation</code> record for the resource specified by * its lookup key. */ Override public GanttDBRO.ReservationRecord queryReservation(String key) { IlvReservation r = reservations.get(key); ReservationRec rrec; if (r == null) { rrec = null; } else { String activityKey = activityKeys.get(r.getActivity()); String resourceKey = resourceKeys.get(r.getResource()); rrec = new ReservationRec(key, activityKey, resourceKey); } Logger.getLogger(logID).log(Level.INFO, "[DB] Query reservation properties: {0}", reservationString(key)); doQueryDelay(); return rrec; } public static class ReservationRec implements GanttDBRO.ReservationRecord { private String key; private String activityKey; private String resourceKey; private ReservationRec(String key, String activityKey, String resourceKey) { this.key = key; this.activityKey = activityKey; this.resourceKey = resourceKey; } Override public String getKey() { return key; } Override public String getActivityKey() { return activityKey; } Override public String getResourceKey() { return resourceKey; } } // ========================================= // Constraints // ========================================= /** * Lookup table of constraints, keyed by their lookup key. */ private Map<String, IlvConstraint> constraints; /** * Reverse lookup table of constraint keys, keyed by the constraint. */ private Map<IlvConstraint, String> constraintKeys; /** * The next assignable constraint key value. */ private long nextConstraintKey = 0; /** * Computes and stores the constraint lookup keys. */ private void initConstraintKeys() { constraints = new HashMap<String, IlvConstraint>(); constraintKeys = new HashMap<IlvConstraint, String>(); for (Iterator<IlvConstraint> i = ganttData.constraintIterator(); i.hasNext();) { IlvConstraint r = i.next(); String key = "Cnt" + (nextConstraintKey++); constraints.put(key, r); constraintKeys.put(r, key); } } /** * Returns a descriptive string for the constraint specified by its lookup * key. */ protected String constraintString(String key) { IlvConstraint c = constraints.get(key); String fromActivityKey = activityKeys.get(c.getFromActivity()); String toActivityKey = activityKeys.get(c.getToActivity()); StringBuffer buf = new StringBuffer(); buf.append('['); buf.append(key); buf.append(','); buf.append(c.getType()); buf.append(",from="); buf.append(activityString(fromActivityKey)); buf.append(",to="); buf.append(activityString(toActivityKey)); buf.append(']'); return buf.toString(); } /** * Returns an array of constraint lookup keys derived from all the constraints * that are traversed by the specified constraint iterator of the underlying * data model. */ private String[] getConstraintKeys(Iterator<IlvConstraint> constraintIter) { List<String> keyList = new ArrayList<String>(); while (constraintIter.hasNext()) { IlvConstraint constraint = constraintIter.next(); String key = constraintKeys.get(constraint); keyList.add(key); } String[] keyArray = new String[keyList.size()]; keyList.toArray(keyArray); return keyArray; } /** * Returns an array of lookup keys for all the constraints. */ Override public String[] queryConstraints() { String[] constraintKeys = getConstraintKeys(ganttData.constraintIterator()); Logger.getLogger(logID).log(Level.INFO, "[DB] Query all constraint keys"); doQueryDelay(); return constraintKeys; } /** * Returns an array of lookup keys for all the constraints that have the * specified activity as their source or <i>from</i> activity, specified by * its lookup key. */ Override public String[] queryConstraintsFromActivity(String activityKey) { IlvActivity activity = activities.get(activityKey); String[] constraintKeys = getConstraintKeys(ganttData.constraintIteratorFromActivity(activity)); Logger.getLogger(logID).log(Level.INFO, "[DB] Query all constraint keys from activity: {0}", activityString(activityKey)); doQueryDelay(); return constraintKeys; } /** * Returns an array of lookup keys for all the constraints that have the * specified activity as their target or <i>to</i> activity, specified by its * lookup key. */ Override public String[] queryConstraintsToActivity(String activityKey) { IlvActivity activity = activities.get(activityKey); String[] constraintKeys = getConstraintKeys(ganttData.constraintIteratorToActivity(activity)); Logger.getLogger(logID).log(Level.INFO, "[DB] Query all constraint keys to activity: {0}", activityString(activityKey)); doQueryDelay(); return constraintKeys; } /** * Returns the <code>Constraint</code> record for the constraint specified by * its lookup key. */ Override public GanttDBRO.ConstraintRecord queryConstraint(String key) { IlvConstraint c = constraints.get(key); ConstraintRec crec; if (c == null) { crec = null; } else { String fromActivityKey = activityKeys.get(c.getFromActivity()); String toActivityKey = activityKeys.get(c.getToActivity()); crec = new ConstraintRec(key, c.getType(), fromActivityKey, toActivityKey); } Logger.getLogger(logID).log(Level.INFO, "[DB] Query constraint properties: {0}", constraintString(key)); doQueryDelay(); return crec; } public static class ConstraintRec implements GanttDBRO.ConstraintRecord { private String key; private IlvConstraintType type; private String fromActivityKey; private String toActivityKey; private ConstraintRec(String key, IlvConstraintType type, String fromActivityKey, String toActivityKey) { this.key = key; this.type = type; this.fromActivityKey = fromActivityKey; this.toActivityKey = toActivityKey; } Override public String getKey() { return key; } Override public IlvConstraintType getType() { return type; } Override public String getFromActivityKey() { return fromActivityKey; } Override public String getToActivityKey() { return toActivityKey; } } }