DefinitionModel.java

  1. /*
  2.  * Copyright © 2017, Salesforce.com, Inc
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions are met:
  7.  *     * Redistributions of source code must retain the above copyright
  8.  *       notice, this list of conditions and the following disclaimer.
  9.  *     * Redistributions in binary form must reproduce the above copyright
  10.  *       notice, this list of conditions and the following disclaimer in the
  11.  *       documentation and/or other materials provided with the distribution.
  12.  *     * Neither the name of the <organization> nor the
  13.  *       names of its contributors may be used to endorse or promote products
  14.  *       derived from this software without specific prior written permission.
  15.  *
  16.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  17.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19.  * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  20.  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21.  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26.  */
  27. package com.salesforce.apt.graph.model;

  28. import java.util.ArrayList;
  29. import java.util.Collection;
  30. import java.util.Collections;
  31. import java.util.HashMap;
  32. import java.util.HashSet;
  33. import java.util.List;
  34. import java.util.Map;
  35. import java.util.Set;

  36. import javax.lang.model.element.TypeElement;

  37. public class DefinitionModel extends AbstractModel {

  38.   private final List<InstanceModel> objectDefinitions = new ArrayList<>();
  39.   private final List<ExpectedModel> expectedDefinitions = new ArrayList<>();
  40.   private final List<String> dependencyNames = new ArrayList<>();
  41.  
  42.   //because this field is transient, deserializers will not set it.  We must
  43.   //carefully account for this by setting the value anywhere it may be used.
  44.   private transient List<DefinitionModel> dependencies;
  45.   private final List<InstanceModel> providedInstances = new ArrayList<>();
  46.   private final Set<ExpectedModel> computedExpected = new HashSet<>();
  47.   private String sha256;          //when read from/written to file.
  48.   private String sourceLocation;  //when read from file
  49.   private final boolean rootNode;
  50.  
  51.   private final Map<String, String> dependencyNameToSha256 = new HashMap<>();  
  52.  
  53.   private transient boolean lockedSourceRead = false;                  //phase 1
  54.   private transient boolean lockedDefintionsMerged = false;            //phase 2
  55.   private transient boolean lockedAnalyzed = false;                    //phase 3

  56.   private void failIfLockRead() {
  57.     if (isLockedSourceRead()) {
  58.       throw new IllegalStateException("Attempting to modify 'source read' content after source read is locked");
  59.     }
  60.   }
  61.  
  62.   private void failIfDefintionsMerged() {
  63.     lockSourceRead();
  64.     if (isLockedDefintionsMerged()) {
  65.       throw new IllegalStateException("Attempting to modify 'definition merge' content after definition merge is locked named: "
  66.         + getIdentity() + " sourced from: " + getSourceLocation() + " of class: " + getSourceClass());
  67.     }
  68.   }
  69.  
  70.   private void failIfLockedAnalyzed() {
  71.     lockDefintionsMerged();
  72.     if (isLockedAnalyzed()) {
  73.       throw new IllegalStateException("Attempting to modify analyzed structure after structure has been computed");
  74.     }
  75.   }
  76.  
  77.   /**
  78.    * Is this node marked as a root node, meaning noone can depend upon it.
  79.    *
  80.    * @return true if this is a root node, and no other nodes may depend on it.
  81.    */
  82.   public boolean isRootNode() {
  83.     return rootNode;
  84.   }
  85.  
  86.   private void setDepenendencyArrayIfNull() {
  87.     if (dependencies == null) {
  88.       dependencies = new ArrayList<>();
  89.     }
  90.   }
  91.  
  92.   public List<DefinitionModel> getDependencies() {
  93.     setDepenendencyArrayIfNull();
  94.     lockDefintionsMerged();
  95.     return Collections.unmodifiableList(dependencies);
  96.   }

  97.   public DefinitionModel(String name) {
  98.     this(name, false);
  99.   }

  100.   public DefinitionModel(String name, boolean rootNode) {
  101.     super(name);
  102.     this.rootNode = rootNode;
  103.   }
  104.  
  105.   public DefinitionModel(TypeElement type) {
  106.     this(type, false);
  107.   }
  108.  
  109.   public DefinitionModel(TypeElement type, boolean rootNode) {
  110.     super(type);
  111.     this.rootNode = rootNode;
  112.   }

  113.   public void addDependency(DefinitionModel model) {
  114.     setDepenendencyArrayIfNull();
  115.     failIfDefintionsMerged();
  116.     this.dependencies.add(model);
  117.   }

  118.   public void addDependencies(List<DefinitionModel> model) {
  119.     setDepenendencyArrayIfNull();
  120.     failIfDefintionsMerged();
  121.     this.dependencies.addAll(model);
  122.   }

  123.   public void addDefinition(InstanceModel model) {
  124.     failIfLockRead();
  125.     this.objectDefinitions.add(model);
  126.   }

  127.   public void addDefinition(ExpectedModel model) {
  128.     failIfLockRead();
  129.     this.expectedDefinitions.add(model);
  130.   }

  131.   public void addDependencyNames(List<String> model) {
  132.     failIfLockRead();
  133.     this.dependencyNames.addAll(model);
  134.   }
  135.  
  136.   public void addDependencyNames(String dependencyName) {
  137.     failIfLockRead();
  138.     this.dependencyNames.add(dependencyName);
  139.   }

  140.   public List<String> getDependencyNames() {
  141.     lockSourceRead();
  142.     return Collections.unmodifiableList(dependencyNames);
  143.   }
  144.  
  145.   public List<InstanceModel> getObjectDefinitions() {
  146.     lockSourceRead();
  147.     return Collections.unmodifiableList(objectDefinitions);
  148.   }

  149.   public List<ExpectedModel> getExpectedDefinitions() {
  150.     lockSourceRead();
  151.     return Collections.unmodifiableList(expectedDefinitions);
  152.   }

  153.   public boolean isComplete() {
  154.     return getExpectedDefinitions().size() == 0;
  155.   }
  156.  
  157.   public List<InstanceModel> getProvidedInstances() {
  158.     lockAnalyzed();
  159.     return Collections.unmodifiableList(providedInstances);
  160.   }
  161.  
  162.   public void addAllProvidedInstances(Collection<InstanceModel> providedInstances) {
  163.     failIfLockedAnalyzed();
  164.     this.providedInstances.addAll(providedInstances);
  165.   }

  166.   public Set<ExpectedModel> getComputedExpected() {
  167.     lockAnalyzed();
  168.     return Collections.unmodifiableSet(computedExpected);
  169.   }
  170.  
  171.   public void addAllComputedExpected(Collection<ExpectedModel> computedExpected) {
  172.     failIfLockedAnalyzed();
  173.     this.computedExpected.addAll(computedExpected);
  174.   }
  175.  
  176.   public void addComputedExpected(ExpectedModel computedExpected) {
  177.     failIfLockedAnalyzed();
  178.     this.computedExpected.add(computedExpected);
  179.   }
  180.  
  181.   /**
  182.    * For the purposes of identification of the object definition class, the location of the class suffices.
  183.    *
  184.    * @return a unique identity representing this definition, specifically the fully qualified name of the source type.
  185.    */
  186.   public String getIdentity() {
  187.     //wont lockSourceRead(); as identity is read while attaching definitions.
  188.     return getElementLocation();
  189.   }

  190.   /**
  191.    * For the purposes of identification of the object definition class, the location of the class suffices.
  192.    *
  193.    * @return the Identity of the {@link DefinitionModel}
  194.    */
  195.   public String toString() {
  196.     lockSourceRead();
  197.     return getElementLocation();
  198.   }

  199.  
  200.   public String getSha256() {
  201.     lockAnalyzed();
  202.     return sha256;
  203.   }

  204.   public void setSha256(String sha256) {
  205.     failIfLockedAnalyzed();
  206.     lockAnalyzed();
  207.     this.sha256 = sha256;
  208.   }

  209.   public boolean isLockedSourceRead() {
  210.     return lockedSourceRead;
  211.   }
  212.  
  213.   public boolean isLockedDefintionsMerged() {
  214.     return lockedDefintionsMerged;
  215.   }

  216.   public boolean isLockedAnalyzed() {
  217.     return lockedAnalyzed;
  218.   }

  219.   private void lockSourceRead() {
  220.     lockedSourceRead = true;
  221.   }

  222.   private void lockDefintionsMerged() {
  223.     lockSourceRead();
  224.     lockedDefintionsMerged = true;
  225.   }

  226.   /**
  227.    * Public so that once all shas are write to {@link DefinitionModel#addDependencyNameToSha256} this
  228.    * can be called, locking down the definition.
  229.    */
  230.   private void lockAnalyzed() {
  231.     lockSourceRead();
  232.     lockDefintionsMerged();
  233.     lockedAnalyzed = true;
  234.   }

  235.  
  236.   public Map<String, String> getDependencyNameToSha256() {
  237.     lockDefintionsMerged();
  238.     return Collections.unmodifiableMap(dependencyNameToSha256);
  239.   }

  240.   public void addDependencyNameToSha256(String dependencyName, String sha256) {
  241.     failIfLockedAnalyzed();
  242.     dependencyNameToSha256.put(dependencyName, sha256);
  243.   }

  244.   public void addAllDependencyNameToSha256(Map<String, String>  dependencyNameToSha256) {
  245.     failIfLockedAnalyzed();
  246.     dependencyNameToSha256.putAll(dependencyNameToSha256);
  247.   }

  248.   public String getSourceLocation() {
  249.     return sourceLocation;
  250.   }

  251.   public void setSourceLocation(String sourceLocation) {
  252.     failIfLockRead();
  253.     this.sourceLocation = sourceLocation;
  254.   }

  255.   public String getSourcePackage() {
  256.     String packageName = "";
  257.     if (getIdentity().lastIndexOf(".") != -1) {
  258.       packageName = getIdentity().substring(0, getIdentity().lastIndexOf("."));
  259.     }
  260.     return packageName;
  261.   }

  262.   public String getSourceClass() {
  263.     return getIdentity().substring(getIdentity().lastIndexOf(".") + 1);
  264.   }
  265. }