/** ****************************************************************************** * @file UAVObjectManager.java * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012. * @brief Critical class. This is the data store for all UAVOs. Allows * other objects to access and change this data. Takes care of * propagating changes to the UAV. * @see The GNU Public License (GPL) Version 3 * *****************************************************************************/ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.openpilot_nonag.uavtalk; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; import java.util.Observable; import java.util.Observer; public class UAVObjectManager { public class CallbackListener extends Observable { public void event (UAVObject obj) { setChanged(); notifyObservers(obj); } } private final CallbackListener newInstance = new CallbackListener(); public void addNewInstanceObserver(Observer o) { synchronized(newInstance) { newInstance.addObserver(o); } } private final CallbackListener newObject = new CallbackListener(); public void addNewObjectObserver(Observer o) { synchronized(newObject) { newObject.addObserver(o); } } private final int MAX_INSTANCES = 10; // Use array list to store objects since rarely added or deleted private final List<List<UAVObject>> objects = new ArrayList<List<UAVObject>>(); public UAVObjectManager() { //mutex = new QMutex(QMutex::Recursive); } /** * Register an object with the manager. This function must be called for all newly created instances. * A new instance can be created directly by instantiating a new object or by calling clone() of * an existing object. The object will be registered and will be properly initialized so that it can accept * updates. * @throws Exception */ public synchronized boolean registerObject(UAVDataObject obj) throws Exception { ListIterator<List<UAVObject>> objIt = objects.listIterator(0); // Check if this object type is already in the list while(objIt.hasNext()) { List<UAVObject> instList = objIt.next(); // Check if the object ID is in the list if( (instList.size() > 0) && (instList.get(0).getObjID() == obj.getObjID() )) { // Check if this is a single instance object, if yes we can not add a new instance if(obj.isSingleInstance()) { return false; } // The object type has alredy been added, so now we need to initialize the new instance with the appropriate id // There is a single metaobject for all object instances of this type, so no need to create a new one // Get object type metaobject from existing instance UAVDataObject refObj = (UAVDataObject) instList.get(0); if (refObj == null) { return false; } UAVMetaObject mobj = refObj.getMetaObject(); // Make sure we aren't requesting to create too many instances if(obj.getInstID() >= MAX_INSTANCES || instList.size() >= MAX_INSTANCES || obj.getInstID() < 0) { return false; } // If InstID is zero then we find the next open instId and create it if (obj.getInstID() == 0) { // Assign the next available ID and initialize the object instance the nadd obj.initialize(instList.size(), mobj); instList.add(obj); return true; } // Check if that inst ID already exists ListIterator<UAVObject> instIter = instList.listIterator(); while(instIter.hasNext()) { UAVObject testObj = instIter.next(); if(testObj.getInstID() == obj.getInstID()) { return false; } } // If the instance ID is specified and not at the default value (0) then we need to make sure // that there are no gaps in the instance list. If gaps are found then then additional instances // will be created. for(long instId = instList.size(); instId < obj.getInstID(); instId++) { UAVDataObject newObj = obj.clone(instId); newObj.initialize(mobj); instList.add(newObj); newInstance.event(newObj); } obj.initialize(mobj); instList.add(obj); newInstance.event(obj); instIter = instList.listIterator(); while(instIter.hasNext()) { UAVObject testObj = instIter.next(); if(testObj.getInstID() == obj.getInstID()) { return false; } } // Check if there are any gaps between the requested instance ID and the ones in the list, // if any then create the missing instances. for (long instId = instList.size(); instId < obj.getInstID(); ++instId) { UAVDataObject cobj = obj.clone(instId); cobj.initialize(mobj); instList.add(cobj); newInstance.event(cobj); } // Finally, initialize the actual object instance obj.initialize(mobj); // Add the actual object instance in the list instList.add(obj); newInstance.event(obj); return true; } } // If this point is reached then this is the first time this object type (ID) is added in the list // create a new list of the instances, add in the object collection and create the object's metaobject // Create metaobject String mname = obj.getName(); mname += "Meta"; UAVMetaObject mobj = new UAVMetaObject(obj.getObjID()+1, mname, obj); // Initialize object obj.initialize(0, mobj); // Add to list addObject(obj); addObject(mobj); return true; } public synchronized void addObject(UAVObject obj) { // Add to list List<UAVObject> ls = new ArrayList<UAVObject>(); ls.add(obj); objects.add(ls); newObject.event(obj); } /** * Get all objects. A two dimentional QList is returned. Objects are grouped by * instances of the same object type. */ public List<List<UAVObject>> getObjects() { return objects; } /** * Same as getObjects() but will only return DataObjects. */ public synchronized List< List<UAVDataObject> > getDataObjects() { List< List<UAVDataObject> > dObjects = new ArrayList< List<UAVDataObject> > (); // Go through objects and copy to new list when types match ListIterator<List<UAVObject>> objIt = objects.listIterator(0); // Check if this object type is already in the list while(objIt.hasNext()) { List<UAVObject> instList = objIt.next(); // If no instances skip if(instList.size() == 0) continue; // If meta data skip if(instList.get(0).isMetadata()) continue; List<UAVDataObject> newInstList = new ArrayList<UAVDataObject>(); ListIterator<UAVObject> instIt = instList.listIterator(); while(instIt.hasNext()) { newInstList.add((UAVDataObject) instIt.next()); } dObjects.add(newInstList); } // Done return dObjects; } /** * Same as getObjects() but will only return MetaObjects. */ public synchronized List <List<UAVMetaObject> > getMetaObjects() { List< List<UAVMetaObject> > mObjects = new ArrayList< List<UAVMetaObject> > (); // Go through objects and copy to new list when types match ListIterator<List<UAVObject>> objIt = objects.listIterator(0); // Check if this object type is already in the list while(objIt.hasNext()) { List<UAVObject> instList = objIt.next(); // If no instances skip if(instList.size() == 0) continue; // If meta data skip if(!instList.get(0).isMetadata()) continue; List<UAVMetaObject> newInstList = new ArrayList<UAVMetaObject>(); ListIterator<UAVObject> instIt = instList.listIterator(); while(instIt.hasNext()) { newInstList.add((UAVMetaObject) instIt.next()); } mObjects.add(newInstList); } // Done return mObjects; } /** * Returns a specific object by name only, returns instance ID zero * @param name The object name * @return The object or null if not found */ public UAVObject getObject(String name) { return getObject(name, 0, 0); } /** * Get a specific object given its name and instance ID * @returns The object is found or NULL if not */ public UAVObject getObject(String name, long instId) { return getObject(name, 0, instId); } /** * Get a specific object with given object ID and instance ID zero * @param objId the object id * @returns The object is found or NULL if not */ public UAVObject getObject(long objId) { return getObject(null, objId, 0); } /** * Get a specific object given its object and instance ID * @returns The object is found or NULL if not */ public UAVObject getObject(long objId, long instId) { return getObject(null, objId, instId); } /** * Helper function for the public getObject() functions. */ public synchronized UAVObject getObject(String name, long objId, long instId) { // Check if this object type is already in the list ListIterator<List<UAVObject>> objIter = objects.listIterator(); while(objIter.hasNext()) { List<UAVObject> instList = objIter.next(); if (instList.size() > 0) { if ( (name != null && instList.get(0).getName().compareTo(name) == 0) || (name == null && instList.get(0).getObjID() == objId) ) { // Look for the requested instance ID ListIterator<UAVObject> iter = instList.listIterator(); while(iter.hasNext()) { UAVObject obj = iter.next(); if(obj.getInstID() == instId) { return obj; } } } } } return null; } /** * Get all the instances of the object specified by name */ public List<UAVObject> getObjectInstances(String name) { return getObjectInstances(name, 0); } /** * Get all the instances of the object specified by its ID */ public List<UAVObject> getObjectInstances(long objId) { return getObjectInstances(null, objId); } /** * Helper function for the public getObjectInstances() */ public synchronized List<UAVObject> getObjectInstances(String name, long objId) { // Check if this object type is already in the list ListIterator<List<UAVObject>> objIter = objects.listIterator(); while(objIter.hasNext()) { List<UAVObject> instList = objIter.next(); if (instList.size() > 0) { if ( (name != null && instList.get(0).getName().compareTo(name) == 0) || (name == null && instList.get(0).getObjID() == objId) ) { return instList; } } } return null; } /** * Get the number of instances for an object given its name */ public int getNumInstances(String name) { return getNumInstances(name, 0); } /** * Get the number of instances for an object given its ID */ public int getNumInstances(long objId) { return getNumInstances(null, objId); } /** * Helper function for public getNumInstances */ public int getNumInstances(String name, long objId) { return getObjectInstances(name,objId).size(); } }