All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.spdx.rdfparser.SPDXDocument Maven / Gradle / Ivy

/**
 * Copyright (c) 2010, 2011 Source Auditor Inc.
 *
 *   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 org.spdx.rdfparser;

import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;

import org.spdx.rdfparser.license.AnyLicenseInfo;
import org.spdx.rdfparser.license.ExtractedLicenseInfo;
import org.spdx.rdfparser.license.LicenseInfoFactory;
import org.spdx.rdfparser.license.SpdxListedLicense;
import org.spdx.rdfparser.model.IRdfModel;
import org.spdx.spdxspreadsheet.InvalidLicenseStringException;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.NodeFactory;
import org.apache.jena.graph.Triple;
import org.apache.jena.rdf.model.AnonId;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.Property;
import org.apache.jena.rdf.model.RDFNode;
import org.apache.jena.rdf.model.Resource;
import org.apache.jena.util.iterator.ExtendedIterator;


/**
 * 
 * Simple model for the SPDX Analysis document.  The document is stored in a Jena RDF
 * model which can be accessed through the model property.
 * 
 * The class should be constructed using the SPDXDocumentFactory class
 * 
 * The createSpdxDocument(uri) must be called first for a blank model
 * 
 * The license, file, and package objects can be constructed then added to the model
 * by using the set functions.
 * 
 * The non-standard licenses must contain a unique ID of the form LicenseRef-NN where NN is a
 * unique number.  The method addNonStandardLicense(licenseText) can be called to 
 * create a new unique Non-Standard License.
 * 
 * This class is provided for compatibility with version 1.2 of the libraries - it has been
 * replaced with SpdxDocumentContainer in version 2.0 and above.
 * 
 * @author Gary O'Neall
 *
 */
@Deprecated
public class SPDXDocument implements SpdxRdfConstants, IModelContainer {
	
	public static final String POINT_EIGHT_SPDX_VERSION = "SPDX-0.8";
	public static final String POINT_NINE_SPDX_VERSION = "SPDX-0.9";
	public static final String ONE_DOT_ZERO_SPDX_VERSION = "SPDX-1.0";
	public static final String ONE_DOT_ONE_SPDX_VERSION = "SPDX-1.1";
	public static final String ONE_DOT_TWO_SPDX_VERSION = "SPDX-1.2";
	public static final String TWO_DOT_ZERO_DOT_ZERO_VERSION = "2.0.0";
	
	public static final String CURRENT_SPDX_VERSION = "SPDX-2.0";
	
	public static final String CURRENT_IMPLEMENTATION_VERSION = "2.0.2";
	
	static Set SUPPORTED_SPDX_VERSIONS = Sets.newHashSet();
	
	static {
		SUPPORTED_SPDX_VERSIONS.add(CURRENT_SPDX_VERSION);
		SUPPORTED_SPDX_VERSIONS.add(POINT_EIGHT_SPDX_VERSION);
		SUPPORTED_SPDX_VERSIONS.add(POINT_NINE_SPDX_VERSION);
		SUPPORTED_SPDX_VERSIONS.add(ONE_DOT_ZERO_SPDX_VERSION);
		SUPPORTED_SPDX_VERSIONS.add(ONE_DOT_ONE_SPDX_VERSION);
		SUPPORTED_SPDX_VERSIONS.add(ONE_DOT_TWO_SPDX_VERSION);
		SUPPORTED_SPDX_VERSIONS.add(TWO_DOT_ZERO_DOT_ZERO_VERSION);
	}

	/**
	 * Keeps tract of the next license reference number when generating the license ID's for
	 * non-standard licenses
	 */
	private AtomicInteger nextLicenseRef = new AtomicInteger(1);
	
	/**
	 * Simple class representing an SPDX Package.  This is stored in an RDF
	 * model.
	 * 
	 * This package is initialized using an existing SPDXPackage in an 
	 * RDF document by constructing the package with the node representing the
	 * SPDX package. 
	 * 
	 * This class is provided for compatibility with version 1.2 of the library.  
	 * This class is replaced by model.SpdxPackage in version 2.0 and above.
	 * 
	 * @author Gary O'Neall
	 *
	 */
	@Deprecated
	public class SPDXPackage {
		private SPDXDocument enclosingSpdxDocument;
		private Node node = null;
		/**
		 * Construct a new SPDX package and populate the properties from the node
		 * @param pkgNode Node in the RDF graph representing the SPDX package
		 */
		public SPDXPackage(Node pkgNode, SPDXDocument enclosingSpdxDocument) {
			this.node = pkgNode;
			this.enclosingSpdxDocument = enclosingSpdxDocument;
		}
		/**
		 * @return the declaredName
		 * @throws InvalidSPDXAnalysisException 
		 */
		public String getDeclaredName() throws InvalidSPDXAnalysisException {
			String[] declaredNames = findDocPropertieStringValues(this.node, PROP_PACKAGE_DECLARED_NAME);
			if (declaredNames == null || declaredNames.length == 0) {
				return null;
			}
			if (declaredNames.length > 1) {
				throw(new InvalidSPDXAnalysisException("More than one declared name for a package"));
			}
			return(declaredNames[0]);
		}

		/**
		 * @param declaredName the declaredName to set
		 * @throws InvalidSPDXAnalysisException 
		 */
		public void setDeclaredName(String declaredName) throws InvalidSPDXAnalysisException {
			removeProperties(node, PROP_PACKAGE_DECLARED_NAME);
			if (declaredName != null) {
				addProperty(node, PROP_PACKAGE_DECLARED_NAME, new String[] {declaredName});
			}
		}
		/**
		 * @return the fileName
		 * @throws InvalidSPDXAnalysisException 
		 */
		public String getFileName() throws InvalidSPDXAnalysisException {
			String[] fileNames = findDocPropertieStringValues(this.node, PROP_PACKAGE_FILE_NAME);
			if (fileNames == null || fileNames.length == 0) {
				return null;
			}
			if (fileNames.length > 1) {
				throw(new InvalidSPDXAnalysisException("More than one machine name for a package"));
			}
			return fileNames[0];
		}
		/**
		 * @param fileName the fileName to set
		 * @throws InvalidSPDXAnalysisException 
		 */
		public void setFileName(String fileName) throws InvalidSPDXAnalysisException {
			removeProperties(node, PROP_PACKAGE_FILE_NAME);
			if (fileName != null) {
				addProperty(node, PROP_PACKAGE_FILE_NAME, new String[] {fileName});
			}
		}
		/**
		 * @return the sha1
		 * @throws InvalidSPDXAnalysisException 
		 */
		public String getSha1() throws InvalidSPDXAnalysisException {
			
			String retval = null;
			Node p = model.getProperty(SPDX_NAMESPACE, PROP_PACKAGE_CHECKSUM).asNode();
			Triple m = Triple.createMatch(this.node, p, null);
			ExtendedIterator tripleIter = model.getGraph().find(m);	
			while (tripleIter.hasNext()) {
				Triple t = tripleIter.next();
				SPDXChecksum cksum = new SPDXChecksum(model, t.getObject());
				if (cksum.getAlgorithm().equals(SpdxRdfConstants.ALGORITHM_SHA1)) {
					retval = cksum.getValue();
				}
			}
			return retval;
		}
		/**
		 * @param sha1 the sha1 to set
		 * @throws InvalidSPDXAnalysisException 
		 */
		public void setSha1(String sha1) throws InvalidSPDXAnalysisException {
			removeProperties(node, PROP_PACKAGE_CHECKSUM);
			if (sha1 != null) {
				SPDXChecksum cksum = new SPDXChecksum(SpdxRdfConstants.ALGORITHM_SHA1, sha1);
				Resource cksumResource = cksum.createResource(model);
				Resource s = getResource(this.node);
				Property p = model.createProperty(SPDX_NAMESPACE, PROP_PACKAGE_CHECKSUM);
				s.addProperty(p, cksumResource);
			}
		}
		/**
		 * @return the sourceInfo
		 * @throws InvalidSPDXAnalysisException 
		 */
		public String getSourceInfo() throws InvalidSPDXAnalysisException {
			String[] sourceInfos = findDocPropertieStringValues(this.node, PROP_PACKAGE_SOURCE_INFO);
			if (sourceInfos == null || sourceInfos.length == 0) {
				return null;
			}
			if (sourceInfos.length > 1) {
				throw(new InvalidSPDXAnalysisException("More than one source info for an SPDX package"));
			}
			return sourceInfos[0];
		}
		/**
		 * @param sourceInfo the sourceInfo to set
		 * @throws InvalidSPDXAnalysisException 
		 */
		public void setSourceInfo(String sourceInfo) throws InvalidSPDXAnalysisException {
			removeProperties(node, PROP_PACKAGE_SOURCE_INFO);
			if (sourceInfo != null) {
				addProperty(node, PROP_PACKAGE_SOURCE_INFO, new String[] {sourceInfo});
			}
		}
		
		/**
		 * @return Version information of the package
		 * @throws InvalidSPDXAnalysisException
		 */
		public String getVersionInfo() throws InvalidSPDXAnalysisException {
			String[] versionInfos = findDocPropertieStringValues(this.node, PROP_PACKAGE_VERSION_INFO);
			if (versionInfos == null || versionInfos.length == 0) {
				return null;
			}
			if (versionInfos.length > 1) {
				throw(new InvalidSPDXAnalysisException("More than one version info for an SPDX package"));
			}
			return versionInfos[0];
		}
		
		/**
		 * Set the version information of the package
		 * @param versionInfo
		 * @throws InvalidSPDXAnalysisException
		 */
		public void setVersionInfo(String versionInfo) throws InvalidSPDXAnalysisException {
			removeProperties(node, PROP_PACKAGE_VERSION_INFO);
			if (versionInfo != null) {
				addProperty(node, PROP_PACKAGE_VERSION_INFO, new String[] {versionInfo});
			}
		}
		
		/**
		 * @return the declaredLicenses
		 * @throws InvalidSPDXAnalysisException 
		 */
		public AnyLicenseInfo getDeclaredLicense() throws InvalidSPDXAnalysisException {
			List alLic = Lists.newArrayList();
			Node p = model.getProperty(SPDX_NAMESPACE, PROP_PACKAGE_DECLARED_LICENSE).asNode();
			Triple m = Triple.createMatch(this.node, p, null);
			ExtendedIterator tripleIter = model.getGraph().find(m);	
			while (tripleIter.hasNext()) {
				Triple t = tripleIter.next();
				alLic.add(LicenseInfoFactory.getLicenseInfoFromModel(enclosingSpdxDocument, t.getObject()));
			}
			if (alLic.size() > 1) {
				throw(new InvalidSPDXAnalysisException("Too many declared licenses"));
			}
			if (alLic.size() == 0) {
				return null;
			}
			return alLic.get(0);
		}
		/**
		 * @param declaredLicenses the declaredLicenses to set
		 * @throws InvalidSPDXAnalysisException 
		 */
		public void setDeclaredLicense(AnyLicenseInfo declaredLicense) throws InvalidSPDXAnalysisException {
			removeProperties(node, PROP_PACKAGE_DECLARED_LICENSE);
			if (declaredLicense != null) {
				Resource s = getResource(this.node);
				Property p = model.createProperty(SPDX_NAMESPACE, PROP_PACKAGE_DECLARED_LICENSE);

				Resource lic = declaredLicense.createResource(this.enclosingSpdxDocument);
				s.addProperty(p, lic);
			}
		}
		
		
		/**
		 * @return the detectedLicenses
		 * @throws InvalidSPDXAnalysisException 
		 */
		public AnyLicenseInfo getConcludedLicenses() throws InvalidSPDXAnalysisException {
			List alLic = Lists.newArrayList();
			Node p = model.getProperty(SPDX_NAMESPACE, PROP_PACKAGE_CONCLUDED_LICENSE).asNode();
			Triple m = Triple.createMatch(this.node, p, null);
			ExtendedIterator tripleIter = model.getGraph().find(m);	
			while (tripleIter.hasNext()) {
				Triple t = tripleIter.next();
				alLic.add(LicenseInfoFactory.getLicenseInfoFromModel(enclosingSpdxDocument, t.getObject()));
			}
			if (alLic.size() > 1) {
				throw(new InvalidSPDXAnalysisException("Too many concluded licenses"));
			}
			if (alLic.size() == 0) {
				return null;
			}
			return alLic.get(0);
		}
		/**
		 * @param detectedLicenses the detectedLicenses to set
		 * @throws InvalidSPDXAnalysisException 
		 */
		public void setConcludedLicenses(AnyLicenseInfo detectedLicenses) throws InvalidSPDXAnalysisException {
			removeProperties(node, PROP_PACKAGE_CONCLUDED_LICENSE);
			if (detectedLicenses != null) {
				Resource s = getResource(this.node);
				Property p = model.createProperty(SPDX_NAMESPACE, PROP_PACKAGE_CONCLUDED_LICENSE);
				Resource lic = detectedLicenses.createResource(this.enclosingSpdxDocument);
				s.addProperty(p, lic);
			}
		}
		/**
		 * @return the licenseComment
		 * @throws InvalidSPDXAnalysisException 
		 */
		public String getLicenseComment() throws InvalidSPDXAnalysisException {
			String[] comments = findDocPropertieStringValues(this.node, PROP_PACKAGE_LICENSE_COMMENT);
			if (comments == null || comments.length == 0) {
				return null;
			}
			if (comments.length > 1) {
				throw(new InvalidSPDXAnalysisException("More than one license comment for a package"));
			}
			return(comments[0]);
		}
		/**
		 * @param comments the license comments to set
		 * @throws InvalidSPDXAnalysisException 
		 */
		public void setLicenseComment(String comments) throws InvalidSPDXAnalysisException {
			removeProperties(node, PROP_PACKAGE_LICENSE_COMMENT);
			if (comments != null) {
				addProperty(node, PROP_PACKAGE_LICENSE_COMMENT, new String[] {comments});
			}
		}
		/**
		 * @return the declaredCopyright
		 * @throws InvalidSPDXAnalysisException 
		 */
		public String getDeclaredCopyright() throws InvalidSPDXAnalysisException {
			String[] copyrights = findDocPropertieStringValues(this.node, PROP_PACKAGE_DECLARED_COPYRIGHT);
			if (copyrights == null || copyrights.length == 0) {
				return null;
			}
			if (copyrights.length > 1) {
				throw(new InvalidSPDXAnalysisException("More than one declared copyright for a package"));
			}
			return(copyrights[0]);
		}
		/**
		 * @param declaredCopyright the declaredCopyright to set
		 * @throws InvalidSPDXAnalysisException 
		 */
		public void setDeclaredCopyright(String declaredCopyright) throws InvalidSPDXAnalysisException {
			removeProperties(node, PROP_PACKAGE_DECLARED_COPYRIGHT);
			if (declaredCopyright != null) {
				addProperty(node, PROP_PACKAGE_DECLARED_COPYRIGHT, new String[] {declaredCopyright});
			}
		}
		/**
		 * @return the shortDescription
		 * @throws InvalidSPDXAnalysisException 
		 */
		public String getShortDescription() throws InvalidSPDXAnalysisException {
			String[] shortDescs = findDocPropertieStringValues(this.node, PROP_PACKAGE_SHORT_DESC);
			if (shortDescs == null || shortDescs.length == 0) {
				return null;
			}
			if (shortDescs.length > 1) {
				throw(new InvalidSPDXAnalysisException("More than one short description for a package"));
			}
			return(shortDescs[0]);
		}
		/**
		 * @param shortDescription the shortDescription to set
		 * @throws InvalidSPDXAnalysisException 
		 */
		public void setShortDescription(String shortDescription) throws InvalidSPDXAnalysisException {
			removeProperties(node, PROP_PACKAGE_SHORT_DESC);
			if (shortDescription != null) {
				addProperty(node, PROP_PACKAGE_SHORT_DESC, new String[] {shortDescription});
			}
		}
		/**
		 * @return the description
		 * @throws InvalidSPDXAnalysisException 
		 */
		public String getDescription() throws InvalidSPDXAnalysisException {
			String[] desc = findDocPropertieStringValues(this.node, PROP_PACKAGE_DESCRIPTION);
			if (desc == null || desc.length == 0) {
				return null;
			}
			if (desc.length > 1) {
				throw(new InvalidSPDXAnalysisException("More than one description for a package"));
			}
			return(desc[0]);
		}
		/**
		 * @param description the description to set
		 * @throws InvalidSPDXAnalysisException 
		 */
		public void setDescription(String description) throws InvalidSPDXAnalysisException {
			removeProperties(node, PROP_PACKAGE_DESCRIPTION);
			if (description != null) {
				addProperty(node, PROP_PACKAGE_DESCRIPTION, new String[] {description});
			}
		}
		
		/**
		 * Set the originator
		 * @param originator Either a valid originator string or NOASSERTION
		 * @throws InvalidSPDXAnalysisException
		 */
		public void setOriginator(String originator) throws InvalidSPDXAnalysisException {
			if (originator == null) {
				removeProperties(node, PROP_PACKAGE_ORIGINATOR);
				return;
			}
			String error = SpdxVerificationHelper.verifyOriginator(originator);
			if (error != null && !error.isEmpty()) {
				throw(new InvalidSPDXAnalysisException(error));
			}
			removeProperties(node, PROP_PACKAGE_ORIGINATOR);
			addProperty(node, PROP_PACKAGE_ORIGINATOR, new String[] {originator});
		}
		
		/**
		 * Set the Supplier
		 * @param supplier Either a valid originator string or NOASSERTION
		 * @throws InvalidSPDXAnalysisException
		 */
		public void setSupplier(String supplier) throws InvalidSPDXAnalysisException {
			if (supplier == null) {
				removeProperties(node, PROP_PACKAGE_SUPPLIER);
				return;
			}
			String error = SpdxVerificationHelper.verifySupplier(supplier);
			if (error != null && !error.isEmpty()) {
				throw(new InvalidSPDXAnalysisException(error));
			}
			removeProperties(node, PROP_PACKAGE_SUPPLIER);
			addProperty(node, PROP_PACKAGE_SUPPLIER, new String[] {supplier});
		}
		
		public String getOriginator() throws InvalidSPDXAnalysisException {
			String[] originators = findDocPropertieStringValues(this.node, PROP_PACKAGE_ORIGINATOR);
			if (originators == null || originators.length == 0) {
				return null;
			}
			if (originators.length > 1) {
				throw(new InvalidSPDXAnalysisException("More than one originator for a package"));
			}
			return(originators[0]);
		}
		
		public String getSupplier() throws InvalidSPDXAnalysisException {
			String[] suppliers = findDocPropertieStringValues(this.node, PROP_PACKAGE_SUPPLIER);
			if (suppliers == null || suppliers.length == 0) {
				return null;
			}
			if (suppliers.length > 1) {
				throw(new InvalidSPDXAnalysisException("More than one supplier for a package"));
			}
			return(suppliers[0]);
		}
		
		/**
		 * @return the files
		 * @throws InvalidSPDXAnalysisException 
		 */
		public SPDXFile[] getFiles() throws InvalidSPDXAnalysisException {
			// files
			List alFiles = Lists.newArrayList();
			Node p = model.getProperty(SPDX_NAMESPACE, PROP_PACKAGE_FILE).asNode();
			Triple m = Triple.createMatch(this.node, p, null);
			ExtendedIterator tripleIter = model.getGraph().find(m);	
			while (tripleIter.hasNext()) {
				Triple t = tripleIter.next();
				alFiles.add(new SPDXFile(enclosingSpdxDocument, t.getObject()));
			}
			SPDXFile[] retval = new SPDXFile[alFiles.size()];
			return alFiles.toArray(retval);
		}
		/**
		 * @param files the files to set
		 * @throws InvalidSPDXAnalysisException 
		 */
		public void setFiles(SPDXFile[] files) throws InvalidSPDXAnalysisException {
			// Delete all existing files
			List alFileNodes = Lists.newArrayList();
			Node n = model.getProperty(SPDX_NAMESPACE, PROP_PACKAGE_FILE).asNode();
			Triple m = Triple.createMatch(this.node, n, null);
			ExtendedIterator tripleIter = model.getGraph().find(m);	
			while (tripleIter.hasNext()) {
				Triple t = tripleIter.next();
				alFileNodes.add(t.getObject());
			}
			removeProperties(node, PROP_PACKAGE_FILE);
			removeProperties(getSpdxDocNode(), PROP_SPDX_FILE_REFERENCE);	// NOTE: In version 2.0, we will need to remove just the files which were in the package

			for (Node fileNode : alFileNodes) {
				model.removeAll(getResource(fileNode), null, null);
			}
			
			if (files != null) {
				Resource s = getResource(this.node);
				Property p = model.createProperty(SPDX_NAMESPACE, PROP_PACKAGE_FILE);
				Resource docResource = getResource(getSpdxDocNode());
				Property docP = model.createProperty(SPDX_NAMESPACE, PROP_SPDX_FILE_REFERENCE);
				for (int i = 0; i < files.length; i++) {				
					Resource file = files[i].createResource(getDocument(), getDocumentNamespace() + getNextSpdxElementRef());
					s.addProperty(p, file);
					docResource.addProperty(docP, file);
				}
			}
		}
		/**
		 * Add a file to the package
		 * @param file
		 */
		public void addFile(SPDXFile file) throws InvalidSPDXAnalysisException {
			Resource s = getResource(this.node);
			Property p = model.createProperty(SPDX_NAMESPACE, PROP_PACKAGE_FILE);
			Resource docResource = getResource(getSpdxDocNode());
			Property docP = model.createProperty(SPDX_NAMESPACE, PROP_SPDX_FILE_REFERENCE);			
			Resource fileResource = file.createResource(getDocument(), getDocumentNamespace() + getNextSpdxElementRef());
			s.addProperty(p, fileResource);
			docResource.addProperty(docP, fileResource);
		}
		
		/**
		 * Removes all SPDX files by the given name
		 * @param fileName Name of SPDX file to be removed
		 * @throws InvalidSPDXAnalysisException 
		 */
		public void removeFile(String fileName) throws InvalidSPDXAnalysisException {
			List filesToRemove = Lists.newArrayList();
			Node fileNameProperty = model.getProperty(SPDX_NAMESPACE, PROP_FILE_NAME).asNode();
			Property docFileProperty = model.getProperty(SPDX_NAMESPACE, PROP_SPDX_FILE_REFERENCE);
			Property pkgFileProperty = model.createProperty(SPDX_NAMESPACE, PROP_PACKAGE_FILE);
			Resource docResource = getResource(getSpdxDocNode());
			Resource pkgResource = getResource(this.node);
			Triple m = Triple.createMatch(getSpdxDocNode(), docFileProperty.asNode(), null);
			ExtendedIterator tripleIter = model.getGraph().find(m);	
			//TODO: See if there is a more efficient search method for files
			while (tripleIter.hasNext()) {
				Triple t = tripleIter.next();
				Node fileObject = t.getObject();
				Triple fileNameMatch = Triple.createMatch(fileObject, fileNameProperty, null);
				ExtendedIterator fileNameIterator = model.getGraph().find(fileNameMatch);
				while (fileNameIterator.hasNext()) {
					Triple fileNameTriple = fileNameIterator.next();
					String searchFileName = fileNameTriple.getObject().toString(false); 
					if (searchFileName.equals(fileName)) {
						filesToRemove.add(fileObject);
					}
				}
			}
			for (int i = 0; i < filesToRemove.size(); i++) {
				// remove the references files
				RDFNode o = model.getRDFNode(filesToRemove.get(i));
				model.removeAll(docResource, docFileProperty, o);
				// remove the package files
				model.removeAll(pkgResource, pkgFileProperty, o);				
			}
		}
		public String getDownloadUrl() throws InvalidSPDXAnalysisException {
			String[] urls = findDocPropertieStringValues(this.node, PROP_PACKAGE_DOWNLOAD_URL);
			if (urls == null || urls.length == 0) {
				return null;
			}
			if (urls.length > 1) {
				throw(new InvalidSPDXAnalysisException("More than one URL for a package"));
			}
			return(urls[0]);
		}
		
		public void setDownloadUrl(String url) throws InvalidSPDXAnalysisException {
			removeProperties(node, PROP_PACKAGE_DOWNLOAD_URL);
			if (url != null) {
				addProperty(node, PROP_PACKAGE_DOWNLOAD_URL, new String[] {url});
			}
		}
		
		public String getHomePage() throws InvalidSPDXAnalysisException {
			String[] urls = findDocPropertieStringValues(this.node, DOAP_NAMESPACE, PROP_PROJECT_HOMEPAGE);
			if (urls == null || urls.length == 0) {
				return null;
			}
			if (urls.length > 1) {
				throw(new InvalidSPDXAnalysisException("More than one home page for a package"));
			}
			return(urls[0]);
		}
		
		public void setHomePage(String url) throws InvalidSPDXAnalysisException {
			removeProperties(node, DOAP_NAMESPACE, PROP_PROJECT_HOMEPAGE);
			if (url != null) {
				addProperty(node, DOAP_NAMESPACE, PROP_PROJECT_HOMEPAGE, new String[] {url});
			}
		}
		
		public SpdxPackageVerificationCode getVerificationCode() throws InvalidSPDXAnalysisException {			
			SpdxPackageVerificationCode retval = null;
			Node p = model.getProperty(SPDX_NAMESPACE, PROP_PACKAGE_VERIFICATION_CODE).asNode();
			Triple m = Triple.createMatch(this.node, p, null);
			ExtendedIterator tripleIter = model.getGraph().find(m);	
			while (tripleIter.hasNext()) {
				Triple t = tripleIter.next();
				retval = new SpdxPackageVerificationCode(model, t.getObject());
			}
			return retval;
		}
		
		public void setVerificationCode(SpdxPackageVerificationCode verificationCode) throws InvalidSPDXAnalysisException {
			removeProperties(node, PROP_PACKAGE_VERIFICATION_CODE);
			if (verificationCode != null) {
				Resource verificationCodeResource = verificationCode.createResource(model);
				Resource s = getResource(this.node);
				Property p = model.createProperty(SPDX_NAMESPACE, PROP_PACKAGE_VERIFICATION_CODE);
				s.addProperty(p, verificationCodeResource);
			}
		}
		public SPDXPackageInfo getPackageInfo() throws InvalidSPDXAnalysisException {
			return new SPDXPackageInfo(this.getDeclaredName(), this.getVersionInfo(), this.getFileName(), 
					this.getSha1(), this.getSourceInfo(), this.getDeclaredLicense(), 
					this.getConcludedLicenses(), this.getLicenseInfoFromFiles(), 
					this.getLicenseComment(), this.getDeclaredCopyright(), 
					this.getShortDescription(), this.getDescription(), this.getDownloadUrl(), 
					this.getVerificationCode(), this.getSupplier(), this.getOriginator(), 
					this.getHomePage());
		}
		
		public void setLicenseInfoFromFiles(AnyLicenseInfo[] licenseInfo) throws InvalidSPDXAnalysisException {
			removeProperties(node, PROP_PACKAGE_LICENSE_INFO_FROM_FILES);
			if (licenseInfo != null) {
				Resource s = getResource(this.node);
				Property p = model.createProperty(SPDX_NAMESPACE, PROP_PACKAGE_LICENSE_INFO_FROM_FILES);
				for (int i = 0; i < licenseInfo.length; i++) {
					Resource lic = licenseInfo[i].createResource(this.enclosingSpdxDocument);
					s.addProperty(p, lic);
				}
			}
		}
		
		public AnyLicenseInfo[] getLicenseInfoFromFiles() throws InvalidSPDXAnalysisException {
			List alLic = Lists.newArrayList();
			Node p = model.getProperty(SPDX_NAMESPACE, PROP_PACKAGE_LICENSE_INFO_FROM_FILES).asNode();
			Triple m = Triple.createMatch(this.node, p, null);
			ExtendedIterator tripleIter = model.getGraph().find(m);	
			while (tripleIter.hasNext()) {
				Triple t = tripleIter.next();
				alLic.add(LicenseInfoFactory.getLicenseInfoFromModel(enclosingSpdxDocument, t.getObject()));
			}
			AnyLicenseInfo[] retval = new AnyLicenseInfo[alLic.size()];
			retval = alLic.toArray(retval);
			return retval;
		}
		
		/**
		 * Clones a deep copy of all fields to a new SPDXPackage contained in the docToCloneTo SPDXDocument. 
		 * NOTE: This will overwrite any existing SPDXPackages contained within the SPDXDocument and the SPDXDocument must not contain any extracted licenses
		 * @param docToCloneTo SPDX Document to contain the result of the clone
		 * @param packageUri URI for the SPDX Package being created
		 * @return A deep copy of this SPDXPackage contained within docToCloneTo
		 * @throws InvalidSPDXAnalysisException
		 */
		public SPDXPackage clone(SPDXDocument docToCloneTo, String packageUri) throws InvalidSPDXAnalysisException {
			if (docToCloneTo.getExtractedLicenseInfos() != null && docToCloneTo.getExtractedLicenseInfos().length > 0) {
				throw(new InvalidSPDXAnalysisException("Can not clone a package to an SPDX document with existing licenses"));
			}
			if (docToCloneTo.getFileReferences()!= null && docToCloneTo.getFileReferences().length > 0) {
				throw(new InvalidSPDXAnalysisException("Can not clone a package to an SPDX document with existing files"));
			}
			//TODO: Allow cloning of existing licenses and files by merging the extracted license infos and mapping the licenses
			SPDXPackage retval = docToCloneTo.createSpdxPackage(packageUri);
			// need to copy the non-standard licenses in case they are referenced
			ExtractedLicenseInfo[] extractedLicenseInfos = getExtractedLicenseInfos();
			if (extractedLicenseInfos != null) {
				docToCloneTo.setExtractedLicenseInfos(extractedLicenseInfos);
				docToCloneTo.initializeNextLicenseRef(extractedLicenseInfos);
			}
			retval.setConcludedLicenses(this.getConcludedLicenses().clone());
			retval.setDeclaredCopyright(this.getDeclaredCopyright());
			retval.setDeclaredLicense(this.getDeclaredLicense().clone());
			retval.setDeclaredName(this.getDeclaredName());
			retval.setDescription(this.getDescription());
			retval.setDownloadUrl(this.getDownloadUrl());
			retval.setFileName(this.getFileName());
			SPDXFile[] myFiles = this.getFiles();
			if (myFiles != null) {
				SPDXFile[] clonedFiles = new SPDXFile[myFiles.length];
				for (int i = 0; i < clonedFiles.length; i++) {
					// For the refactored code, replace the following by a call to clone, call to setId, then a call to createResource
					clonedFiles[i] = myFiles[i].clone(docToCloneTo, docToCloneTo.getDocumentNamespace() + docToCloneTo.getNextSpdxElementRef());
				}
				retval.setFiles(clonedFiles);				
			}
			retval.setHomePage(this.getHomePage());
			retval.setLicenseComment(this.getLicenseComment());
			AnyLicenseInfo[] licenseInfosFromFiles = this.getLicenseInfoFromFiles();
			if (licenseInfosFromFiles != null) {
				AnyLicenseInfo[] clonedLicenseInfosFromFiles = new AnyLicenseInfo[licenseInfosFromFiles.length];
				for (int i = 0; i < clonedLicenseInfosFromFiles.length; i++) {
					clonedLicenseInfosFromFiles[i] = licenseInfosFromFiles[i].clone();
				}
				retval.setLicenseInfoFromFiles(clonedLicenseInfosFromFiles);
			}
			retval.setOriginator(this.getOriginator());
			retval.setSha1(this.getSha1());
			retval.setShortDescription(this.getShortDescription());
			retval.setSourceInfo(this.getSourceInfo());
			retval.setSupplier(this.getSupplier());
			retval.setVerificationCode(this.getVerificationCode());
			retval.setVersionInfo(this.getVersionInfo());
			// need to reset the next reference numbers in the toDocument
			return retval;
		}
		
		/**
		 * @return Array list of any error messages found in verifying the package model
		 */
		public List verify() {
			List retval = Lists.newArrayList();
			// name
			try {
				String name = this.getDeclaredName();
				if (name == null || name.isEmpty()) {
					retval.add("Missing required name for package");
				}
			} catch (InvalidSPDXAnalysisException e) {
				retval.add("Invalid name: "+e.getMessage());
			}
			// summary
			try {
				@SuppressWarnings("unused")
				String summary = this.getShortDescription();
			} catch (InvalidSPDXAnalysisException e) {
				retval.add("Invalid summary: "+e.getMessage());
			}
			// description
			try {
				@SuppressWarnings("unused")
				String description = this.getDescription();
			} catch (InvalidSPDXAnalysisException e) {
				retval.add("Invalid description: "+e.getMessage());
			}
			// download location
			try {
				String downloadLocation = this.getDownloadUrl();
				if (downloadLocation == null || downloadLocation.isEmpty()) {
					retval.add("Missing required download location for package");
				}
			} catch (InvalidSPDXAnalysisException e) {
				retval.add("Invalid download location: "+e.getMessage());
			}
			// checksum
			try {
				String checksum = this.getSha1();
				if (checksum != null && !checksum.isEmpty()) {
					String verify = SpdxVerificationHelper.verifyChecksumString(checksum);
					if (verify != null) {
						retval.add("Package checksum error: "+verify);
					}
				}
			} catch (InvalidSPDXAnalysisException e) {
				retval.add("Invalid checksum: "+e.getMessage());
			}
			// source Info - optional
			try {
				@SuppressWarnings("unused")
				String sourceInfo = this.getSourceInfo();
			} catch (InvalidSPDXAnalysisException e) {
				retval.add("Invalid package source info: "+e.getMessage());
			}
			
			// copyright text - mandatory
			try {
				String copyrightText = this.getDeclaredCopyright();
				if (copyrightText == null || copyrightText.isEmpty()) {
					retval.add("Missing required package copyright text");
				}
			} catch (InvalidSPDXAnalysisException e) {
				retval.add("Invalid package copyright: "+e.getMessage());
			}
			
			// license comments - optional
			try {
				@SuppressWarnings("unused")
				String licenseComments = this.getLicenseComment();
			} catch (InvalidSPDXAnalysisException e) {
				retval.add("Invalid license comments: "+e.getMessage());
			}
			
			// license declared - mandatory - 1 (need to change return values)
			try {
				AnyLicenseInfo declaredLicense = this.getDeclaredLicense();
				if (declaredLicense == null) {
					retval.add("Missing required declared license");
				} else {
					retval.addAll(declaredLicense.verify());
				}				
			} catch (InvalidSPDXAnalysisException e) {
				retval.add("Invalid package declared license: "+e.getMessage());
			}
			
			// license concluded - mandatory - 1 (need to change return values)
			try {
				AnyLicenseInfo concludedLicense = this.getConcludedLicenses();
				if (concludedLicense == null) {
					retval.add("Missing required concluded license");
				} else {
					retval.addAll(concludedLicense.verify());
				}
			} catch (InvalidSPDXAnalysisException e) {
				retval.add("Invalid package concluded license: "+e.getMessage());
			}
			
			// license infos from files - mandatory - 1 or more
			try {
				AnyLicenseInfo[] licenseInfosFromFiles = this.getLicenseInfoFromFiles();
				if (licenseInfosFromFiles == null || licenseInfosFromFiles.length == 0) {
					retval.add("Missing required license information from files");
				} else {
					for (int i = 0; i < licenseInfosFromFiles.length; i++) {
						retval.addAll(licenseInfosFromFiles[i].verify());
					}
				}
			} catch (InvalidSPDXAnalysisException e) {
				retval.add("Invalid package license information from files: "+e.getMessage());
			}
			
			// hasFiles mandatory one or more
			try {
				SPDXFile[] files = this.getFiles();
				if (files == null || files.length == 0) {
					retval.add("Missing required package files");
				} else {
					for (int i = 0; i < files.length; i++) {
						retval.addAll(files[i].verify());
					}
				}
			} catch (InvalidSPDXAnalysisException e) {
				retval.add("Invalid package files: "+e.getMessage());
			}		
			
			// verification code
			SpdxPackageVerificationCode verificationCode = null;
			try {
				verificationCode = this.getVerificationCode();
				if (verificationCode == null) {
					retval.add("Missing required package verification code.");
				} else {
					retval.addAll(verificationCode.verify());
				}
			} catch (InvalidSPDXAnalysisException e) {
				retval.add("Invalid package verification code: "+e.getMessage());
			}

			// supplier
			String supplier = null;
			try {
				supplier = this.getSupplier();
				if (supplier != null) {
					String error = SpdxVerificationHelper.verifySupplier(supplier);
					if (error != null && !error.isEmpty()) {
						retval.add("Supplier error - "+error);
					}
				}
			} catch (InvalidSPDXAnalysisException e) {
				retval.add("Invalid supplier: "+e.getMessage());
			}
			
			// originator
			String originator = null;
			try {
				originator = this.getOriginator();
				if (originator != null) {
					String error = SpdxVerificationHelper.verifyOriginator(originator);
					if (error != null && !error.isEmpty()) {
						retval.add("Originator error - "+error);
					}
				}
			} catch (InvalidSPDXAnalysisException e) {
				retval.add("Invalid originator: "+e.getMessage());
			}
			return retval;
		}
	}
		
	Model model;
	SPDXPackage spdxPackage = null;
	/**
	 * Namespace for all SPDX document elements
	 */
	private String documentNamespace;
	private AtomicInteger nextElementRef = new AtomicInteger(0);
	
	public SPDXDocument(Model model) throws InvalidSPDXAnalysisException {
		this.model = model;
		initialize();

	}

	/**
	 * Initialize the next license ref and next element reference variables
	 * @return any verification errors encountered
	 * @throws InvalidSPDXAnalysisException 
	 */
	private List initialize() throws InvalidSPDXAnalysisException {
		Node spdxDocNode = getSpdxDocNode();
		if (spdxDocNode != null) {	// not empty - we should verify
			if (!spdxDocNode.isURI()) {
				throw(new InvalidSPDXAnalysisException("SPDX Documents must have a unique URI"));
			}
			String docUri = spdxDocNode.getURI();
			this.documentNamespace = this.formDocNamespace(docUri);
			List errors = verify();
			initializeNextLicenseRef();
			initializeNextElementRef();
			return errors;
		} else {
			return Lists.newArrayList();
		}
	}

	/**
	 * Initialize the next SPDX element reference used for creating new SPDX element URIs
	 */
	private void initializeNextElementRef() {
		int highestElementRef = 0;
		Triple m = Triple.createMatch(null, null, null);
		ExtendedIterator tripleIter = model.getGraph().find(m);	// find everything
		while (tripleIter.hasNext()) {
			// iterate through everything looking for matches to this SPDX document URI
			Triple trip = tripleIter.next();
			if (trip.getSubject().isURI()) {	// check the subject
				String subjectUri = trip.getSubject().getURI();
				if (subjectUri.startsWith(this.documentNamespace + SPDX_ELEMENT_REF_PRENUM)) {
					String elementRef = subjectUri.substring(this.documentNamespace.length());
					if (SPDX_ELEMENT_REF_PATTERN.matcher(elementRef).matches()) {
						int elementRefNum = getElementRefNumber(elementRef);
						if (elementRefNum > highestElementRef) {
							highestElementRef = elementRefNum;
						}
					}
				}
			}
			if (trip.getObject().isURI()) {		// check the object
				String objectUri = trip.getObject().getURI();
				if (objectUri.startsWith(this.documentNamespace + SPDX_ELEMENT_REF_PRENUM)) {
					String elementRef = objectUri.substring(this.documentNamespace.length());
					if (SPDX_ELEMENT_REF_PATTERN.matcher(elementRef).matches()) {
						int elementRefNum = getElementRefNumber(elementRef);
						if (elementRefNum > highestElementRef) {
							highestElementRef = elementRefNum;
						}
					}
				}
			}
		}
		
		this.nextElementRef.set(highestElementRef + 1);
	}

	/**
	 * Parses out the reference number for an SPDX element reference
	 * @param elementReference Element reference to parse
	 * @return element reference or -1 if the element reference is not valid
	 */
	public static int getElementRefNumber(String elementReference) {
		String numPart = elementReference.substring(SPDX_ELEMENT_REF_PRENUM.length());
		try {
			return Integer.parseInt(numPart);
		} catch(Exception ex) {
			return -1;
		}
	}

	/**
	 * Initialize the next license reference by scanning all of the existing non-standard licenses
	 * @throws InvalidSPDXAnalysisException 
	 */
	protected void initializeNextLicenseRef() throws InvalidSPDXAnalysisException {
		initializeNextLicenseRef(this.getExtractedLicenseInfos());
	}
	
	protected void initializeNextLicenseRef(ExtractedLicenseInfo[] existingLicenses) throws InvalidSPDXAnalysisException {
		int highestNonStdLicense = 0;
		for (int i = 0; i < existingLicenses.length; i++) {
			try {
			int idNum = getLicenseRefNum(existingLicenses[i].getLicenseId());
			if (idNum > highestNonStdLicense) {
				highestNonStdLicense = idNum;
			}
			} catch (NonNumericLicenseIdException ex) {
				// just continue
			}
		}	
		this.nextLicenseRef.set(highestNonStdLicense + 1);
	}
	
	/**
	 * Parses a license ID and return the integer representing the ID number (e.g. N in LicenseRef-N)
	 * Note that in SPDX 1.2, non-numeric license IDs are allowed. This method will throw a NonNumericException if
	 * a non numeric license ID passed as a licenseID parameter
	 * @param licenseID
	 * @return
	 * @throws NonNumericLicenseIdException If the non-standard license ID is not of the form LicenseRef-NN
	 */
	public int getLicenseRefNum(String licenseID) throws NonNumericLicenseIdException {
		Matcher matcher = LICENSE_ID_PATTERN_NUMERIC.matcher(licenseID);
		if (!matcher.matches()) {
			throw(new NonNumericLicenseIdException("Invalid license ID found in the non-standard licenses: '"+licenseID+"'"));
		}
		int numGroups = matcher.groupCount();
		if (numGroups != 1) {
			throw(new NonNumericLicenseIdException("Invalid license ID found in the non-standard licenses: '"+licenseID+"'"));
		}
		int idNum = Integer.decode(matcher.group(1));
		return idNum;
	}
	
	public static String formNonStandardLicenseID(int idNum) {
		return NON_STD_LICENSE_ID_PRENUM + String.valueOf(idNum);
	}

	public String verifySpdxVersion(String spdxVersion) {
		if (!spdxVersion.startsWith("SPDX-")) {
			return "Invalid spdx version - must start with 'SPDX-'";
		}
		Matcher docSpecVersionMatcher = SpdxRdfConstants.SPDX_VERSION_PATTERN.matcher(spdxVersion);
		if (!docSpecVersionMatcher.matches()) {
			return "Invalid spdx version format - must match 'SPDX-M.N'";
		}
		return null;	// if we got here, there is no problem
	}
	/**
	 * Verifies the spdx document
	 * @return error messages for any fields which do not match the spec.  Return an empty array list if no issues.
	 */
	public List verify() {
		List retval = Lists.newArrayList();
		// specVersion
		String docSpecVersion = "";	// note - this is used later in verify to verify version specific info
		try {
			docSpecVersion = this.getSpdxVersion();
			if (docSpecVersion == null || docSpecVersion.isEmpty()) {
				retval.add("Missing required SPDX version");
			} else {
				String verify = verifySpdxVersion(docSpecVersion);
				if (verify != null) {
					retval.add(verify);
				} else {
					if (!SUPPORTED_SPDX_VERSIONS.contains(docSpecVersion)) {
						retval.add("Version "+docSpecVersion+" is not supported by this version of the rdf parser");
					}
				}				
			}
		} catch (InvalidSPDXAnalysisException e) {
			retval.add("Invalid spec version: "+e.getMessage());
		}
		// creationInfo
		try {
			SPDXCreatorInformation creator = this.getCreatorInfo();
			if (creator == null) {
				retval.add("Missing required Creator");
			} else {
				List creatorVerification = creator.verify();
				retval.addAll(creatorVerification);
			}
		} catch (InvalidSPDXAnalysisException e) {
			retval.add("Invalid creator information: "+e.getMessage());
		}
		// Package
		try {
			SPDXPackage sPkg = this.getSpdxPackage();
			if (sPkg == null) {
				retval.add("Missing required SPDX Package");
			} else {
				List packageVerification = sPkg.verify();
				retval.addAll(packageVerification);
			}
		} catch (InvalidSPDXAnalysisException e) {
			retval.add("Invalid SPDX Package: "+e.getMessage());
		}
		// Reviewers
		try {
			SPDXReview[] reviews = this.getReviewers();
			if (reviews != null) {
				for (int i = 0; i < reviews.length; i++) {
					List reviewerVerification = reviews[i].verify();
					retval.addAll(reviewerVerification);
				}
			}
		} catch (InvalidSPDXAnalysisException e) {
			retval.add("Invalid reviewers: "+e.getMessage());
		}
		// Non standard licenses
		try {
			ExtractedLicenseInfo[] extractedLicInfos = this.getExtractedLicenseInfos();
			if (extractedLicInfos != null) {
				for (int i = 0; i < extractedLicInfos.length; i++) {
					List extractedLicInfoVerification = extractedLicInfos[i].verify();
					retval.addAll(extractedLicInfoVerification);
				}
			}
		} catch (InvalidSPDXAnalysisException e) {
			retval.add("Invalid extracted licensing info: "+e.getMessage());
		}
		// data license
		if (docSpecVersion != null && !docSpecVersion.equals(POINT_EIGHT_SPDX_VERSION) && !docSpecVersion.equals(POINT_NINE_SPDX_VERSION)) { // added as a mandatory field in 1.0
			try {
				SpdxListedLicense dataLicense = this.getDataLicense();
				if (dataLicense == null) {
					retval.add("Missing required data license");
				}else if (docSpecVersion.equals(ONE_DOT_ZERO_SPDX_VERSION)) { 
					if (!dataLicense.getLicenseId().equals(SPDX_DATA_LICENSE_ID_VERSION_1_0)) {
						retval.add("Incorrect data license for SPDX version 1.0 document - found "+dataLicense.getLicenseId()+", expected "+SPDX_DATA_LICENSE_ID_VERSION_1_0);
					}
				} else {
					if (!dataLicense.getLicenseId().equals(SPDX_DATA_LICENSE_ID)) {
						retval.add("Incorrect data license for SPDX document - found "+dataLicense.getLicenseId()+", expected "+SPDX_DATA_LICENSE_ID);
					}					
				}
			} catch (InvalidSPDXAnalysisException e) {
				retval.add("Invalid data license: "+e.getMessage());
			}
		}
		// document comment
		try {
			String[] comments = findDocPropertieStringValues(getSpdxDocNode(), RDFS_NAMESPACE, RDFS_PROP_COMMENT);
			if (comments.length > 1) {
				retval.add("More than one document comment exists for the SPDX Package");
			}
		}
		catch(Exception e) {
			retval.add("Invalid document comment: "+e.getMessage());
		}
		return retval;
	}
	
	/**
	 * Find all property string values belonging to the subject
	 * @param subject
	 * @param propertyName
	 * @return string values of the properties or null if the subject or propertyName is null
	 */	
	private String[] findDocPropertieStringValues(Node subject, String propertyName) {
		return findDocPropertieStringValues(subject, SPDX_NAMESPACE, propertyName);
	}

	/**
	 * Find all property string values belonging to the subject
	 * @param subject
	 * @param nameSpace
	 * @param propertyName
	 * @return string values of the properties or null if the subject or propertyName is null
	 */
	private String[] findDocPropertieStringValues(Node subject, String nameSpace, String propertyName) {
		if (subject == null || propertyName == null) {
			return null;
		}
		List alResult = Lists.newArrayList();
		Node p = model.getProperty(nameSpace, propertyName).asNode();
		Triple m = Triple.createMatch(subject, p, null);
		ExtendedIterator tripleIter = model.getGraph().find(m);	
		while (tripleIter.hasNext()) {
			Triple t = tripleIter.next();
			if (t.getObject().isURI()) {
				if (t.getObject().getURI().equals(SpdxRdfConstants.URI_VALUE_NONE)) {
					alResult.add(SpdxRdfConstants.NONE_VALUE);
				} else if (t.getObject().getURI().equals(SpdxRdfConstants.URI_VALUE_NOASSERTION)) {
					alResult.add(SpdxRdfConstants.NOASSERTION_VALUE);
				} else {
					alResult.add(t.getObject().toString(false));
				}
			} else {
				alResult.add(t.getObject().toString(false));
			}
		}
		String[] retval = new String[alResult.size()];
		return alResult.toArray(retval);
	}
	
	/**
	 * Remove all properties by the property name from the subject node
	 * @param node
	 * @param propertyName
	 * @throws InvalidSPDXAnalysisException 
	 */
	private void removeProperties(Node subject, String propertyName) throws InvalidSPDXAnalysisException {
		removeProperties(subject, SPDX_NAMESPACE, propertyName);
	}
	
	/**
	 * Remove all properties by the property name within the nameSpace from the subject node
	 * @param node
	 * @param propertyName
	 * @throws InvalidSPDXAnalysisException 
	 */
	private void removeProperties(Node subject, String nameSpace, String propertyName) throws InvalidSPDXAnalysisException {
		Property p = model.getProperty(nameSpace, propertyName);
		Resource s = getResource(subject);
		model.removeAll(s, p, null);
	}
	
	private Resource getResource(Node node) throws InvalidSPDXAnalysisException {
		Resource s;
		if (node.isURI()) {
			s = model.createResource(node.getURI());
		} else if (node.isBlank()) {
			s = model.createResource(new AnonId(node.getBlankNodeId()));
		} else {
			throw(new InvalidSPDXAnalysisException("Node can not be a literal"));
		}
		return s;
	}
	
	/**
	 * Add a literal string property value
	 * @param subject
	 * @param propertyName
	 * @param propertyValue
	 * @throws InvalidSPDXAnalysisException
	 */
	private void addProperty(Node subject, String propertyName, String[] propertyValue) throws InvalidSPDXAnalysisException { 
		addProperty(subject, SPDX_NAMESPACE, propertyName, propertyValue);
	}
	
	/**
	 * Add a literal string property value
	 * @param subject
	 * @param nameSpace
	 * @param propertyName
	 * @param propertyValue
	 * @throws InvalidSPDXAnalysisException
	 */
	private void addProperty(Node subject, String nameSpace, String propertyName, String[] propertyValue) throws InvalidSPDXAnalysisException { 
		Resource s = getResource(subject);
		for (int i = 0; i < propertyValue.length; i++) {
			Property p = model.createProperty(nameSpace, propertyName);
			if (propertyValue[i].equals(SpdxRdfConstants.NONE_VALUE)) {
				Resource r = model.createResource(SpdxRdfConstants.URI_VALUE_NONE);
				s.addProperty(p, r);
			} else if (propertyValue[i].equals(SpdxRdfConstants.NOASSERTION_VALUE)) {
				Resource r = model.createResource(SpdxRdfConstants.URI_VALUE_NOASSERTION);
				s.addProperty(p, r);
			} else {
				s.addProperty(p, propertyValue[i]);
			}
		}
	}
	
	/**
	 * @return the spdxVersion or null if there is no SPDX document
	 * @throws InvalidSPDXAnalysisException 
	 */
	public String getSpdxVersion() throws InvalidSPDXAnalysisException {
		String[] versions = findDocPropertieStringValues(getSpdxDocNode(), PROP_SPDX_VERSION);
		if (versions == null || versions.length == 0) {
			return null;
		}
		if (versions.length > 1) {
			throw(new InvalidSPDXAnalysisException("More than one version exists for the SPDX Document"));
		}
		return versions[0];
	}

	/**
	 * @param comment the documentComment to set
	 * @throws InvalidSPDXAnalysisException 
	 */
	public void setDocumentComment(String comment) throws InvalidSPDXAnalysisException {
		Node spdxDocNode = getSpdxDocNode();
		if (spdxDocNode == null) {
			throw(new InvalidSPDXAnalysisException("Must create the SPDX document before setting spdxVersion"));
		}
		removeProperties(spdxDocNode, RDFS_NAMESPACE, RDFS_PROP_COMMENT);
		if (comment != null && !comment.isEmpty()) {
			addProperty(spdxDocNode, RDFS_NAMESPACE, RDFS_PROP_COMMENT, new String[] {comment});
		}
	}

	/**
	 * @return the documentComment or null if there is no SPDX document or SPDX document comment
	 * @throws InvalidSPDXAnalysisException 
	 */
	public String getDocumentComment() throws InvalidSPDXAnalysisException {
		String[] comments = findDocPropertieStringValues(getSpdxDocNode(), RDFS_NAMESPACE, RDFS_PROP_COMMENT);
		if (comments == null || comments.length == 0) {
			return null;
		}
		if (comments.length > 1) {
			throw(new InvalidSPDXAnalysisException("More than one document comment exists for the SPDX Document"));
		}
		return comments[0];
	}

	/**
	 * @param spdxVersion the spdxVersion to set
	 * @throws InvalidSPDXAnalysisException 
	 */
	public void setSpdxVersion(String spdxVersion) throws InvalidSPDXAnalysisException {
		String versionVerify = verifySpdxVersion(spdxVersion);
		if (versionVerify != null && !versionVerify.isEmpty()) {
			throw(new InvalidSPDXAnalysisException(versionVerify));
		}
		Node spdxDocNode = getSpdxDocNode();
		if (spdxDocNode == null) {
			throw(new InvalidSPDXAnalysisException("Must create the SPDX document before setting spdxVersion"));
		}
		removeProperties(spdxDocNode, PROP_SPDX_VERSION);
		addProperty(spdxDocNode, PROP_SPDX_VERSION, new String[] {spdxVersion});
	}
	
	public SpdxListedLicense getDataLicense() throws InvalidSPDXAnalysisException {
		List alLic = Lists.newArrayList();
		Node p = model.getProperty(SPDX_NAMESPACE, PROP_SPDX_DATA_LICENSE).asNode();
		Triple m = Triple.createMatch(getSpdxDocNode(), p, null);
		ExtendedIterator tripleIter = model.getGraph().find(m);	
		while (tripleIter.hasNext()) {
			Triple t = tripleIter.next();
			alLic.add(LicenseInfoFactory.getLicenseInfoFromModel(this, t.getObject()));
		}
		if (alLic.size() > 1) {
			throw(new InvalidSPDXAnalysisException("Too many data licenses"));
		}
		if (alLic.size() == 0) {
			return null;
		}
		if (!(alLic.get(0) instanceof SpdxListedLicense)) {
			throw(new InvalidSPDXAnalysisException("Incorrect license for datalicense - must be a standard SPDX license type"));
		}
		return (SpdxListedLicense)(alLic.get(0));
	}
	
	public void setDataLicense(SpdxListedLicense dataLicense) throws InvalidSPDXAnalysisException {
		String spdxVersion = this.getSpdxVersion();
		if (spdxVersion == null) {
			throw(new InvalidSPDXAnalysisException("Can not set a data license - document does not contain a version.  Set the SPDX version property before setting the data license."));
		}
		if (spdxVersion.equals(ONE_DOT_ZERO_SPDX_VERSION)) {
			if (!dataLicense.getLicenseId().equals(SPDX_DATA_LICENSE_ID_VERSION_1_0)) {
				throw(new InvalidSPDXAnalysisException("Invalid data license for version 1 SPDX document - license must have ID "+SPDX_DATA_LICENSE_ID_VERSION_1_0));
			}
		} else {
			if (!dataLicense.getLicenseId().equals(SPDX_DATA_LICENSE_ID)) {
				throw(new InvalidSPDXAnalysisException("Invalid data license for SPDX document - license must have ID "+SPDX_DATA_LICENSE_ID));
			}
		}
		
		removeProperties(getSpdxDocNode(), PROP_SPDX_DATA_LICENSE);
		Resource s = getResource(getSpdxDocNode());
		Property p = model.createProperty(SPDX_NAMESPACE, PROP_SPDX_DATA_LICENSE);

		Resource lic = dataLicense.createResource(this);
		s.addProperty(p, lic);
	}

	public SPDXFile[] getFileReferences() throws InvalidSPDXAnalysisException {
		List alFiles = Lists.newArrayList();
		Node p = model.getProperty(SPDX_NAMESPACE, PROP_SPDX_FILE_REFERENCE).asNode();
		Triple m = Triple.createMatch(getSpdxDocNode(), p, null);
		ExtendedIterator tripleIter = model.getGraph().find(m);	
		while (tripleIter.hasNext()) {
			Triple t = tripleIter.next();
			alFiles.add(new SPDXFile(this, t.getObject()));
		}
		SPDXFile[] retval = new SPDXFile[alFiles.size()];
		return alFiles.toArray(retval);
	}

	@Deprecated
	/**
	 * This method id deprecated - please use the getCreator() method for this information
	 * @return the The creators of the Analysis
	 * @throws InvalidSPDXAnalysisException 
	 */
	public String[] getCreators() throws InvalidSPDXAnalysisException {
		SPDXCreatorInformation creator = getCreatorInfo();
		if (creator != null && creator.getCreators() != null) {
			return creator.getCreators();
		} else {
			return null;
		}
	}
	
	public SPDXCreatorInformation getCreatorInfo() throws InvalidSPDXAnalysisException {
		Node spdxDocNode = getSpdxDocNode();
		if (spdxDocNode == null) {
			throw(new InvalidSPDXAnalysisException("No SPDX Document was found.  Can not access the creator information"));
		}
		List als = Lists.newArrayList();
		Node p = model.getProperty(SPDX_NAMESPACE, PROP_SPDX_CREATION_INFO).asNode();
		Triple m = Triple.createMatch(spdxDocNode, p, null);
		ExtendedIterator tripleIter = model.getGraph().find(m);	
		while (tripleIter.hasNext()) {
			Triple t = tripleIter.next();
			als.add(new SPDXCreatorInformation(model, t.getObject()));
		}
		if (als.size() > 1) {
			throw(new InvalidSPDXAnalysisException("Too many creation information for document.  Only one is allowed."));
		}
		if (als.size() > 0) {
			return als.get(0);
		} else {
			return null;
		}
	}

	/**
	 * @param creators the creators of the analysis
	 * @throws InvalidSPDXDocException 
	 */
	public void setCreationInfo(SPDXCreatorInformation creator) throws InvalidSPDXAnalysisException {
		Node spdxDocNode = getSpdxDocNode();
		if (spdxDocNode == null) {
			throw(new InvalidSPDXAnalysisException("Must have an SPDX document to set creationInfo"));
		}
		// delete any previous created
		Property p = model.getProperty(SPDX_NAMESPACE, PROP_SPDX_CREATION_INFO);
		Resource s = getResource(spdxDocNode);
		model.removeAll(s, p, null);
		// add the property
		p = model.createProperty(SPDX_NAMESPACE, PROP_SPDX_CREATION_INFO);
		s.addProperty(p, creator.createResource(model));
	}

	@Deprecated
	/**
	 * This method id deprecated - please use the getCreator() method for this information
	 * @return the creator comments for the analysis
	 * @throws InvalidSPDXAnalysisException 
	 */
	public String getCreatorComment() throws InvalidSPDXAnalysisException {
		SPDXCreatorInformation creator = this.getCreatorInfo();
		if (creator != null) {
			return creator.getComment();
		} else {
			return null;
		}
	}

	/**
	 * @return the reviewers
	 * @throws InvalidSPDXAnalysisException 
	 */
	public SPDXReview[] getReviewers() throws InvalidSPDXAnalysisException {
		Node spdxDocNode = getSpdxDocNode();
		if (spdxDocNode == null) {
			throw(new InvalidSPDXAnalysisException("Must have an SPDX document to get reviewers"));
		}
		List als = Lists.newArrayList();
		als.clear();
		Node p = model.getProperty(SPDX_NAMESPACE, PROP_SPDX_REVIEWED_BY).asNode();
		Triple m = Triple.createMatch(spdxDocNode, p, null);
		ExtendedIteratortripleIter = model.getGraph().find(m);	
		while (tripleIter.hasNext()) {
			Triple t = tripleIter.next();
			als.add(new SPDXReview(model, t.getObject()));
		}
		SPDXReview[] reviewers = new SPDXReview[als.size()];
		reviewers = als.toArray(reviewers);
		return reviewers;
	}

	/**
	 * @param reviewers the reviewers to set
	 * @throws InvalidSPDXAnalysisException 
	 */
	public void setReviewers(SPDXReview[] reviewers) throws InvalidSPDXAnalysisException {
		if (reviewers.length > 0) {
			List errors = Lists.newArrayList();
			for (int i = 0;i < reviewers.length; i++) {
				errors.addAll(reviewers[i].verify());
			}
			if (errors.size() > 0) {
				StringBuilder sb = new StringBuilder("Invalid reviewers due to the following errors in validation:\n");
				for (int i = 0; i < errors.size(); i++) {
					sb.append(errors.get(i));
					sb.append('\n');
				}
				throw(new InvalidSPDXAnalysisException(sb.toString()));
			}
		}
		Node spdxDocNode = getSpdxDocNode();
		if (spdxDocNode == null) {
			throw(new InvalidSPDXAnalysisException("Must have an SPDX document to set reviewers"));
		}
		// delete any previous created
		Property p = model.getProperty(SPDX_NAMESPACE, PROP_SPDX_REVIEWED_BY);
		Resource s = getResource(spdxDocNode);
		model.removeAll(s, p, null);
		// add the property
		for (int i = 0; i < reviewers.length; i++) {
			p = model.createProperty(SPDX_NAMESPACE, PROP_SPDX_REVIEWED_BY);
			s.addProperty(p, reviewers[i].createResource(model));
		}
	}

	@Deprecated
	/**
	 * This method id deprecated - please use the getCreator() method for this information
	 * @return the created
	 * @throws InvalidSPDXAnalysisException 
	 */
	public String getCreated() throws InvalidSPDXAnalysisException {
		SPDXCreatorInformation creator = this.getCreatorInfo();
		if (creator != null) {
			return creator.getCreated();
		} else {
			return null;
		}
	}

	/**
	 * @return the spdxPackage
	 * @throws InvalidSPDXAnalysisException 
	 */
	public SPDXPackage getSpdxPackage() throws InvalidSPDXAnalysisException {
		if (this.spdxPackage != null) {
			return this.spdxPackage;
		}
		Node spdxDocNode = getSpdxDocNode();
		if (spdxDocNode == null) {
			throw(new InvalidSPDXAnalysisException("Must set an SPDX doc before getting an SPDX package"));
		}
		Node p = model.getProperty(SPDX_NAMESPACE, PROP_SPDX_PACKAGE).asNode();
		Triple m = Triple.createMatch(spdxDocNode, p, null);
		ExtendedIterator tripleIter = model.getGraph().find(m);	
		SPDXPackage newSpdxPackage = null;
		while (tripleIter.hasNext()) {
			Triple t = tripleIter.next();
			newSpdxPackage = new SPDXPackage(t.getObject(), this);
		}
		this.spdxPackage = newSpdxPackage;
		return newSpdxPackage;
	}

	/**
	 * Creates an empty SPDX package
	 * @param uri Unique URI representing the SPDX package
	 * @return 
	 * @throws InvalidSPDXAnalysisException 
	 */
	public SPDXPackage createSpdxPackage(String uri) throws InvalidSPDXAnalysisException {
		Node spdxDocNode = getSpdxDocNode();
		if (spdxDocNode == null) {
			throw(new InvalidSPDXAnalysisException("Must create the SPDX document before creating an SPDX Package"));
		}
		// delete the previous SPDX package
		Property p = model.getProperty(SPDX_NAMESPACE, PROP_SPDX_PACKAGE);
		Resource s = getResource(getSpdxDocNode());
		model.removeAll(s, p, null);
		p = model.createProperty(SPDX_NAMESPACE, PROP_SPDX_PACKAGE);
		Resource pkgType = model.createResource(SPDX_NAMESPACE+CLASS_SPDX_PACKAGE);
		Resource spdxPkg = model.createResource(uri, pkgType);
		s.addProperty(p, spdxPkg);
		return this.spdxPackage = new SPDXPackage(spdxPkg.asNode(), this);
	}
	
	public void createSpdxPackage() throws InvalidSPDXAnalysisException {
		// generate a unique URI by appending the next available SPDX element ref to the document namespace
		Node spdxDocNode = getSpdxDocNode();
		if (spdxDocNode == null) {
			throw(new InvalidSPDXAnalysisException("Must create the SPDX document before creating an SPDX Package"));
		}
		createSpdxPackage(this.documentNamespace + this.getNextSpdxElementRef());
	}

	/**
	 * @return the nonStandardLicenses
	 * @throws InvalidSPDXAnalysisException 
	 */
	public ExtractedLicenseInfo[] getExtractedLicenseInfos() throws InvalidSPDXAnalysisException {
		// nonStandardLicenses
		Node spdxDocNode = getSpdxDocNode();
		if (spdxDocNode == null) {
			throw(new InvalidSPDXAnalysisException("No SPDX Document - can not get the Non Standard Licenses"));
		}
		List alLic = Lists.newArrayList();
		Node p = model.getProperty(SPDX_NAMESPACE, PROP_SPDX_EXTRACTED_LICENSES).asNode();
		Triple m = Triple.createMatch(spdxDocNode, p, null);
		ExtendedIterator tripleIter = model.getGraph().find(m);	
		while (tripleIter.hasNext()) {
			Triple t = tripleIter.next();
			alLic.add(new ExtractedLicenseInfo(this, t.getObject()));
		}
		ExtractedLicenseInfo[] nonStandardLicenses = new ExtractedLicenseInfo[alLic.size()];
		nonStandardLicenses = alLic.toArray(nonStandardLicenses);
		return nonStandardLicenses;
	}

	/**
	 * Resets all ExtractedLicenseInfos to nonStandardLicenses.  Removes references to any ExtractedLicenseInfos not present in nonStandardLicenses.
	 * If any LicenseID's are already present in the model, the text will be replaced with the text in the new nonStandardLicenses
	 * @param nonStandardLicenses the nonStandardLicenses to set
	 * @throws InvalidSPDXAnalysisException 
	 */
	public void setExtractedLicenseInfos(ExtractedLicenseInfo[] nonStandardLicenses) throws InvalidSPDXAnalysisException {
		List errors = Lists.newArrayList();
		// verify the licenses
		for (int i = 0;i < nonStandardLicenses.length; i++) {
			errors.addAll(nonStandardLicenses[i].verify());
		}
		if (errors.size() > 0) {
			StringBuilder sb = new StringBuilder("Invalid extracted license information due to the following verification failures:\n");
			for (int i = 0; i < errors.size(); i++) {
				sb.append(errors.get(i));
				sb.append('\n');
			}
			throw new InvalidSPDXAnalysisException(sb.toString());
		}
		Node spdxDocNode = getSpdxDocNode();
		if (spdxDocNode == null) {
			throw(new InvalidSPDXAnalysisException("Must create the SPDX document before setting Non-Standard Licenses"));
		}
		// validate the license ID's and update the next license ID property
		initializeNextLicenseRef(nonStandardLicenses);
		// delete the previous createdby's
		Property p = model.getProperty(SPDX_NAMESPACE, PROP_SPDX_EXTRACTED_LICENSES);
		Resource s = getResource(getSpdxDocNode());
		model.removeAll(s, p, null);
		for (int i = 0; i < nonStandardLicenses.length; i++) {
			p = model.createProperty(SPDX_NAMESPACE, PROP_SPDX_EXTRACTED_LICENSES);
			s.addProperty(p, nonStandardLicenses[i].createResource(this));
		}
	}
	
	/**
	 * Adds a new non-standard license containing the text provided.  Forms the license ID
	 * from the next License ID available
	 * @param licenseText
	 * @return the newly created NonStandardLicense
	 * @throws InvalidSPDXAnalysisException
	 */
	public ExtractedLicenseInfo addNewExtractedLicenseInfo(String licenseText) throws InvalidSPDXAnalysisException {
		String licenseID = getNextLicenseRef();
		ExtractedLicenseInfo retval = new ExtractedLicenseInfo(licenseID, licenseText);
		addNewExtractedLicenseInfo(retval);
		return retval;
	}
	
	/**
	 * Adds the license as a new ExtractedLicenseInfo
	 * @param license
	 * @throws InvalidSPDXAnalysisException
	 */
	public void addNewExtractedLicenseInfo(ExtractedLicenseInfo license) throws InvalidSPDXAnalysisException {
		if (extractedLicenseExists(license.getLicenseId())) {
			throw(new InvalidSPDXAnalysisException("Can not add license - ID "+license.getLicenseId()+" already exists."));
		}
		Property p = model.getProperty(SPDX_NAMESPACE, PROP_SPDX_EXTRACTED_LICENSES);
		Resource s = getResource(getSpdxDocNode());
		s.addProperty(p, license.createResource(this));		
	}
	
	/**
	 * @param id
	 * @return true if the license ID is already in the model as an extracted license info
	 * @throws InvalidSPDXAnalysisException 
	 */
	protected boolean extractedLicenseExists(String id) throws InvalidSPDXAnalysisException {
		Node p = model.getProperty(SPDX_NAMESPACE, PROP_LICENSE_ID).asNode();
		Node o = NodeFactory.createLiteral(id);
		Triple m = Triple.createMatch(null, p, o);
		ExtendedIterator tripleIter = model.getGraph().find(m);	
		return tripleIter.hasNext();
	}

	/**
	 * @return next available license ID for an ExtractedLicenseInfo
	 */
	public synchronized String getNextLicenseRef() {
		int nextLicNum = this.nextLicenseRef.getAndIncrement();
		return formNonStandardLicenseID(nextLicNum);
	}
	
	/**
	 * @return return the next available SPDX element reference.
	 */
	@Override
	public String getNextSpdxElementRef() {
		int nextSpdxElementNum = this.nextElementRef.getAndIncrement();
		return formSpdxElementRef(nextSpdxElementNum);
	}

	public static String formSpdxElementRef(int refNum) {
		return SPDX_ELEMENT_REF_PRENUM + String.valueOf(refNum);
	}

	/**
	 * @return the URI of the SPDX Document
	 */
	public String getSpdxDocUri() {
		// populate the model
		Node spdxDocNode = getSpdxDocNode();
		if (spdxDocNode == null) {
			return null;
		}
		return spdxDocNode.toString(false);
	}
	
	/**
	 * @return the model
	 */
	@Override
    public Model getModel() {
		return model;
	}

	/**
	 * @param model the model to set
	 * @throws InvalidSPDXAnalysisException 
	 */
	public void setModel(Model model) throws InvalidSPDXAnalysisException {
		Model oldModel = this.model;
		this.model = model;
		try {
			List errors = initialize();
			if (errors != null && errors.size() > 0) {
				this.model = oldModel;
				throw(new InvalidSPDXAnalysisException("New model contains verification errors"));
			}
		} catch (InvalidSPDXAnalysisException e) {
			this.model = oldModel;
			throw(e);
		}
	}
	/**
	 * Creates a new empty SPDX Document with the current SPDX document version.
	 * Note: Any previous SPDX documents will be deleted from the model to
	 * preserve the one and only one constraint.
	 * Note: Follow-up calls MUST be made to add the required properties for this
	 * to be a valid SPDX document
	 * @param uri URI for the SPDX Document
	 * @throws InvalidSPDXAnalysisException 
	 */
	public void createSpdxAnalysis(String uri) throws InvalidSPDXAnalysisException {
		createSpdxAnalysis(uri, CURRENT_SPDX_VERSION);
	}
	
	/**
	 * Creates a new empty SPDX Document.
	 * Note: Any previous SPDX documents will be deleted from the model to
	 * preserve the one and only one constraint.
	 * Note: Follow-up calls MUST be made to add the required properties for this
	 * to be a valid SPDX document
	 * @param uri URI for the SPDX Document
	 * @param spdxVersion The version of SPDX analysis to create (impacts the data license for some versions)
	 * @throws InvalidSPDXAnalysisException 
	 */
	public void createSpdxAnalysis(String uri, String spdxVersion) throws InvalidSPDXAnalysisException {
		String v = verifySpdxVersion(spdxVersion);
		if (v != null) {
			throw(new InvalidSPDXAnalysisException("Invalid SPDX Version: "+v));
		}
		Node spdxDocNode = getSpdxDocNode();
		if (spdxDocNode != null) {
			// delete
			model.removeAll();
		}
		model.setNsPrefix("spdx", SPDX_NAMESPACE);
		model.setNsPrefix("doap", DOAP_NAMESPACE);
		model.setNsPrefix("rdfs", RDFS_NAMESPACE);
		model.setNsPrefix("rdf", RDF_NAMESPACE);
		this.documentNamespace = formDocNamespace(uri);
		model.setNsPrefix("", this.documentNamespace);
		// set the default namespace to the document namespace
		Resource spdxAnalysisType = model.createResource(SPDX_NAMESPACE+CLASS_SPDX_DOCUMENT);
		model.createResource(uri, spdxAnalysisType);
		// add the version
		this.setSpdxVersion(spdxVersion);
		// reset the next license number and next spdx element num
		this.nextElementRef.set(1);
		this.nextLicenseRef.set(1);
		// add the default data license
		if (!spdxVersion.equals(POINT_EIGHT_SPDX_VERSION) && !spdxVersion.equals(POINT_NINE_SPDX_VERSION)) { // added as a mandatory field in 1.0
			try {
				SpdxListedLicense dataLicense;
				if (spdxVersion.equals(ONE_DOT_ZERO_SPDX_VERSION)) 
					{ 
					dataLicense = (SpdxListedLicense)(LicenseInfoFactory.parseSPDXLicenseString(SPDX_DATA_LICENSE_ID_VERSION_1_0));
				} else {
					dataLicense = (SpdxListedLicense)(LicenseInfoFactory.parseSPDXLicenseString(SPDX_DATA_LICENSE_ID));				
				}
				this.setDataLicense(dataLicense);
			} catch (InvalidLicenseStringException e) {
				throw new InvalidSPDXAnalysisException("Unable to create data license", e);
			}
		}
	}
	
	/**
	 * Form the document namespace URI from the SPDX document URI
	 * @param docUriString String form of the SPDX document URI
	 * @return
	 */
	private String formDocNamespace(String docUriString) {
		// just remove any fragments for the DOC URI
		int fragmentIndex = docUriString.indexOf('#');
		if (fragmentIndex <= 0) {
			return docUriString + "#";
		} else {
			return docUriString.substring(0, fragmentIndex) + "#";
		}
	}

	/**
	 * @return the spdx doc node from the model
	 */
	private Node getSpdxDocNode() {
		Node spdxDocNode = null;
		Node rdfTypePredicate = this.model.getProperty(RDF_NAMESPACE, RDF_PROP_TYPE).asNode();
		Node spdxDocObject = this.model.getProperty(SPDX_NAMESPACE, CLASS_SPDX_DOCUMENT).asNode();
		Triple m = Triple.createMatch(null, rdfTypePredicate, spdxDocObject);
		ExtendedIterator tripleIter = model.getGraph().find(m);	// find the document
		while (tripleIter.hasNext()) {
			Triple docTriple = tripleIter.next();
			spdxDocNode = docTriple.getSubject();
		}
		return spdxDocNode;
	}

	/**
	 * @return Document namespace
	 */
	@Override
    public String getDocumentNamespace() {
		return this.documentNamespace;
	}
	
	protected SPDXDocument getDocument() {
		return this;
	}
	
	public SPDXDocument getSpdxDocument() {
		return this;
	}

	/* (non-Javadoc)
	 * @see org.spdx.rdfparser.IModelContainer#spdxElementRefExists(java.lang.String)
	 */
	@Override
	public boolean spdxElementRefExists(String elementRef) {
		// TODO Implement
		return false;
	}

	/* (non-Javadoc)
	 * @see org.spdx.rdfparser.IModelContainer#addSpdxElementRef(java.lang.String)
	 */
	@Override
	public void addSpdxElementRef(String elementRef)
			throws InvalidSPDXAnalysisException {
		// TODO Implement
		
	}

	/* (non-Javadoc)
	 * @see org.spdx.rdfparser.IModelContainer#documentNamespaceToId(java.lang.String)
	 */
	@Override
	public String documentNamespaceToId(String externalNamespace) {
		// SPDXDocument does not support external document references
		return null;
	}

	/* (non-Javadoc)
	 * @see org.spdx.rdfparser.IModelContainer#externalDocumentIdToNamespace(java.lang.String)
	 */
	@Override
	public String externalDocumentIdToNamespace(String docId) {
		// SPDXDocument does not support external document references
		return null;
	}

	/* (non-Javadoc)
	 * @see org.spdx.rdfparser.IModelContainer#createResource(org.apache.jena.rdf.model.Resource, java.lang.String, org.apache.jena.rdf.model.Resource, org.spdx.rdfparser.model.IRdfModel)
	 */
	@Override
	public Resource createResource(Resource duplicate, String uri,
			Resource type, IRdfModel modelObject) {
		if (duplicate != null) {
			return duplicate;
		} else if (uri == null) {			
			return model.createResource(type);
		} else {
			return model.createResource(uri, type);
		}
	}

	/* (non-Javadoc)
	 * @see org.spdx.rdfparser.IModelContainer#addCheckNodeObject(org.apache.jena.graph.Node, org.spdx.rdfparser.model.IRdfModel)
	 */
	@Override
	public boolean addCheckNodeObject(Node node, IRdfModel rdfModelObject) {
		// TODO Auto-generated method stub
		return false;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy