/* * Dog - Core * * Copyright (c) 2009-2014 Dario Bonino and Luigi De Russis * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package it.polito.elite.dog.core.housemodel.semantic.loader; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import it.polito.elite.dog.core.housemodel.semantic.SemanticHouseModel; import it.polito.elite.dog.core.housemodel.semantic.query.SPARQLQueryWrapper; import it.polito.elite.dog.core.library.util.LogHelper; import org.mindswap.pellet.jena.PelletInfGraph; import org.osgi.service.log.LogService; import com.hp.hpl.jena.ontology.Individual; import com.hp.hpl.jena.ontology.OntModel; import com.hp.hpl.jena.ontology.impl.OntResourceImpl; import com.hp.hpl.jena.rdf.model.NodeIterator; import com.hp.hpl.jena.rdf.model.Property; import com.hp.hpl.jena.rdf.model.RDFNode; /** * @author <a href="mailto:dario.bonino@polito.it">Dario Bonino</a> * @author <a href="mailto:luigi.derussis@polito.it">Luigi De Russis</a> * @see <a href="http://elite.polito.it">http://elite.polito.it</a> * */ public class ThreadedDeviceRemover extends Thread { // the device(s) to remove private String deviceToRemove; // the OntModel object to which the device must be added private OntModel theHome; private OntModel thePlainHome; // the SemanticHouseModel object for issuing the notify change event private SemanticHouseModel sHouseModel; // the query wrapper to use for performing queries on the model private SPARQLQueryWrapper qWrapper; // the properties to be used private volatile Property hasCommand; private volatile Property hasNotification; private volatile Property hasFunctionality; private volatile Property hasState; private volatile Property hasStateValue; private volatile String prefix; // The logger private LogHelper logger; public ThreadedDeviceRemover(String deviceURI, OntModel dogOntModel, OntModel plainDogOntModel, SemanticHouseModel parentModel) { // fill the instance variables this.deviceToRemove = deviceURI; this.theHome = dogOntModel; this.thePlainHome = plainDogOntModel; this.sHouseModel = parentModel; this.qWrapper = parentModel.getQWrapper(); this.prefix = this.sHouseModel.getNamespaces().get("dogOnt") + "#"; // get the main relations involving the device this.hasCommand = this.theHome.getProperty(prefix + "hasCommand"); this.hasNotification = this.theHome.getProperty(prefix + "hasNotification"); this.hasFunctionality = this.theHome.getProperty(prefix + "hasFunctionality"); this.hasState = this.theHome.getProperty(prefix + "hasState"); this.hasStateValue = this.theHome.getProperty(prefix + "hasStateValue"); // init the logger this.logger = this.sHouseModel.getLogger(); } // TODO: check if it works or not.... public void run() { // first disable reasoned model change detection ((PelletInfGraph) this.theHome.getGraph()).setAutoDetectChanges(false); // here the given device shall be removed, including all the related // instances // first, get the ontology individual representing the device, // please notice that here there is no "safe" notion on the correctness // of // the given device URI. Therefore we adopt the following policy: if the // given device URI // is in the short form (only the device unique name) the model entry // point URI is used for // expanding the given name to a full URI format. If no individual can // be found the process // is aborted and the error is logged // the Jena individual representing the individual to remove Individual deviceToRemoveInd; // check if it is a real URI URI devUri = null; try { devUri = new URI(deviceToRemove); } catch (URISyntaxException e) { logger.log(LogService.LOG_WARNING, "[SemanticHouseModel] The given device has not a valid URI format.\n" + e); } if ((devUri!=null) && (devUri.isAbsolute())) deviceToRemoveInd = this.thePlainHome.getIndividual(this.deviceToRemove); else deviceToRemoveInd = this.thePlainHome.getIndividual(this.sHouseModel.getEntryPoint() + "#" + this.qWrapper.toShortForm(this.deviceToRemove)); // check if an individual has been found, otherwise log the error and // close the task if (deviceToRemoveInd != null) { // Create a set of OntResources to remove ArrayList<OntResourceImpl> toRemove = new ArrayList<OntResourceImpl>(); // if here the individual is not null, then we can start to harvest // the related instances so as to // remove them in a clean way... // TODO: check if removal shall be open or can be a little bit // hard-wired (open is actually difficult... // get all the functionality instances NodeIterator fIter = deviceToRemoveInd.listPropertyValues(this.hasFunctionality); // iterate over the functionalities associated to the device while (fIter.hasNext()) { // the RDF node representing the functionality individual RDFNode fNode = fIter.next(); // check individual // if(fNode instanceof Individual) // { // get the property values NodeIterator cIter = ((OntResourceImpl) fNode).listPropertyValues(this.hasCommand); while (cIter.hasNext()) { RDFNode cNode = cIter.next(); // if(cNode instanceof Individual) // { toRemove.add((OntResourceImpl) cNode); // } } // get the property values NodeIterator nIter = ((OntResourceImpl) fNode).listPropertyValues(this.hasNotification); while (nIter.hasNext()) { RDFNode nNode = nIter.next(); // if(nNode instanceof Individual) // { toRemove.add((OntResourceImpl) nNode); // } } // } toRemove.add((OntResourceImpl) fNode); } // get all the state instances NodeIterator sIter = deviceToRemoveInd.listPropertyValues(this.hasState); // iterate over the states associated to the device while (sIter.hasNext()) { // the RDF node representing the state individual RDFNode sNode = sIter.next(); // check individual // if(sNode instanceof Individual) // { // get the property values NodeIterator svIter = ((OntResourceImpl) sNode).listPropertyValues(this.hasStateValue); while (svIter.hasNext()) { RDFNode svNode = svIter.next(); // if(svNode instanceof Individual) // { toRemove.add((OntResourceImpl) svNode); // } } toRemove.add((OntResourceImpl) sNode); // } } toRemove.add((OntResourceImpl) deviceToRemoveInd); // remove all this.thePlainHome.enterCriticalSection(true); for (OntResourceImpl toRemoveNow : toRemove) { toRemoveNow.remove(); } this.thePlainHome.leaveCriticalSection(); // here the device has been completely removed, // send the updated model notification and log removal this.logger.log(LogService.LOG_INFO, "[ThreadedDeviceRemover] removed: " + this.deviceToRemove); // re-enable automatic change detection // first disable reasoned model change detection ((PelletInfGraph) this.theHome.getGraph()).setAutoDetectChanges(true); // send notification //this.sHouseModel.notifyRemovedDevice(new DeviceDescriptor(this.deviceToRemove)); } else { // log the error... this.logger.log(LogService.LOG_WARNING, "[ThreadedDeviceRemover] failed to locate the individual to remove."); } } }