001package org.biopax.paxtools.controller; 002 003import org.apache.commons.logging.Log; 004import org.apache.commons.logging.LogFactory; 005import org.biopax.paxtools.model.BioPAXElement; 006import org.biopax.paxtools.model.BioPAXFactory; 007import org.biopax.paxtools.model.Model; 008 009import java.util.HashSet; 010import java.util.Set; 011 012/** 013 * Specifically "Clones" the BioPAX elements set 014 * (traverses to obtain dependent elements), 015 * puts them to the new model using the visitor and traverser framework; 016 * ignores elements that are not in the source list (compare to {@link Fetcher}) 017 * 018 * @see org.biopax.paxtools.controller.Visitor 019 * @see org.biopax.paxtools.controller.Traverser 020 */ 021public class Cloner implements Visitor 022{ 023 private static final Log LOG = LogFactory.getLog(Cloner.class); 024 025 Traverser traverser; 026 private BioPAXFactory factory; 027 private Model targetModel; 028 029 public Cloner(EditorMap map, BioPAXFactory factory) 030 { 031 this.factory = factory; 032 this.traverser = new Traverser(map, this); 033 this.targetModel = null; 034 } 035 036 037 /** 038 * For each element from the 'toBeCloned' list, 039 * it creates a copy in the new model, setting all 040 * the data properties; however, object property values 041 * that refer to BioPAX elements not in 'toBeCloned' list 042 * are ignored. 043 * 044 * @param source model 045 * @param toBeCloned elements to clone 046 * @return a new model containing the cloned biopax objects 047 */ 048 public Model clone(Model source, Set<BioPAXElement> toBeCloned) 049 { 050 this.targetModel = factory.createModel(); 051 052 for (BioPAXElement bpe : new HashSet<BioPAXElement>(toBeCloned)) 053 { 054 // make a copy (all properties are empty except for ID) 055 if(targetModel.containsID(bpe.getRDFId())) { 056 throw new RuntimeException("There are same URI different objects " 057 + "in the input set, uri:" + bpe.getRDFId()); 058 } 059 targetModel.addNew(bpe.getModelInterface(), bpe.getRDFId()); 060 } 061 062 // a hack to avoid unnecessary checks for the valid sub-model being cloned, 063 // and warnings when the Cloner copies BPS.stepProcess values, 064 // and there is a Conversion among them (-always unless stepConversion is null). 065 AbstractPropertyEditor.checkRestrictions.set(false); 066 067 for (BioPAXElement bpe : toBeCloned) 068 { 069 traverser.traverse(bpe, source); 070 } 071 072 AbstractPropertyEditor.checkRestrictions.set(true); //back to the default mode 073 074 return targetModel; 075 } 076 077// --------------------- Interface Visitor --------------------- 078 079 public void visit(BioPAXElement domain, Object range, Model model, PropertyEditor editor) 080 { 081 BioPAXElement targetDomain = targetModel.getByID(domain.getRDFId()); 082 083 if (range instanceof BioPAXElement) 084 { 085 BioPAXElement bpe = (BioPAXElement) range; 086 BioPAXElement existing = targetModel.getByID(bpe.getRDFId()); 087 //set the property value if the value is already present in the target 088 if (existing != null) { 089 editor.setValueToBean(existing, targetDomain); 090 } 091 } 092 else 093 { 094 editor.setValueToBean(range, targetDomain); 095 } 096 } 097} 098 099 100