--- /dev/null
+build.xml
+/nbproject
+nb-configuration.xml
+/target/
+release.properties
+pom.xml.releaseBackup
+nbactions.xml
--- /dev/null
+language: java
+
+jdk:
+ - openjdk7
+ - oraclejdk7
+ - oraclejdk8
+
+bracnhes:
+ only:
+ - master
--- /dev/null
+The work represented by this source file is partially or entirely funded
+by the EGI-InSPIRE project through the European Commission's 7th Framework
+Programme (contract # INFSO-RI-261323)
+
+Copyright (c) 2014-2015 CESNET
+
+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.
--- /dev/null
+jOCCI-core - A Java OCCI Framework
+==================================
+
+[](http://travis-ci.org/EGI-FCTF/jOCCI-core)
+
+Requirements
+------------
+* JDK 7+
+* Maven
+
+Installation
+------------
+Using Maven:
+```xml
+<dependency>
+ <groupId>cz.cesnet.cloud</groupId>
+ <artifactId>jocci-core</artifactId>
+ <version>0.2.4</version>
+</dependency>
+```
+### Continuous integration
+
+[Continuous integration for jOCCI by Travis-CI](http://travis-ci.org/EGI-FCTF/jOCCI-core/)
+
+### Contribute
+
+1. Fork it.
+2. Create a branch (git checkout -b my_markup)
+3. Commit your changes (git commit -am "My changes")
+4. Push to the branch (git push origin my_markup)
+5. Create an Issue with a link to your branch
--- /dev/null
+Information about jocci-core
+----------------------------
+
+This package was debianized using the mh_make command
+from the maven-debian-helper package.
+
+The build system uses Maven but prevents it from downloading
+anything from the Internet, making the build compliant with
+the Debian policy.
--- /dev/null
+jocci-core (0.2.4-1) unstable; urgency=low
+
+ * Initial release
+
+ -- František Dvořák <valtri@civ.zcu.cz> Fri, 09 Sep 2016 00:13:39 +0200
--- /dev/null
+Source: jocci-core
+Section: java
+Priority: optional
+Maintainer: Debian Java Maintainers <pkg-java-maintainers@lists.alioth.debian.org>
+Uploaders: František Dvořák <valtri@civ.zcu.cz>
+Build-Depends: debhelper (>= 9), cdbs, default-jdk, maven-debian-helper (>= 1.5)
+Build-Depends-Indep: libslf4j-java, junit4, libslf4j-java, default-jdk-doc, libmaven-javadoc-plugin-java
+Standards-Version: 3.9.5
+Vcs-Svn: svn://anonscm.debian.org/pkg-java/trunk/jocci-core
+Vcs-Browser: http://anonscm.debian.org/viewvc/pkg-java/trunk/jocci-core
+Homepage: https://github.com/EGI-FCTF/jOCCI-core
+
+Package: libjocci-core-java
+Architecture: all
+Depends: ${misc:Depends}, ${maven:Depends}
+Recommends: ${maven:OptionalDepends}
+Suggests: libjocci-core-java-doc
+Description: cz.cesnet.cloud:jocci-core
+ OCCI-core is a java-based implementation of the OCCI (Open Cloud Computing
+ Interface) standard. jOCCI-core currently implements:
+ .
+ * classes defined by the OCCI Core model and methods for manipulating them
+ * methods for rendering plain-text or HTTP header representations of those
+ classes' instances
+ * methods for basic parsing of such renderings
+ * methods for validation of OCCI requests with respect to known models on
+ client-side
+
+Package: libjocci-core-java-doc
+Architecture: all
+Section: doc
+Depends: ${misc:Depends}, ${maven:DocDepends}
+Recommends: ${maven:DocOptionalDepends}
+Suggests: libjocci-core-java
+Description: Documentation for cz.cesnet.cloud:jocci-core
+ OCCI-core is a java-based implementation of the OCCI (Open Cloud Computing
+ Interface) standard. jOCCI-core currently implements:
+ .
+ * classes defined by the OCCI Core model and methods for manipulating them
+ * methods for rendering plain-text or HTTP header representations of those
+ classes' instances
+ * methods for basic parsing of such renderings
+ * methods for validation of OCCI requests with respect to known models on
+ client-side
+ .
+ This package contains the API documentation of libjocci-core-java.
--- /dev/null
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: cz.cesnet.cloud:jocci-core
+Source: https://github.com/EGI-FCTF/jOCCI-core
+
+Files: *
+Copyright: 2016, Michal Kimle <kimle.michal@gmail.com>
+License: Apache-2.0
+
+Files: debian/*
+Copyright: 2016, František Dvořák <valtri@civ.zcu.cz>
+License: Apache-2.0
+
+License: Apache-2.0
+ On Debian systems, the full text of the Apache-2.0 license
+ can be found in the file '/usr/share/common-licenses/Apache-2.0'
+
+
--- /dev/null
+Document: libjocci-core-java
+Title: API Javadoc for cz.cesnet.cloud:jocci-core
+Author: cz.cesnet.cloud:jocci-core developers
+Abstract: This is the API Javadoc provided for the
+ libjocci-core-java library.
+Section: Programming
+
+Format: HTML
+Index: /usr/share/doc/libjocci-core-java/api/index.html
+Files: /usr/share/doc/libjocci-core-java/api/*
--- /dev/null
+target/apidocs/* usr/share/doc/libjocci-core-java/api
+
--- /dev/null
+# List of POM files for the package
+# Format of this file is:
+# <path to pom file> [option]*
+# where option can be:
+# --ignore: ignore this POM and its artifact if any
+# --ignore-pom: don't install the POM. To use on POM files that are created
+# temporarily for certain artifacts such as Javadoc jars. [mh_install, mh_installpoms]
+# --no-parent: remove the <parent> tag from the POM
+# --package=<package>: an alternative package to use when installing this POM
+# and its artifact
+# --has-package-version: to indicate that the original version of the POM is the same as the upstream part
+# of the version for the package.
+# --keep-elements=<elem1,elem2>: a list of XML elements to keep in the POM
+# during a clean operation with mh_cleanpom or mh_installpom
+# --artifact=<path>: path to the build artifact associated with this POM,
+# it will be installed when using the command mh_install. [mh_install]
+# --java-lib: install the jar into /usr/share/java to comply with Debian
+# packaging guidelines
+# --usj-name=<name>: name to use when installing the library in /usr/share/java
+# --usj-version=<version>: version to use when installing the library in /usr/share/java
+# --no-usj-versionless: don't install the versionless link in /usr/share/java
+# --dest-jar=<path>: the destination for the real jar.
+# It will be installed with mh_install. [mh_install]
+# --classifier=<classifier>: Optional, the classifier for the jar. Empty by default.
+# --site-xml=<location>: Optional, the location for site.xml if it needs to be installed.
+# Empty by default. [mh_install]
+#
+pom.xml --has-package-version
--- /dev/null
+
+com.github.github site-maven-plugin * * * *
+org.apache.maven.plugins maven-javadoc-plugin * * * *
+org.apache.maven.plugins maven-release-plugin * * * *
+org.sonatype.plugins nexus-staging-maven-plugin * * * *
--- /dev/null
+# Include here properties to pass to Maven during the build.
+# For example:
+# maven.test.skip=true
+
--- /dev/null
+
+cz.cesnet.cloud jocci-core jar s/.*/debian/ * *
+junit junit jar s/4\..*/4.x/ * *
--- /dev/null
+#!/usr/bin/make -f
+
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/cdbs/1/class/maven.mk
+
+JAVA_HOME := /usr/lib/jvm/default-java
+
+get-orig-source:
+ uscan --download-version $(DEB_UPSTREAM_VERSION) --force-download --rename
--- /dev/null
+3.0 (quilt)
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>cz.cesnet.cloud</groupId>
+ <artifactId>jocci-core</artifactId>
+ <version>0.2.4</version>
+ <packaging>jar</packaging>
+ <name>${project.groupId}:${project.artifactId}</name>
+ <description>A Java OCCI framework - core library.</description>
+ <url>https://github.com/EGI-FCTF/jOCCI-core</url>
+ <licenses>
+ <license>
+ <name>The Apache License, Version 2.0</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+ </license>
+ </licenses>
+ <developers>
+ <developer>
+ <name>Michal Kimle</name>
+ <email>kimle.michal@gmail.com</email>
+ <organization>CESNET</organization>
+ <organizationUrl>http://www.cesnet.cz/</organizationUrl>
+ </developer>
+ </developers>
+ <scm>
+ <connection>scm:git:git@github.com:EGI-FCTF/jOCCI-core.git</connection>
+ <developerConnection>scm:git:git@github.com:EGI-FCTF/jOCCI-core.git</developerConnection>
+ <url>https://github.com/EGI-FCTF/jOCCI-core</url>
+ <tag>jocci-core-0.2.4</tag>
+ </scm>
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.7.7</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>1.7.7</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.10</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <maven.compiler.source>1.7</maven.compiler.source>
+ <maven.compiler.target>1.7</maven.compiler.target>
+ <github.global.server>github</github.global.server>
+ </properties>
+ <distributionManagement>
+ <snapshotRepository>
+ <id>ossrh</id>
+ <url>https://oss.sonatype.org/content/repositories/snapshots</url>
+ </snapshotRepository>
+ <repository>
+ <id>ossrh</id>
+ <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
+ </repository>
+ </distributionManagement>
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.9</version>
+ <reportSets>
+ <reportSet>
+ <reports>
+ <report>javadoc</report>
+ </reports>
+ </reportSet>
+ <reportSet>
+ <id>aggregate</id>
+ <inherited>false</inherited>
+ <reports>
+ <report>aggregate</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ </plugin>
+ </plugins>
+ </reporting>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.sonatype.plugins</groupId>
+ <artifactId>nexus-staging-maven-plugin</artifactId>
+ <version>1.6.3</version>
+ <extensions>true</extensions>
+ <configuration>
+ <serverId>ossrh</serverId>
+ <nexusUrl>https://oss.sonatype.org/</nexusUrl>
+ <autoReleaseAfterClose>true</autoReleaseAfterClose>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-release-plugin</artifactId>
+ <version>2.5</version>
+ <configuration>
+ <autoVersionSubmodules>true</autoVersionSubmodules>
+ <useReleaseProfile>false</useReleaseProfile>
+ <releaseProfiles>release</releaseProfiles>
+ <goals>deploy</goals>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-site-plugin</artifactId>
+ <version>3.4</version>
+ </plugin>
+ <plugin>
+ <groupId>com.github.github</groupId>
+ <artifactId>site-maven-plugin</artifactId>
+ <version>0.11</version>
+ <configuration>
+ <message>Creating site for ${project.version}</message>
+ <server>github</server>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>site</goal>
+ </goals>
+ <phase>site</phase>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <profiles>
+ <profile>
+ <id>release</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-source-plugin</artifactId>
+ <version>2.2.1</version>
+ <executions>
+ <execution>
+ <id>attach-sources</id>
+ <goals>
+ <goal>jar-no-fork</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.9.1</version>
+ <executions>
+ <execution>
+ <id>attach-javadocs</id>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-gpg-plugin</artifactId>
+ <version>1.5</version>
+ <executions>
+ <execution>
+ <id>sign-artifacts</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>sign</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
\ No newline at end of file
--- /dev/null
+package cz.cesnet.cloud.occi;
+
+import cz.cesnet.cloud.occi.collection.SetCover;
+import cz.cesnet.cloud.occi.core.ActionInstance;
+import cz.cesnet.cloud.occi.core.Link;
+import cz.cesnet.cloud.occi.core.Resource;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Class representing a collection of OCCI instances. It can contain instances
+ * of classes Resource, Link and ActionInstance. Collection can be assigned a
+ * Model instance which will represent a OCCI model structure for all the
+ * instances in the collection.
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class Collection {
+
+ private final SetCover<Resource> resources = new SetCover<>();
+ private final SetCover<Link> links = new SetCover<>();
+ private final SetCover<ActionInstance> actions = new SetCover<>();
+ private Model model;
+
+ /**
+ * Creates an empty collection instance.
+ */
+ public Collection() {
+ }
+
+ /**
+ * Checks whether collection contains the resource.
+ *
+ * @param resource resource looked up in the collection
+ * @return true if collection contains the resource, false otherwise
+ */
+ public boolean containsResource(Resource resource) {
+ return resources.contains(resource);
+ }
+
+ /**
+ * Checks whether collection contains the resource specified by its
+ * identifier.
+ *
+ * @param resourceIdentifier identifier of the resource looked up in the
+ * collection
+ * @return true if collection contains the resource, false otherwise
+ */
+ public boolean containsResource(String resourceIdentifier) {
+ return resources.contains(resourceIdentifier);
+ }
+
+ /**
+ * Adds resource instance to the collection.
+ *
+ * @param resource resource to be added to the collection
+ * @return true if the addition was successful, false otherwise
+ */
+ public boolean addResource(Resource resource) {
+ return resources.add(resource);
+ }
+
+ /**
+ * Retrieves the resource specified by its identifier from the collection.
+ *
+ * @param resourceIdentifier identifier of the retrieved resource
+ * @return specified resource if in collection, null otherwise
+ */
+ public Resource getResource(String resourceIdentifier) {
+ return resources.get(resourceIdentifier);
+ }
+
+ /**
+ * Removes resource from the collection.
+ *
+ * @param resource resource instance to remove from the collection
+ * @return true if the removal was successful, false otherwise
+ */
+ public boolean removeResource(Resource resource) {
+ return resources.remove(resource);
+ }
+
+ /**
+ * Removes all resources from the collection.
+ */
+ public void clearResources() {
+ resources.clear();
+ }
+
+ /**
+ * Returns all resources in the collection in form of a set.
+ *
+ * @return set of all resources in the collection
+ */
+ public Set<Resource> getResources() {
+ return resources.getSet();
+ }
+
+ /**
+ * Checks whether collection contains the link.
+ *
+ * @param link link looked up in the collection
+ * @return true if collection contains the link, false otherwise
+ */
+ public boolean containsLink(Link link) {
+ return links.contains(link);
+ }
+
+ /**
+ * Checks whether collection contains the link specified by its identifier.
+ *
+ * @param linkIdentifier identifier of the link looked up in the collection
+ * @return true if collection contains the link, false otherwise
+ */
+ public boolean containsLink(String linkIdentifier) {
+ return links.contains(linkIdentifier);
+ }
+
+ /**
+ * Adds link instance to the collection.
+ *
+ * @param link link to be added to the collection
+ * @return true if the addition was successful, false otherwise
+ */
+ public boolean addLink(Link link) {
+ return links.add(link);
+ }
+
+ /**
+ * Retrieves the link specified by its identifier from the collection.
+ *
+ * @param linkIdentifier identifier of the retrieved link
+ * @return specified link if in collection, null otherwise
+ */
+ public Link getLink(String linkIdentifier) {
+ return links.get(linkIdentifier);
+ }
+
+ /**
+ * Removes link from the collection.
+ *
+ * @param link link instance to remove from the collection
+ * @return true if the removal was successful, false otherwise
+ */
+ public boolean removeLink(Link link) {
+ return links.remove(link);
+ }
+
+ /**
+ * Removes all links from the collection.
+ */
+ public void clearLinks() {
+ links.clear();
+ }
+
+ /**
+ * Returns all links in the collection in form of a set.
+ *
+ * @return set of all links in the collection
+ */
+ public Set<Link> getLinks() {
+ return links.getSet();
+ }
+
+ /**
+ * Checks whether collection contains the action.
+ *
+ * @param action action looked up in the collection
+ * @return true if collection contains the action, false otherwise
+ */
+ public boolean containsAction(ActionInstance action) {
+ return actions.contains(action);
+ }
+
+ /**
+ * Checks whether collection contains the action specified by its
+ * identifier.
+ *
+ * @param actionIdentifier identifier of the action looked up in the
+ * collection
+ * @return true if collection contains the action, false otherwise
+ */
+ public boolean containsAction(String actionIdentifier) {
+ return actions.contains(actionIdentifier);
+ }
+
+ /**
+ * Adds action instance to the collection.
+ *
+ * @param action action to be added to the collection
+ * @return true if the addition was successful, false otherwise
+ */
+ public boolean addAction(ActionInstance action) {
+ return actions.add(action);
+ }
+
+ /**
+ * Retrieves the action specified by its identifier from the collection.
+ *
+ * @param actionIdentifier identifier of the retrieved action
+ * @return specified action if in collection, null otherwise
+ */
+ public ActionInstance getAction(String actionIdentifier) {
+ return actions.get(actionIdentifier);
+ }
+
+ /**
+ * Removes action from the collection.
+ *
+ * @param action action instance to remove from the collection
+ * @return true if the removal was successful, false otherwise
+ */
+ public boolean removeAction(ActionInstance action) {
+ return actions.remove(action);
+ }
+
+ /**
+ * Removes all actions from the collection.
+ */
+ public void clearActions() {
+ actions.clear();
+ }
+
+ /**
+ * Returns all actions in the collection in form of a set.
+ *
+ * @return set of all actions in the collection
+ */
+ public Set<ActionInstance> getActions() {
+ return actions.getSet();
+ }
+
+ /**
+ * Merges collection's content to the current collection.
+ *
+ * @param collection collection which content should be merged
+ */
+ public void merge(Collection collection) {
+ resources.addAll(collection.getResources());
+ links.addAll(collection.getLinks());
+ actions.addAll(collection.getActions());
+ }
+
+ /**
+ * Sets model for the whole collection (all the resources, links and actions
+ * in the collection)
+ *
+ * @param model model to be set for this collection
+ */
+ public void setModel(Model model) {
+ this.model = model;
+ for (Link link : links.getSet(true)) {
+ link.setModel(model);
+ }
+ for (Resource resource : resources.getSet(true)) {
+ resource.setModel(model);
+ }
+ for (ActionInstance ai : actions.getSet(true)) {
+ ai.setModel(model);
+ }
+ }
+
+ /**
+ * Returns collection's model.
+ *
+ * @return collection's model
+ */
+ public Model getModel() {
+ return model;
+ }
+
+ /**
+ * @see Object#hashCode()
+ * @return collection's hash code
+ */
+ @Override
+ public int hashCode() {
+ int hash = 5;
+ hash = 41 * hash + Objects.hashCode(this.resources);
+ hash = 41 * hash + Objects.hashCode(this.links);
+ return hash;
+ }
+
+ /**
+ * @see Object#equals(java.lang.Object)
+ * @param obj object to compare collection with
+ * @return true if two collections are equal, false otherwise
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final Collection other = (Collection) obj;
+ if (!Objects.equals(this.resources, other.resources)) {
+ return false;
+ }
+ if (!Objects.equals(this.links, other.links)) {
+ return false;
+ }
+ if (!Objects.equals(this.actions, other.actions)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Resturns string representation of the collection
+ *
+ * @see Object#toString()
+ * @return string representation of the collection
+ */
+ @Override
+ public String toString() {
+ return "Collection{" + "resources=" + resources + ", links=" + links + ", model=" + model + '}';
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi;
+
+import cz.cesnet.cloud.occi.collection.SetCover;
+import cz.cesnet.cloud.occi.core.Action;
+import cz.cesnet.cloud.occi.core.Kind;
+import cz.cesnet.cloud.occi.core.Link;
+import cz.cesnet.cloud.occi.core.Mixin;
+import cz.cesnet.cloud.occi.core.Resource;
+import cz.cesnet.cloud.occi.exception.AmbiguousIdentifierException;
+import cz.cesnet.cloud.occi.parser.CollectionType;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Class representing an OCCI model. Can contain instances of classes Kind,
+ * Mixin and Action.
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class Model {
+
+ private final SetCover<Kind> kinds = new SetCover<>();
+ private final SetCover<Mixin> mixins = new SetCover<>();
+ private final SetCover<Action> actions = new SetCover<>();
+
+ /**
+ * Creates an empty model.
+ */
+ public Model() {
+ }
+
+ /**
+ * Checks whether model contains a kind
+ *
+ * @param kind kind looked up in the model
+ * @return true if model contains the kind, false otherwise
+ */
+ public boolean containsKind(Kind kind) {
+ return kinds.contains(kind);
+ }
+
+ /**
+ * Checks whether model contains a kind specified by the identifier
+ *
+ * @param kindIdentifier identifier for the kind looked up in the model
+ * @return true if model contains the kind, false otherwise
+ */
+ public boolean containsKind(String kindIdentifier) {
+ return kinds.contains(kindIdentifier);
+ }
+
+ /**
+ * Adds kind to the model.
+ *
+ * @param kind kind to be added to the model
+ * @return true if the addition was successful, false otherwise
+ */
+ public boolean addKind(Kind kind) {
+ return kinds.add(kind);
+ }
+
+ /**
+ * Retrieves a kind from the model.
+ *
+ * @param kindIdentifier identifier of the kind to be retrieved
+ * @return kind instance from the mdoel
+ */
+ public Kind getKind(String kindIdentifier) {
+ return kinds.get(kindIdentifier);
+ }
+
+ /**
+ * Removes kind from model.
+ *
+ * @param kind kind to be removed from the model
+ * @return true if the removal was successful, false otherwise
+ */
+ public boolean removeKind(Kind kind) {
+ return kinds.remove(kind);
+ }
+
+ /**
+ * Remove all kinds from the model.
+ */
+ public void clearKinds() {
+ kinds.clear();
+ }
+
+ /**
+ * Returns all kinds from the model in a form of set.
+ *
+ * @return set of all kinds from the model
+ */
+ public Set<Kind> getKinds() {
+ return kinds.getSet();
+ }
+
+ /**
+ * Checks whether model contains a mixin
+ *
+ * @param mixin mixin looked up in the model
+ * @return true if model contains the mixin, false otherwise
+ */
+ public boolean containsMixin(Mixin mixin) {
+ return mixins.contains(mixin);
+ }
+
+ /**
+ * Checks whether model contains a mixin specified by the identifier
+ *
+ * @param mixinIdentifier identifier for the mixin looked up in the model
+ * @return true if model contains the mixin, false otherwise
+ */
+ public boolean containsMixin(String mixinIdentifier) {
+ return mixins.contains(mixinIdentifier);
+ }
+
+ /**
+ * Adds mixin to the model.
+ *
+ * @param mixin mixin to be added to the model
+ * @return true if the addition was successful, false otherwise
+ */
+ public boolean addMixin(Mixin mixin) {
+ return mixins.add(mixin);
+ }
+
+ /**
+ * Retrieves a mixin from the model.
+ *
+ * @param mixinIdentifier identifier of the mixin to be retrieved
+ * @return mixin instance from the mdoel
+ */
+ public Mixin getMixin(String mixinIdentifier) {
+ return mixins.get(mixinIdentifier);
+ }
+
+ /**
+ * Removes mixin from model.
+ *
+ * @param mixin mixin to be removed from the model
+ * @return true if the removal was successful, false otherwise
+ */
+ public boolean removeMixin(Mixin mixin) {
+ return mixins.remove(mixin);
+ }
+
+ /**
+ * Remove all mixins from the model.
+ */
+ public void clearMixins() {
+ mixins.clear();
+ }
+
+ /**
+ * Returns all mixins from the model in a form of set.
+ *
+ * @return set of all mixins from the model
+ */
+ public Set<Mixin> getMixins() {
+ return mixins.getSet();
+ }
+
+ /**
+ * Checks whether model contains a action
+ *
+ * @param action action looked up in the model
+ * @return true if model contains the action, false otherwise
+ */
+ public boolean containsAction(Action action) {
+ return actions.contains(action);
+ }
+
+ /**
+ * Checks whether model contains a action specified by the identifier
+ *
+ * @param actionIdentifier identifier for the action looked up in the model
+ * @return true if model contains the action, false otherwise
+ */
+ public boolean containsAction(String actionIdentifier) {
+ return actions.contains(actionIdentifier);
+ }
+
+ /**
+ * Adds action to the model.
+ *
+ * @param action action to be added to the model
+ * @return true if the addition was successful, false otherwise
+ */
+ public boolean addAction(Action action) {
+ return actions.add(action);
+ }
+
+ /**
+ * Retrieves a action from the model.
+ *
+ * @param actionIdentifier identifier of the action to be retrieved
+ * @return action instance from the mdoel
+ */
+ public Action getAction(String actionIdentifier) {
+ return actions.get(actionIdentifier);
+ }
+
+ /**
+ * Removes action from model.
+ *
+ * @param action action to be removed from the model
+ * @return true if the removal was successful, false otherwise
+ */
+ public boolean removeAction(Action action) {
+ return actions.remove(action);
+ }
+
+ /**
+ * Remove all actions from the model.
+ */
+ public void clearActions() {
+ actions.clear();
+ }
+
+ /**
+ * Returns all actions from the model in a form of set.
+ *
+ * @return set of all actions from the model
+ */
+ public Set<Action> getActions() {
+ return actions.getSet();
+ }
+
+ /**
+ * Finds kind with given identifier (schema+term) in model.
+ *
+ * @param identifier
+ * @return Kind instance with given identifier if found, null otherwise
+ */
+ public Kind findKind(URI identifier) {
+ if (identifier == null) {
+ return null;
+ }
+
+ String identifierString = identifier.toString();
+ for (Kind kind : kinds.getSet()) {
+ if (kind.getIdentifier().equals(identifierString)) {
+ return kind;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Finds kind with given term in model.
+ *
+ * @param term
+ * @return Kind instance with given term if found, null otherwise
+ * @throws AmbiguousIdentifierException if model contains more than one kind
+ * with given term
+ */
+ public Kind findKind(String term) throws AmbiguousIdentifierException {
+ Kind foundKind = null;
+ for (Kind kind : kinds.getSet()) {
+ if (kind.getTerm().equals(term)) {
+ if (foundKind != null) {
+ throw new AmbiguousIdentifierException("term '" + term + "' is ambiguous");
+ }
+ foundKind = kind;
+ }
+ }
+
+ return foundKind;
+ }
+
+ /**
+ * Finds kinds related to kind specified by given identifier.
+ *
+ * @param identifier
+ * @return list of Kinds related to the one specified Kind
+ */
+ public List<Kind> findRelatedKinds(URI identifier) {
+ Kind main = findKind(identifier);
+ return getRelatedKinds(main);
+ }
+
+ /**
+ * Finds kinds related to kind specified by given term.
+ *
+ * @param term
+ * @return list of Kinds related to the one specified Kind
+ * @throws AmbiguousIdentifierException if model contains more than one kind
+ * with given term
+ */
+ public List<Kind> findRelatedKinds(String term) throws AmbiguousIdentifierException {
+ Kind main = findKind(term);
+ return getRelatedKinds(main);
+ }
+
+ private List<Kind> getRelatedKinds(Kind main) {
+ List<Kind> related = new ArrayList<>();
+ if (main == null) {
+ return related;
+ }
+
+ for (Kind kind : kinds.getSet()) {
+ if (kind.relatesTo(main)) {
+ related.add(kind);
+ }
+ }
+
+ return related;
+ }
+
+ /**
+ * Determines CollectionType for given kind (for parsing purposes).
+ *
+ * @param kind
+ * @return CollectionType instance if determined, null otherwise
+ */
+ public CollectionType findKindType(Kind kind) {
+ while (kind != null) {
+ if (kind.getIdentifier().equals(Resource.KIND_IDENTIFIER_DEFAULT)) {
+ return CollectionType.RESOURCE;
+ }
+ if (kind.getIdentifier().equals(Link.KIND_IDENTIFIER_DEFAULT)) {
+ return CollectionType.LINK;
+ }
+ kind = kind.getParentKind();
+ }
+
+ return null;
+ }
+
+ /**
+ * Determines CollectionType for kind with given location (for parsing
+ * purposes).
+ *
+ * @param location
+ * @return CollectionType instance if determined, null otherwise
+ */
+ public CollectionType findKindType(String location) {
+ Kind kind = null;
+ for (Kind k : kinds.getSet()) {
+ if (k.getLocation().getPath().equals(location)) {
+ kind = k;
+ break;
+ }
+ }
+
+ return findKindType(kind);
+ }
+
+ //TODO: refactor findMixin methods
+ /**
+ * Finds mixin with given identifier (schema+term) in model.
+ *
+ * @param identifier
+ * @return Mixin instance with given identifier if found, null otherwise
+ */
+ public Mixin findMixin(URI identifier) {
+ if (identifier == null) {
+ return null;
+ }
+
+ String identigfierString = identifier.toString();
+ for (Mixin mixin : mixins.getSet()) {
+ if (mixin.getIdentifier().equals(identigfierString)) {
+ return mixin;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Finds mixin with given term in model.
+ *
+ * @param term
+ * @return Mixin instance with given term if found, null otherwise
+ * @throws AmbiguousIdentifierException if model contains more than one
+ * mixin with given term
+ */
+ public Mixin findMixin(String term) throws AmbiguousIdentifierException {
+ Mixin foundMixin = null;
+ for (Mixin mixin : mixins.getSet()) {
+ if (mixin.getTerm().equals(term)) {
+ if (foundMixin != null) {
+ throw new AmbiguousIdentifierException("term '" + term + "' is ambiguous");
+ }
+ foundMixin = mixin;
+ }
+ }
+
+ return foundMixin;
+ }
+
+ /**
+ * Finds mixin with given term and relation in model.
+ *
+ * @param term
+ * @param rel term of related mixin
+ * @return Mixin instance with given term and relation if found, null
+ * otherwise
+ * @throws AmbiguousIdentifierException if model contains more than one
+ * mixin with given term
+ */
+ public Mixin findMixin(String term, String rel) throws AmbiguousIdentifierException {
+ Mixin relMixin = findMixin(rel);
+ if (relMixin == null) {
+ return null;
+ }
+
+ Mixin foundMixin = null;
+ for (Mixin mixin : mixins.getSet()) {
+ if (mixin.getTerm().equals(term) && mixin.relatesTo(relMixin)) {
+ if (foundMixin != null) {
+ throw new AmbiguousIdentifierException("term '" + term + "' is ambiguous");
+ }
+ foundMixin = mixin;
+ }
+ }
+
+ return foundMixin;
+ }
+
+ /**
+ * Finds mixin with given term and relation in model.
+ *
+ * @param term
+ * @param rel identifier of related mixin (scheme+term)
+ * @return Mixin instance with given term and relation if found, null
+ * otherwise
+ * @throws AmbiguousIdentifierException if model contains more than one
+ * mixin with given term
+ */
+ public Mixin findMixin(String term, URI rel) throws AmbiguousIdentifierException {
+ if (rel == null) {
+ return null;
+ }
+
+ Mixin foundMixin = null;
+ for (Mixin mixin : mixins.getSet()) {
+ if (mixin.getTerm().equals(term) && mixin.relatesTo(rel.toString())) {
+ if (foundMixin != null) {
+ throw new AmbiguousIdentifierException("term '" + term + "' is ambiguous");
+ }
+ foundMixin = mixin;
+ }
+ }
+
+ return foundMixin;
+ }
+
+ /**
+ * Finds mixins related to mixin specified by given identifier.
+ *
+ * @param identifier
+ * @return list of Mixins related to the one specified Mixin
+ */
+ public List<Mixin> findRelatedMixins(URI identifier) {
+ Mixin main = findMixin(identifier);
+ return getRelatedMixins(main);
+ }
+
+ /**
+ * Finds mixins related to mixin specified by given term.
+ *
+ * @param term
+ * @return list of Mixins related to the one specified Mixin
+ * @throws AmbiguousIdentifierException if model contains more than one
+ * mixin with given term
+ */
+ public List<Mixin> findRelatedMixins(String term) throws AmbiguousIdentifierException {
+ Mixin main = findMixin(term);
+ return getRelatedMixins(main);
+ }
+
+ private List<Mixin> getRelatedMixins(Mixin main) {
+ List<Mixin> related = new ArrayList<>();
+ if (main == null) {
+ return related;
+ }
+
+ for (Mixin mixin : mixins.getSet()) {
+ if (mixin.relatesTo(main)) {
+ related.add(mixin);
+ }
+ }
+
+ return related;
+ }
+
+ /**
+ * Finds action with given term in model.
+ *
+ * @param term
+ * @return Action instance with given term if found, null otherwise
+ * @throws AmbiguousIdentifierException if model contains more than one
+ * action with given term
+ */
+ public Action findAction(String term) throws AmbiguousIdentifierException {
+ Action foundAction = null;
+ for (Action action : actions.getSet()) {
+ if (action.getTerm().equals(term)) {
+ if (foundAction != null) {
+ throw new AmbiguousIdentifierException("term '" + term + "' is ambiguous");
+ }
+ foundAction = action;
+ }
+ }
+
+ return foundAction;
+ }
+
+ /**
+ * Finds action with given identifier (schema+term) in model.
+ *
+ * @param identifier
+ * @return Action instance with given identifier if found, null otherwise
+ */
+ public Action findAction(URI identifier) {
+ if (identifier == null) {
+ return null;
+ }
+
+ String identigfierString = identifier.toString();
+ for (Action action : actions.getSet()) {
+ if (action.getIdentifier().equals(identigfierString)) {
+ return action;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * @see Object#hashCode()
+ * @return model's hash code
+ */
+ @Override
+ public int hashCode() {
+ int hash = 3;
+ hash = 59 * hash + Objects.hashCode(this.kinds);
+ hash = 59 * hash + Objects.hashCode(this.mixins);
+ hash = 59 * hash + Objects.hashCode(this.actions);
+ return hash;
+ }
+
+ /**
+ * @see Object#equals(java.lang.Object)
+ * @param obj object to compare model with
+ * @return true if two models are equal, false otherwise
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final Model other = (Model) obj;
+ if (!Objects.equals(this.kinds, other.kinds)) {
+ return false;
+ }
+ if (!Objects.equals(this.mixins, other.mixins)) {
+ return false;
+ }
+ if (!Objects.equals(this.actions, other.actions)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Resturns string representation of the model
+ *
+ * @see Object#toString()
+ * @return string representation of the model
+ */
+ @Override
+ public String toString() {
+ return "Model{" + "kinds=" + kinds + ", mixins=" + mixins + ", actions=" + actions + '}';
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.collection;
+
+import com.sun.net.httpserver.Headers;
+import cz.cesnet.cloud.occi.core.Attribute;
+import cz.cesnet.cloud.occi.parser.TextParser;
+import cz.cesnet.cloud.occi.renderer.TextRenderer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Class representing attributes and their values.
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class AttributeMapCover {
+
+ private final Map<Attribute, String> attributes = new HashMap<>();
+
+ /**
+ * Stores attribute and its value.
+ *
+ * @param attribute attribute to be stored. Cannot be null.
+ * @param value value to be stored for the attribute. Cannot be null.
+ */
+ public void add(Attribute attribute, String value) {
+ if (attribute == null) {
+ throw new NullPointerException("Cannot add null attribute.");
+ }
+ if (value == null) {
+ throw new NullPointerException("Cannot add null value.");
+ }
+
+ attributes.put(attribute, value);
+ }
+
+ /**
+ * Removes attribute from the collection.
+ *
+ * @param attribute attribute to be removed. Cannot be null.
+ */
+ public void remove(Attribute attribute) {
+ if (attribute == null) {
+ throw new NullPointerException("Cannot remove null attribute.");
+ }
+
+ attributes.remove(attribute);
+ }
+
+ /**
+ * Removes attribute from the collection.
+ *
+ * @param attributeName name of the attribute to be removed. Cannot be null.
+ */
+ public void remove(String attributeName) {
+ Attribute attTmp = new Attribute(attributeName);
+ attributes.remove(attTmp);
+ }
+
+ /**
+ * Checks whether collection contains the attribute.
+ *
+ * @param attribute attribute to be looked up in the collection
+ * @return true if collection contains the attribute, false otherwise
+ */
+ public boolean containsAttribute(Attribute attribute) {
+ return attributes.containsKey(attribute);
+ }
+
+ /**
+ * Checks whether collection contains the attribute.
+ *
+ * @param attributeName name of the attribute to be looked up in the
+ * collection. Cannot be null.
+ * @return true if collection contains the attribute, false otherwise
+ */
+ public boolean containsAttribute(String attributeName) {
+ Attribute attTmp = new Attribute(attributeName);
+ return containsAttribute(attTmp);
+ }
+
+ /**
+ * Returns the value for the given attribute.
+ *
+ * @param attribute attribute of which value is returned.
+ * @return value for the given attribute
+ */
+ public String getValue(Attribute attribute) {
+ return attributes.get(attribute);
+ }
+
+ /**
+ * Returns the value for the given attribute.
+ *
+ * @param attributeName name of the attribute of which value is returned.
+ * Cannot be null.
+ * @return value for the given attribute
+ */
+ public String getValue(String attributeName) {
+ Attribute attTmp = new Attribute(attributeName);
+ return getValue(attTmp);
+ }
+
+ /**
+ * Returns all the attributes and their values in form of map.
+ *
+ * @return all the attributes and their values in form of map
+ */
+ public Map<Attribute, String> getAttributes() {
+ return Collections.unmodifiableMap(attributes);
+ }
+
+ /**
+ * Removes all attributes and their values from the collection.
+ */
+ public void clear() {
+ attributes.clear();
+ }
+
+ /**
+ * Returns the number of attributes in the collection.
+ *
+ * @return the number of attributes in the collection
+ */
+ public int size() {
+ return attributes.size();
+ }
+
+ /**
+ * @see Object#hashCode()
+ * @return collection's hash code
+ */
+ @Override
+ public int hashCode() {
+ int hash = 5;
+ hash = 83 * hash + Objects.hashCode(this.attributes);
+ return hash;
+ }
+
+ /**
+ * @see Object#equals(java.lang.Object)
+ * @param obj object to compare collection with
+ * @return true if two collections are equal, false otherwise
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final AttributeMapCover other = (AttributeMapCover) obj;
+ if (!Objects.equals(this.attributes, other.attributes)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Resturns string representation of the collection
+ *
+ * @see Object#toString()
+ * @return string representation of the collection
+ */
+ @Override
+ public String toString() {
+ return "AttributeMapCover{" + attributes + '}';
+ }
+
+ /**
+ * Generates a list of strings from attributes and their values
+ *
+ * @return attributes and their values in form of list of strings
+ */
+ private List<String> toList() {
+ List<String> list = new ArrayList<>();
+ List<Attribute> attributeList = new ArrayList<>(attributes.keySet());
+ Collections.sort(attributeList);
+ for (Attribute attribute : attributeList) {
+ String name = attribute.getName();
+ StringBuilder sb = new StringBuilder(name);
+ String value = attributes.get(attribute);
+ if (value.matches(TextParser.REGEXP_NUMBER)) {
+ sb.append(TextRenderer.surroundString(value, "=", ""));
+ } else {
+ sb.append(TextRenderer.surroundString(value, "=\"", "\""));
+ }
+ list.add(sb.toString());
+ }
+
+ Collections.sort(list);
+ return list;
+ }
+
+ /**
+ * Returns a text representation of OCCI attributes with prefix.
+ *
+ * @return text representation of OCCI attributes with prefix
+ */
+ public String toPrefixText() {
+ String prefix = "X-OCCI-Attribute: ";
+ StringBuilder sb = new StringBuilder();
+
+ for (String s : toList()) {
+ sb.append(prefix);
+ sb.append(s);
+ sb.append("\n");
+ }
+
+ if (!sb.toString().isEmpty()) {
+ sb.deleteCharAt(sb.length() - 1);
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Returns an occi text representation of OCCI attributes in form of
+ * headers.
+ *
+ * @return occi text representation of OCCI attributes in form of headers
+ */
+ public Headers toHeaders() {
+ Headers headers = new Headers();
+
+ for (String s : toList()) {
+ headers.add("X-OCCI-Attribute", s);
+ }
+
+ return headers;
+ }
+
+ /**
+ * Returns text representation of OCCI attributes in one line.
+ *
+ * @return text representation of OCCI attributes in one line
+ */
+ public String toOneLineText() {
+ StringBuilder sb = new StringBuilder();
+
+ for (String s : toList()) {
+
+ sb.append(s);
+ sb.append(";");
+ }
+
+ return sb.toString();
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.collection;
+
+import cz.cesnet.cloud.occi.type.Identifiable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Objects;
+
+/**
+ * Collection class serving as a set for all classes identifiable.
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ * @param <E>
+ */
+public class SetCover<E extends Identifiable> {
+
+ private final Set<E> set = new HashSet<>();
+
+ /**
+ * Checks whether set contains the element.
+ *
+ * @param element looked up in the set
+ * @return true if set contains the element, false otherwise
+ */
+ public boolean contains(E element) {
+ return set.contains(element);
+ }
+
+ /**
+ * Checks whether set contains an element specified by the identifier.
+ *
+ * @param elementIdentifier identifier of the element looked up in the set
+ * @return true if set contains the element, false otherwise
+ */
+ public boolean contains(String elementIdentifier) {
+ for (E element : set) {
+ if (element.getIdentifier().equals(elementIdentifier)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Adds element to the set.
+ *
+ * @param element element to be added. Cannot be null.
+ * @return true if the addition was successful, false otherwise
+ */
+ public boolean add(E element) {
+ if (element == null) {
+ throw new NullPointerException("Cannot add null element.");
+ }
+
+ return set.add(element);
+ }
+
+ /**
+ * Adds all elements from the collection to the set.
+ *
+ * @param elements collection of elements to be added. Cannot contain any
+ * null elements.
+ * @return true if the addition was successful, false otherwise
+ */
+ public boolean addAll(Collection<E> elements) {
+ if (elements.contains(null)) {
+ throw new NullPointerException("Cannot add null element.");
+ }
+
+ return set.addAll(elements);
+ }
+
+ /**
+ * Retrieves element rom the set.
+ *
+ * @param elementIdentifier identifier of the element to be retrieved
+ * @return element specified by its identifier if in set, null otherwise
+ */
+ public E get(String elementIdentifier) {
+ if (!contains(elementIdentifier)) {
+ return null;
+ }
+
+ return find(elementIdentifier);
+ }
+
+ /**
+ * Removes element from the set
+ *
+ * @param element element to be remoed from the set. Cannot be null.
+ * @return true if the deletion was successful, false otherwise
+ */
+ public boolean remove(E element) {
+ if (element == null) {
+ throw new NullPointerException("Cannot remove null element.");
+ }
+
+ return set.remove(element);
+ }
+
+ private E find(String elementIdentifier) {
+ for (E element : set) {
+ if (element.getIdentifier().equals(elementIdentifier)) {
+ return element;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Removes all the elements from the set.
+ */
+ public void clear() {
+ set.clear();
+ }
+
+ /**
+ * Returns unmodifiable set of elements.
+ *
+ * @return unmodifiable set of elements
+ */
+ public Set<E> getSet() {
+ return getSet(false);
+ }
+
+ /**
+ * Returns set of elements.
+ *
+ * @param modifiable specifies if the set will be modifiable or not
+ * @return set of elements
+ */
+ public Set<E> getSet(boolean modifiable) {
+ if (modifiable) {
+ return set;
+ } else {
+ return Collections.unmodifiableSet(set);
+ }
+ }
+
+ /**
+ * Returns number of elements in the set.
+ *
+ * @return number of elements in the set
+ */
+ public int size() {
+ return set.size();
+ }
+
+ /**
+ * @see Object#hashCode()
+ * @return set's hash code
+ */
+ @Override
+ public int hashCode() {
+ int hash = 7;
+ hash = 53 * hash + Objects.hashCode(this.set);
+ return hash;
+ }
+
+ /**
+ * @see Object#equals(java.lang.Object)
+ * @param obj object to compare set with
+ * @return true if two sets are equal, false otherwise
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final SetCover<?> other = (SetCover<?>) obj;
+ if (!Objects.equals(this.set, other.set)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Resturns string representation of the set
+ *
+ * @see Object#toString()
+ * @return string representation of the set
+ */
+ @Override
+ public String toString() {
+ return "SetCover{" + set + '}';
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.core;
+
+import com.sun.net.httpserver.Headers;
+import cz.cesnet.cloud.occi.renderer.TextRenderer;
+import cz.cesnet.cloud.occi.type.Identifiable;
+import java.net.URI;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.Set;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class representing an OCCI Action structure.
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class Action implements Identifiable, Comparable<Action> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Action.class);
+ private Category category;
+
+ /**
+ * Constructor. Creates an Action instance with given scheme, term, title
+ * and set of attributes.
+ *
+ * @param scheme action's scheme. Cannot be null.
+ * @param term action's term. Cannot be null nor empty.
+ * @param title action's title
+ * @param attributes set of action's attributes
+ */
+ public Action(URI scheme, String term, String title, Collection<Attribute> attributes) {
+ LOGGER.debug("Creating action: scheme={}, term={}, title={}, attributes={}", scheme, term, title, attributes);
+ this.category = new Category(scheme, term, title, null, attributes);
+ }
+
+ /**
+ * Constructor. Creates an Action instance with given scheme and term.
+ *
+ * @param scheme action's scheme. Cannot be null.
+ * @param term action's term. Cannot be null nor empty.
+ */
+ public Action(URI scheme, String term) {
+ this(scheme, term, null, null);
+ }
+
+ /**
+ * Returns action's scheme.
+ *
+ * @return action's scheme.
+ */
+ public URI getScheme() {
+ return category.getScheme();
+ }
+
+ /**
+ * Sets action's scheme.
+ *
+ * @param scheme action's scheme. Cannot be null.
+ */
+ public void setScheme(URI scheme) {
+ category.setScheme(scheme);
+ }
+
+ /**
+ * Returns action's term.
+ *
+ * @return action's term.
+ */
+ public String getTerm() {
+ return category.getTerm();
+ }
+
+ /**
+ * Sets action's term.
+ *
+ * @param term action's term. Cannot be null nor empty.
+ */
+ public void setTerm(String term) {
+ category.setTerm(term);
+ }
+
+ /**
+ * Returns action's identifier.
+ *
+ * @return action's identifier
+ */
+ @Override
+ public String getIdentifier() {
+ return category.getIdentifier();
+ }
+
+ /**
+ * Returns action's title.
+ *
+ * @return action's title
+ */
+ public String getTitle() {
+ return category.getTitle();
+ }
+
+ /**
+ * Sets action's title.
+ *
+ * @param title action's title
+ */
+ public void setTitle(String title) {
+ category.setTitle(title);
+ }
+
+ /**
+ * Checks whether action has the attribute.
+ *
+ * @param attribute attribute to be looked up
+ * @return true if action has the attribute, false otherwise
+ */
+ public boolean containsAttribute(Attribute attribute) {
+ return category.containsAttribute(attribute);
+ }
+
+ /**
+ * Checks whether action has the attribute.
+ *
+ * @param attributeName name of the attribute to be looked up
+ * @return true if action has the attribute, false otherwise
+ */
+ public boolean containsAttribute(String attributeName) {
+ return category.containsAttribute(attributeName);
+ }
+
+ /**
+ * Adds attribute to the action.
+ *
+ * @param attribute attribute to be added
+ * @return true if the addition was successful, false otherwise
+ */
+ public boolean addAttribute(Attribute attribute) {
+ return category.addAttribute(attribute);
+ }
+
+ /**
+ * Retrieves an attribute from the action.
+ *
+ * @param attributeName name of the attribute to be retrieved
+ * @return attribute
+ */
+ public Attribute getAttribute(String attributeName) {
+ return category.getAttribute(attributeName);
+ }
+
+ /**
+ * Removes attribute from the action.
+ *
+ * @param attribute attribute to be removed
+ * @return true if the removal was successful, false otherwise
+ */
+ public boolean removeAttribute(Attribute attribute) {
+ return category.removeAttribute(attribute);
+ }
+
+ /**
+ * Returns all action's attribute in form of set.
+ *
+ * @return all action's attribute in form of set
+ */
+ public Set<Attribute> getAttributes() {
+ return category.getAttributes();
+ }
+
+ /**
+ * Returns action's default scheme 'http://schemas.ogf.org/occi/core#'
+ *
+ * @return action's default scheme
+ */
+ public URI getSchemeDefault() {
+ return Category.SCHEME_CORE_DEFAULT;
+ }
+
+ /**
+ * Returns action's default term 'term'
+ *
+ * @return action's default term
+ */
+ public String getTermDefault() {
+ return "action";
+ }
+
+ /**
+ * @see Object#hashCode()
+ * @return action's hash code
+ */
+ @Override
+ public int hashCode() {
+ int hash = 7;
+ hash = 29 * hash + Objects.hashCode(this.category);
+ return hash;
+ }
+
+ /**
+ * @see Object#equals(java.lang.Object)
+ * @param obj object to compare action with
+ * @return true if two actions are equal, false otherwise
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final Action other = (Action) obj;
+ if (!Objects.equals(this.category, other.category)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Resturns string representation of the action
+ *
+ * @see Object#toString()
+ * @return string representation of the action
+ */
+ @Override
+ public String toString() {
+ return "Action{" + "category=" + category + '}';
+ }
+
+ /**
+ * Returns a text representation of action link as described in OCCI
+ * standard.
+ *
+ * @param resourceLocation
+ * @return text representation of action link
+ */
+ public String toText(String resourceLocation) {
+ StringBuilder sb = new StringBuilder("Link: ");
+ sb.append(textBody(resourceLocation));
+
+ return sb.toString();
+ }
+
+ /**
+ * Returns an occi text representation of action link as described in OCCI
+ * standard in form of headers.
+ *
+ * @param resourceLocation
+ * @return text representation of action link
+ */
+ public Headers toHeaders(String resourceLocation) {
+ Headers headers = new Headers();
+ headers.add("Link", textBody(resourceLocation));
+
+ return headers;
+ }
+
+ private String textBody(String resourceLocation) {
+ StringBuilder sb = new StringBuilder("");
+
+ String descriptor = resourceLocation + "?action=" + getTerm();
+ sb.append(TextRenderer.surroundString(descriptor, "<", ">;"));
+
+ sb.append("rel");
+ sb.append(TextRenderer.surroundString(getScheme().toString() + getTerm()));
+
+ return sb.toString();
+ }
+
+ /**
+ * Comapres two actions lexicographically based on their identifier.
+ *
+ * @see Comparable#compareTo(java.lang.Object)
+ */
+ @Override
+ public int compareTo(Action a) {
+ return getIdentifier().compareTo(a.getIdentifier());
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.core;
+
+import com.sun.net.httpserver.Headers;
+import cz.cesnet.cloud.occi.Model;
+import cz.cesnet.cloud.occi.collection.AttributeMapCover;
+import cz.cesnet.cloud.occi.renderer.TextRenderer;
+import cz.cesnet.cloud.occi.type.Identifiable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class representing an instance of Action
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class ActionInstance implements Identifiable, Comparable<ActionInstance> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(ActionInstance.class);
+ private final AttributeMapCover attributes = new AttributeMapCover();
+ private Action action;
+ private Model model;
+
+ /**
+ * Constructor. Creates an instance of ActionInstance with given Action.
+ *
+ * @param action action to create instance of. Cannot be null.
+ */
+ public ActionInstance(Action action) {
+ LOGGER.debug("Creating ActionInstance: action={}", action);
+
+ if (action == null) {
+ throw new NullPointerException("ActionInstance action cannot be null.");
+ }
+
+ this.action = action;
+ }
+
+ /**
+ * Returns action of this instance.
+ *
+ * @return action of this instance
+ */
+ public Action getAction() {
+ return action;
+ }
+
+ /**
+ * Sets action for this instance.
+ *
+ * @param action action for this instance. Cannot be null.
+ */
+ public void setAction(Action action) {
+ if (action == null) {
+ throw new NullPointerException("ActionInstance action cannot be null.");
+ }
+
+ this.action = action;
+ }
+
+ /**
+ * Returns action's identifier.
+ *
+ * @return action's identifier
+ */
+ @Override
+ public String getIdentifier() {
+ return action.getIdentifier();
+ }
+
+ /**
+ * Returns instance's model.
+ *
+ * @return instance's model
+ */
+ public Model getModel() {
+ return model;
+ }
+
+ /**
+ * Sets model for the instance.
+ *
+ * @param model model for the instance
+ */
+ public void setModel(Model model) {
+ this.model = model;
+ }
+
+ /**
+ * Adds attribute and its value for the instance.
+ *
+ * @param attribute attribute to be added
+ * @param value value of the attribute to be added
+ */
+ public void addAttribute(Attribute attribute, String value) {
+ attributes.add(attribute, value);
+ }
+
+ /**
+ * Adds all attributes and their values from the given map.
+ *
+ * @param attributes map of attributes and their values
+ */
+ public void addAttributes(Map<String, String> attributes) {
+ for (String name : attributes.keySet()) {
+ addAttribute(new Attribute(name), attributes.get(name));
+ }
+ }
+
+ /**
+ * Removes attribute and its value from the instance.
+ *
+ * @param attribute attribute to be removed
+ */
+ public void removeAttribute(Attribute attribute) {
+ attributes.remove(attribute);
+ }
+
+ /**
+ * Checks whether the instance has an attribute.
+ *
+ * @param attribute attribute to be looked up
+ * @return true if instance has the attribute, false otherwise
+ */
+ public boolean containsAttribute(Attribute attribute) {
+ return attributes.containsAttribute(attribute);
+ }
+
+ /**
+ * Checks whether the instance has an attribute.
+ *
+ * @param attributeName name of the attribute to be looked up
+ * @return true if instance has the attribute, false otherwise
+ */
+ public boolean containsAttribute(String attributeName) {
+ return attributes.containsAttribute(attributeName);
+ }
+
+ /**
+ * Returns value of the given attribute.
+ *
+ * @param attribute attribute which value is returned
+ * @return value of the given attribute
+ */
+ public String getValue(Attribute attribute) {
+ return attributes.getValue(attribute);
+ }
+
+ /**
+ * Returns value of the given attribute.
+ *
+ * @param attributeName name of the attribute which value is returned
+ * @return value of the given attribute
+ */
+ public String getValue(String attributeName) {
+ return attributes.getValue(attributeName);
+ }
+
+ /**
+ * Returns all instance's attributes and their values in form of map.
+ *
+ * @return all instance's attributes and their values in form of map
+ */
+ public Map<Attribute, String> getAttributes() {
+ return attributes.getAttributes();
+ }
+
+ /**
+ * Removes all attributes with their values from the instance.
+ */
+ public void clearAttributes() {
+ attributes.clear();
+ }
+
+ /**
+ * Returns a plain text representation of action instance as described in
+ * OCCI standard.
+ *
+ * @return text representation of action instance
+ */
+ public String toText() {
+ StringBuilder sb = new StringBuilder("Category: ");
+ sb.append(textBody());
+
+ String attributesString = attributes.toPrefixText();
+ if (!attributesString.isEmpty()) {
+ sb.append("\n");
+ sb.append(attributesString);
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Returns an occi text representation of action instance as described in
+ * OCCI standard in form of headers.
+ *
+ * @return occi text representation of action instance in form of headers
+ */
+ public Headers toHeaders() {
+ Headers headers = new Headers();
+ headers.add("Category", textBody());
+
+ Headers attributesHeaders = attributes.toHeaders();
+ if (!attributesHeaders.isEmpty()) {
+ headers.putAll(attributesHeaders);
+ }
+
+ return headers;
+ }
+
+ private String textBody() {
+ StringBuilder sb = new StringBuilder(action.getTerm());
+ sb.append(";");
+ sb.append("scheme");
+ sb.append(TextRenderer.surroundString(action.getScheme().toString()));
+ sb.append("class");
+ sb.append(TextRenderer.surroundString(action.getClass().getSimpleName().toLowerCase()));
+
+ String title = action.getTitle();
+ if (title != null && !title.isEmpty()) {
+ sb.append("title");
+ sb.append(TextRenderer.surroundString(title));
+ }
+
+ Set<Attribute> actionAttributes = action.getAttributes();
+ if (actionAttributes != null && !actionAttributes.isEmpty()) {
+ sb.append("attributes");
+ StringBuilder attrSB = new StringBuilder();
+ List<Attribute> attributeList = new ArrayList<>(actionAttributes);
+ Collections.sort(attributeList);
+ for (Attribute attribute : attributeList) {
+ attrSB.append(attribute.toText());
+ attrSB.append(" ");
+ }
+ attrSB.deleteCharAt(attrSB.length() - 1);
+ sb.append(TextRenderer.surroundString(attrSB.toString()));
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * @see Object#hashCode()
+ * @return instance's hash code
+ */
+ @Override
+ public int hashCode() {
+ int hash = 7;
+ hash = 41 * hash + Objects.hashCode(this.attributes);
+ hash = 41 * hash + Objects.hashCode(this.action);
+ return hash;
+ }
+
+ /**
+ * @see Object#equals(java.lang.Object)
+ * @param obj object to compare instance with
+ * @return true if two instances are equal, false otherwise
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final ActionInstance other = (ActionInstance) obj;
+ if (!Objects.equals(this.attributes, other.attributes)) {
+ return false;
+ }
+ if (!Objects.equals(this.action, other.action)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Resturns string representation of the instance
+ *
+ * @see Object#toString()
+ * @return string representation of the instance
+ */
+ @Override
+ public String toString() {
+ return "ActionInstance{" + "attributes=" + attributes + ", action=" + action + '}';
+ }
+
+ /**
+ * Comapres two instances lexicographically based on their actions.
+ *
+ * @see Comparable#compareTo(java.lang.Object)
+ */
+ @Override
+ public int compareTo(ActionInstance a) {
+ return getIdentifier().compareTo(a.getIdentifier());
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.core;
+
+import cz.cesnet.cloud.occi.renderer.TextRenderer;
+import cz.cesnet.cloud.occi.type.Identifiable;
+import java.util.Objects;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class representing an OCCI attribute. Attributes are used to store properties
+ * of OCCI classes.
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class Attribute implements Identifiable, Comparable<Attribute> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Attribute.class);
+ private String name;
+ private boolean required;
+ private boolean immutable;
+ private String type;
+ private String pattern;
+ private String defaultValue;
+ private String description;
+
+ /**
+ * Constructor.
+ *
+ * @param name name of the attribute. Cannot be null nor empty.
+ * @param required whether attribute is required or not
+ * @param immutable whether attribute is immutable or not
+ * @param type attribute's type
+ * @param pattern attribute's pattern
+ * @param defaultValue attribute's default value
+ * @param description attribute's description
+ */
+ public Attribute(String name, boolean required, boolean immutable, String type, String pattern, String defaultValue, String description) {
+ LOGGER.debug("Creating attribute: name={}, required={}, immutable={}, type={}, pattern={}, defaultValue={}, description={}",
+ name, required, immutable, type, pattern, defaultValue, description);
+
+ if (name == null) {
+ throw new NullPointerException("Attribute name cannot be null.");
+ }
+ if (name.isEmpty()) {
+ throw new IllegalArgumentException("Attribute name cannot be empty.");
+ }
+
+ this.name = name;
+ this.required = required;
+ this.immutable = immutable;
+ this.type = type;
+ this.pattern = pattern == null ? ".*" : pattern;
+ this.defaultValue = defaultValue;
+ this.description = description;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param name name of the attribute. Cannot be null nor empty.
+ * @param required whether attribute is required or not
+ * @param immutable whether attribute is immutable or not
+ */
+ public Attribute(String name, boolean required, boolean immutable) {
+ this(name, required, immutable, null, null, null, null);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param name name of the attribute. Cannot be null nor empty.
+ */
+ public Attribute(String name) {
+ this(name, false, false, null, null, null, null);
+ }
+
+ /**
+ * Returns attribute's name.
+ *
+ * @return attribute's name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets attribute's name.
+ *
+ * @param name attribute's name. Cannot be null nor empty
+ */
+ public void setName(String name) {
+ if (name == null) {
+ throw new NullPointerException("Attribute name cannot be null.");
+ }
+ if (name.isEmpty()) {
+ throw new IllegalArgumentException("Attribute name cannot be empty.");
+ }
+
+ this.name = name;
+ }
+
+ /**
+ * Returns attribute's identifier.
+ *
+ * @return attribute's identifier
+ */
+ @Override
+ public String getIdentifier() {
+ return getName();
+ }
+
+ /**
+ * Returns whether atttribute is required.
+ *
+ * @return true if attribute is required, false otherwise
+ */
+ public boolean isRequired() {
+ return required;
+ }
+
+ /**
+ * Sets attribute's requiredness.
+ *
+ * @param required whether the attribute should be required or not
+ */
+ public void setRequired(boolean required) {
+ this.required = required;
+ }
+
+ /**
+ * Returns whether atttribute is immutable.
+ *
+ * @return true if attribute is immutable, false otherwise
+ */
+ public boolean isImmutable() {
+ return immutable;
+ }
+
+ /**
+ * Sets attribute's immutability.
+ *
+ * @param immutable whether the attribute should be immutable or not
+ */
+ public void setImmutable(boolean immutable) {
+ this.immutable = immutable;
+ }
+
+ /**
+ * Returns attribute's type.
+ *
+ * @return attribute's type
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Sets attribute's type.
+ *
+ * @param type attribute's type
+ */
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ /**
+ * Returns attribute's pattern.
+ *
+ * @return attribute's pattern
+ */
+ public String getPattern() {
+ return pattern;
+ }
+
+ /**
+ * Sets attribute's pattern.
+ *
+ * @param pattern attribute's pattern
+ */
+ public void setPattern(String pattern) {
+ this.pattern = pattern;
+ }
+
+ /**
+ * Returns attribute's default value.
+ *
+ * @return attribute's default value
+ */
+ public String getDefaultValue() {
+ return defaultValue;
+ }
+
+ /**
+ * Sets attribute's default value.
+ *
+ * @param defaultValue attribute's default value
+ */
+ public void setDefaultValue(String defaultValue) {
+ this.defaultValue = defaultValue;
+ }
+
+ /**
+ * Returns attribute's description.
+ *
+ * @return attribute's description
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Sets attribute's description.
+ *
+ * @param description attribute's description
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * @see Object#hashCode()
+ * @return attribute's hash code
+ */
+ @Override
+ public int hashCode() {
+ int hash = 3;
+ hash = 53 * hash + Objects.hashCode(this.name);
+ return hash;
+ }
+
+ /**
+ * @see Object#equals(java.lang.Object)
+ * @param obj object to compare attribute with
+ * @return true if two attributes are equal, false otherwise
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final Attribute other = (Attribute) obj;
+ if (!Objects.equals(this.name, other.name)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Resturns string representation of the attribute
+ *
+ * @see Object#toString()
+ * @return string representation of the attribute
+ */
+ @Override
+ public String toString() {
+ return "Attribute{" + "name=" + name + ", required=" + required + ", immutable=" + immutable + ", type=" + type + ", pattern=" + pattern + ", defaultValue=" + defaultValue + ", description=" + description + '}';
+ }
+
+ /**
+ * Returns plain text representation of the attribute according to OCCI
+ * standard.
+ *
+ * @return plain text representation of the attribute
+ */
+ public String toText() {
+ StringBuilder sb = new StringBuilder(name);
+
+ StringBuilder properties = null;
+ if (required) {
+ properties = new StringBuilder("required");
+ }
+
+ if (immutable) {
+ if (properties == null) {
+ properties = new StringBuilder("immutable");
+ } else {
+ properties.append(" immutable");
+ }
+ }
+
+ if (properties != null) {
+ sb.append(TextRenderer.surroundString(properties.toString(), "{", "}"));
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Comapres two attributes lexicographically based on their identifier.
+ *
+ * @see Comparable#compareTo(java.lang.Object)
+ */
+ @Override
+ public int compareTo(Attribute a) {
+ return getIdentifier().compareTo(a.getIdentifier());
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.core;
+
+import com.sun.net.httpserver.Headers;
+import cz.cesnet.cloud.occi.collection.SetCover;
+import cz.cesnet.cloud.occi.renderer.TextRenderer;
+import cz.cesnet.cloud.occi.type.Identifiable;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class representing an OCCI Category.
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class Category implements Identifiable, Comparable<Category> {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Category.class);
+ public static final URI SCHEME_CORE_DEFAULT = URI.create("http://schemas.ogf.org/occi/core#");
+ public static final URI SCHEME_INFRASTRUCTURE_DEFAULT = URI.create("http://schemas.ogf.org/occi/infrastructure#");
+
+ private String term;
+ private URI scheme;
+ private String title;
+ private URI location;
+ private final SetCover<Attribute> attributes = new SetCover<>();
+ private final SetCover<Action> actions = new SetCover<>();
+ private final SetCover<Entity> entities = new SetCover<>();
+
+ /**
+ * Constructor. Creates a category with scheme, term, title, location and
+ * attributes.
+ *
+ * @param scheme category's scheme. Cannot be null.
+ * @param term category's term. Cannot be null nor empty.
+ * @param title category's title
+ * @param location category's location
+ * @param attributes category's attributes
+ */
+ public Category(URI scheme, String term, String title, URI location, Collection<Attribute> attributes) {
+ LOGGER.debug("Creating category: scheme={}, term={}, title={}, location={}, attributes={}", scheme, term, title, location, attributes);
+
+ if (scheme == null) {
+ throw new NullPointerException("Category scheme cannot be null.");
+ }
+ if (term == null) {
+ throw new NullPointerException("Category term cannot be null.");
+ }
+ if (term.isEmpty()) {
+ throw new IllegalArgumentException("Category term cannot be empty.");
+ }
+
+ this.scheme = scheme;
+ this.term = term;
+ this.title = title;
+ this.location = location;
+
+ if (attributes != null) {
+ this.attributes.addAll(attributes);
+ }
+ }
+
+ /**
+ * Constructor. Creates a category with scheme and term.
+ *
+ * @param scheme category's scheme. Cannot be null.
+ * @param term category's term. Cannot be null nor empty.
+ */
+ public Category(URI scheme, String term) {
+ this(scheme, term, null, null, null);
+ }
+
+ /**
+ * Returns category's term.
+ *
+ * @return category's term
+ */
+ public String getTerm() {
+ return term;
+ }
+
+ /**
+ * Sets category's term.
+ *
+ * @param term category's term. Cannot be null nor empty.
+ */
+ public void setTerm(String term) {
+ if (term == null) {
+ throw new NullPointerException("Category term cannot be null.");
+ }
+ if (term.isEmpty()) {
+ throw new IllegalArgumentException("Category term cannot be empty.");
+ }
+
+ this.term = term;
+ }
+
+ /**
+ * Returns category's scheme.
+ *
+ * @return category's scheme
+ */
+ public URI getScheme() {
+ return scheme;
+ }
+
+ /**
+ * Sets category's scheme.
+ *
+ * @param scheme category's scheme. Cannot be null.
+ */
+ public void setScheme(URI scheme) {
+ if (scheme == null) {
+ throw new NullPointerException("Category scheme cannot be null.");
+ }
+
+ this.scheme = scheme;
+ }
+
+ /**
+ * Returns category's identifier.
+ *
+ * @return category's identifier
+ */
+ @Override
+ public String getIdentifier() {
+ return getScheme().toString() + getTerm();
+ }
+
+ /**
+ * Returns category's title.
+ *
+ * @return category's title
+ */
+ public String getTitle() {
+ return title;
+ }
+
+ /**
+ * Sets category's title
+ *
+ * @param title category's title
+ */
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ /**
+ * Returns category's location.
+ *
+ * @return category's location
+ */
+ public URI getLocation() {
+ return location;
+ }
+
+ /**
+ * Sets category's location
+ *
+ * @param location category's location
+ */
+ public void setLocation(URI location) {
+ this.location = location;
+ }
+
+ //attributes
+ /**
+ * Checks whether category has given attribute.
+ *
+ * @param attribute attribute to be looked up
+ * @return true if category has given attribute, false otherwise
+ */
+ public boolean containsAttribute(Attribute attribute) {
+ return attributes.contains(attribute);
+ }
+
+ /**
+ * Checks whether category has given attribute.
+ *
+ * @param attributeIdentifier identifier of attribute to be looked up
+ * @return true if category has given attribute, false otherwise
+ */
+ public boolean containsAttribute(String attributeIdentifier) {
+ return attributes.contains(attributeIdentifier);
+ }
+
+ /**
+ * Adds given attribute to category.
+ *
+ * @param attribute attribute to be added
+ * @return true if the addition was successful, false otherwise
+ */
+ public boolean addAttribute(Attribute attribute) {
+ return attributes.add(attribute);
+ }
+
+ /**
+ * Returns attribute from category.
+ *
+ * @param attributeIdentifier identifier of the requested attribute
+ * @return attribute from category
+ */
+ public Attribute getAttribute(String attributeIdentifier) {
+ return attributes.get(attributeIdentifier);
+ }
+
+ /**
+ * Removes attribute from category
+ *
+ * @param attribute to be removed
+ * @return true if the removal was successful, false otherwise
+ */
+ public boolean removeAttribute(Attribute attribute) {
+ return attributes.remove(attribute);
+ }
+
+ /**
+ * Removes all attributes from category.
+ */
+ public void clearAttributes() {
+ attributes.clear();
+ }
+
+ /**
+ * Returns all category's attributes in form of set.
+ *
+ * @return all category's attributes in form of set
+ */
+ public Set<Attribute> getAttributes() {
+ return attributes.getSet();
+ }
+
+ //actions
+ /**
+ * Checks whether category has given action.
+ *
+ * @param action action to be looked up
+ * @return true if category has given action, false otherwise
+ */
+ public boolean containsAction(Action action) {
+ return actions.contains(action);
+ }
+
+ /**
+ * Checks whether category has given action.
+ *
+ * @param actionIdentifier identifier of action to be looked up
+ * @return true if category has given action, false otherwise
+ */
+ public boolean containsAction(String actionIdentifier) {
+ return actions.contains(actionIdentifier);
+ }
+
+ /**
+ * Adds given action to category.
+ *
+ * @param action action to be added
+ * @return true if the addition was successful, false otherwise
+ */
+ public boolean addAction(Action action) {
+ return actions.add(action);
+ }
+
+ /**
+ * Returns action from category.
+ *
+ * @param actionIdentifier identifier of the requested action
+ * @return action from category
+ */
+ public Action getAction(String actionIdentifier) {
+ return actions.get(actionIdentifier);
+ }
+
+ /**
+ * Removes action from category
+ *
+ * @param action to be removed
+ * @return true if the removal was successful, false otherwise
+ */
+ public boolean removeAction(Action action) {
+ return actions.remove(action);
+ }
+
+ /**
+ * Removes all actions from category.
+ */
+ public void clearActions() {
+ actions.clear();
+ }
+
+ /**
+ * Returns all category's actions in form of set.
+ *
+ * @return all category's actions in form of set
+ */
+ public Set<Action> getActions() {
+ return actions.getSet();
+ }
+
+ //entities
+ /**
+ * Checks whether category has given entity.
+ *
+ * @param entity entity to be looked up
+ * @return true if category has given entity, false otherwise
+ */
+ public boolean containsEntity(Entity entity) {
+ return entities.contains(entity);
+ }
+
+ /**
+ * Checks whether category has given entity.
+ *
+ * @param entityIdentifier identifier of entity to be looked up
+ * @return true if category has given entity, false otherwise
+ */
+ public boolean containsEntity(String entityIdentifier) {
+ return entities.contains(entityIdentifier);
+ }
+
+ /**
+ * Adds given entity to category.
+ *
+ * @param entity entity to be added
+ * @return true if the addition was successful, false otherwise
+ */
+ public boolean addEntity(Entity entity) {
+ return entities.add(entity);
+ }
+
+ /**
+ * Returns entity from category.
+ *
+ * @param entityIdentifier identifier of the requested entity
+ * @return entity from category
+ */
+ public Entity getEntity(String entityIdentifier) {
+ return entities.get(entityIdentifier);
+ }
+
+ /**
+ * Removes entity from category
+ *
+ * @param entity to be removed
+ * @return true if the removal was successful, false otherwise
+ */
+ public boolean removeEntity(Entity entity) {
+ return entities.remove(entity);
+ }
+
+ /**
+ * Removes all entities from category.
+ */
+ public void clearEntities() {
+ entities.clear();
+ }
+
+ /**
+ * Returns all category's entities in form of set.
+ *
+ * @return all category's entities in form of set
+ */
+ public Set<Entity> getEntities() {
+ return entities.getSet();
+ }
+
+ /**
+ * @see Object#hashCode()
+ * @return category's hash code
+ */
+ @Override
+ public int hashCode() {
+ int hash = 7;
+ hash = 79 * hash + Objects.hashCode(this.term);
+ hash = 79 * hash + Objects.hashCode(this.scheme);
+ return hash;
+ }
+
+ /**
+ * @see Object#equals(java.lang.Object)
+ * @param obj object to compare category with
+ * @return true if two categories are equal, false otherwise
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final Category other = (Category) obj;
+ if (!Objects.equals(this.term, other.term)) {
+ return false;
+ }
+ if (!Objects.equals(this.scheme, other.scheme)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Resturns string representation of the category
+ *
+ * @see Object#toString()
+ * @return string representation of the category
+ */
+ @Override
+ public String toString() {
+ return "Category{" + "term=" + term + ", scheme=" + scheme + ", title=" + title + ", location=" + location + ", attributes=" + attributes + '}';
+ }
+
+ /**
+ * Returns a plain text representation of category and its subtypes (kinds
+ * and mixins) according to OCCI standard.
+ *
+ * @return plain text representation of category
+ */
+ public String toText() {
+ return toText(true);
+ }
+
+ /**
+ * Returns a plain text representation of category and its subtypes (kinds
+ * and mixins) according to OCCI standard.
+ *
+ * @param fullRendering whether to render all the information
+ * @return plain text representation of category
+ */
+ public String toText(boolean fullRendering) {
+ StringBuilder sb = new StringBuilder("Category: ");
+ sb.append(textBody(fullRendering));
+
+ return sb.toString();
+ }
+
+ /**
+ * Returns an occi text representation of category and its subtypes (kinds
+ * and mixins) according to OCCI standard in form of headers.
+ *
+ * @return plain text representation of category
+ */
+ public Headers toHeaders() {
+ return toHeaders(true);
+ }
+
+ /**
+ * Returns an occi text representation of category and its subtypes (kinds
+ * and mixins) according to OCCI standard in form of headers.
+ *
+ * @param fullRendering whether to render all the information
+ * @return plain text representation of category
+ */
+ public Headers toHeaders(boolean fullRendering) {
+ Headers headers = new Headers();
+ headers.add("Category", textBody(fullRendering));
+
+ return headers;
+ }
+
+ private String textBody(boolean fullRendering) {
+ StringBuilder sb = new StringBuilder(term);
+ sb.append(";");
+ sb.append("scheme");
+ sb.append(TextRenderer.surroundString(scheme.toString()));
+ sb.append("class");
+ sb.append(TextRenderer.surroundString(this.getClass().getSimpleName().toLowerCase()));
+
+ if (fullRendering) {
+ if (title != null && !title.isEmpty()) {
+ sb.append("title");
+ sb.append(TextRenderer.surroundString(title));
+ }
+
+ if (this instanceof Kind) {
+ Kind kind = (Kind) this;
+ if (kind.getRelations().size() == 1) {
+ sb.append("rel");
+ for (Kind k : kind.getRelations()) {
+ sb.append(TextRenderer.surroundString(k.getIdentifier()));
+ }
+ }
+ }
+
+ if (this instanceof Mixin) {
+ Mixin mixin = (Mixin) this;
+ if (mixin.getRelations().size() == 1) {
+ sb.append("rel");
+ for (Mixin m : mixin.getRelations()) {
+ sb.append(TextRenderer.surroundString(m.getIdentifier()));
+ }
+ }
+ }
+
+ if (location != null) {
+ sb.append("location");
+ sb.append(TextRenderer.surroundString(location.toString()));
+ }
+
+ if (attributes != null && !attributes.getSet().isEmpty()) {
+ sb.append("attributes");
+ StringBuilder attrSB = new StringBuilder();
+ List<Attribute> attributeList = new ArrayList<>(attributes.getSet());
+ Collections.sort(attributeList);
+ for (Attribute attribute : attributeList) {
+ attrSB.append(attribute.toText());
+ attrSB.append(" ");
+ }
+ attrSB.deleteCharAt(attrSB.length() - 1);
+ sb.append(TextRenderer.surroundString(attrSB.toString()));
+ }
+
+ if (actions != null && !actions.getSet().isEmpty()) {
+ sb.append("actions");
+ StringBuilder actionsSB = new StringBuilder();
+ List<Action> actionList = new ArrayList<>(actions.getSet());
+ Collections.sort(actionList);
+ for (Action action : actionList) {
+ actionsSB.append(action.getIdentifier());
+ actionsSB.append(" ");
+ }
+ actionsSB.deleteCharAt(actionsSB.length() - 1);
+ sb.append(TextRenderer.surroundString(actionsSB.toString()));
+ }
+ }
+
+ if (sb.charAt(sb.length() - 1) == ';') {
+ sb.deleteCharAt(sb.length() - 1);
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Comapres two cetegories lexicographically based on their identifier.
+ *
+ * @see Comparable#compareTo(java.lang.Object)
+ */
+ @Override
+ public int compareTo(Category c) {
+ return getIdentifier().compareTo(c.getIdentifier());
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.core;
+
+import com.sun.net.httpserver.Headers;
+import cz.cesnet.cloud.occi.Model;
+import cz.cesnet.cloud.occi.collection.AttributeMapCover;
+import cz.cesnet.cloud.occi.type.Identifiable;
+import cz.cesnet.cloud.occi.collection.SetCover;
+import cz.cesnet.cloud.occi.exception.InvalidAttributeValueException;
+import cz.cesnet.cloud.occi.exception.RenderingException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract class representing an OCCI Entity.
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public abstract class Entity implements Identifiable, Comparable<Entity> {
+
+ public static final String ID_ATTRIBUTE_NAME = "occi.core.id";
+ public static final String TITLE_ATTRIBUTE_NAME = "occi.core.title";
+ public static final URI SCHEME_DEFAULT = Category.SCHEME_CORE_DEFAULT;
+ public static final String TERM_DEFAULT = "entity";
+ public static final String KIND_IDENTIFIER_DEFAULT = SCHEME_DEFAULT + TERM_DEFAULT;
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Entity.class);
+ private Kind kind;
+ private Model model;
+ private final SetCover<Mixin> mixins = new SetCover<>();
+ private final AttributeMapCover attributes = new AttributeMapCover();
+
+ /**
+ * Constructor.
+ *
+ * @param id occi.core.id attribute. Cannot be null.
+ * @param kind entity's kind. Cannot be null.
+ * @param title occi.core.title attribute
+ * @param model entity's model
+ * @throws InvalidAttributeValueException in case of invalid id or title
+ * value
+ */
+ public Entity(String id, Kind kind, String title, Model model) throws InvalidAttributeValueException {
+ LOGGER.debug("Creating Entity: class={}, id={}, kind={}, title={}, model={}", getClass().getName(), id, kind, title, model);
+
+ if (id == null) {
+ throw new NullPointerException("Entity id cannot be null.");
+ }
+ if (kind == null) {
+ throw new NullPointerException("Entity kind cannot be null.");
+ }
+
+ privateAddAttribute(ID_ATTRIBUTE_NAME, id);
+ if (title != null && !title.isEmpty()) {
+ privateAddAttribute(TITLE_ATTRIBUTE_NAME, title);
+ }
+ this.kind = kind;
+ this.model = model;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param id occi.core.id attribute. Cannot be null.
+ * @param kind entity's kind. Cannot be null.
+ * @throws InvalidAttributeValueException in case of invalid id or title
+ * value
+ */
+ public Entity(String id, Kind kind) throws InvalidAttributeValueException {
+ this(id, kind, null, null);
+ }
+
+ /**
+ * Returns entity's id.
+ *
+ * @return entity's id
+ */
+ public String getId() {
+ return getValue(ID_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets entity's id.
+ *
+ * @param id entity's id. Cannot be null.
+ * @throws InvalidAttributeValueException in case of invalid id value
+ */
+ public void setId(String id) throws InvalidAttributeValueException {
+ if (id == null) {
+ throw new NullPointerException("Entity id cannot be null.");
+ }
+
+ addAttribute(ID_ATTRIBUTE_NAME, id);
+ }
+
+ /**
+ * Returns entity's kind.
+ *
+ * @return entity's kind
+ */
+ public Kind getKind() {
+ return kind;
+ }
+
+ /**
+ * Sets entity's kind.
+ *
+ * @param kind entity's kind. Cannot be null.
+ */
+ public void setKind(Kind kind) {
+ if (kind == null) {
+ throw new NullPointerException("Entity kind cannot be null.");
+ }
+
+ this.kind = kind;
+ }
+
+ /**
+ * Returns entity's identifier.
+ *
+ * @return entity's identifier
+ */
+ @Override
+ public String getIdentifier() {
+ return kind.getIdentifier() + "|" + getId();
+ }
+
+ /**
+ * Returns entity's title.
+ *
+ * @return entity's title
+ */
+ public String getTitle() {
+ return getValue(TITLE_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets entity's title.
+ *
+ * @param title entity's title
+ * @throws InvalidAttributeValueException in case of invalit tile value
+ */
+ public void setTitle(String title) throws InvalidAttributeValueException {
+ addAttribute(TITLE_ATTRIBUTE_NAME, title);
+ }
+
+ /**
+ * Returns entity's model.
+ *
+ * @return entity's model
+ */
+ public Model getModel() {
+ return model;
+ }
+
+ /**
+ * Sets entity's model.
+ *
+ * @param model entity's model
+ */
+ public void setModel(Model model) {
+ this.model = model;
+ }
+
+ private void privateAddAttribute(String attributeIdentifier, String value) throws InvalidAttributeValueException {
+ if (!isValidAttributeValue(attributeIdentifier, value)) {
+ Attribute attribute = getAttribute(attributeIdentifier);
+ throw new InvalidAttributeValueException("'" + value + "' is not a suitable value for " + attribute);
+ }
+
+ Attribute attribute = getAttribute(attributeIdentifier);
+ if (attribute == null) {
+ attribute = new Attribute(attributeIdentifier);
+ }
+ attributes.add(attribute, value);
+ }
+
+ /**
+ * Adds attribute and its value. If attribute has a content restriction,
+ * value is checked.
+ *
+ * @param attributeIdentifier
+ * @param value
+ * @throws InvalidAttributeValueException
+ */
+ public void addAttribute(String attributeIdentifier, String value) throws InvalidAttributeValueException {
+ privateAddAttribute(attributeIdentifier, value);
+ }
+
+ /**
+ * Adds attributes and their values. If attributes have a content
+ * restriction, values are checked.
+ *
+ * @param attributes
+ * @throws InvalidAttributeValueException
+ */
+ public void addAttributes(Map<String, String> attributes) throws InvalidAttributeValueException {
+ for (String name : attributes.keySet()) {
+ privateAddAttribute(name, attributes.get(name));
+ }
+ }
+
+ private boolean isValidAttributeValue(String attributeIdentifier, String value) {
+ Attribute attribute = getAttribute(attributeIdentifier);
+
+ if (attribute == null) {
+ return true;
+ }
+
+ if (attribute.getPattern() == null || attribute.getPattern().isEmpty()) {
+ return true;
+ }
+
+ return value.matches(attribute.getPattern());
+ }
+
+ private Attribute getAttribute(String attributeIdentifier) {
+ Attribute attribute = getAttributeFromKindsIfExists(kind, attributeIdentifier);
+ if (attribute == null) {
+ attribute = getAttributeFromMixinsIfExists(getMixins(), attributeIdentifier);
+ }
+
+ return attribute;
+ }
+
+ private Attribute getAttributeFromKindsIfExists(Kind kind, String attributeIdentifier) {
+ if (kind == null) {
+ return null;
+ }
+
+ if (kind.containsAttribute(attributeIdentifier)) {
+ return kind.getAttribute(attributeIdentifier);
+ }
+
+ Attribute attribute = null;
+ for (Kind k : kind.getRelations()) {
+ if (attribute != null) {
+ return attribute;
+ }
+
+ attribute = getAttributeFromKindsIfExists(k, attributeIdentifier);
+ }
+
+ return attribute;
+ }
+
+ private Attribute getAttributeFromMixinsIfExists(Set<Mixin> mixins, String attributeIdentifier) {
+ for (Mixin m : mixins) {
+ if (m.containsAttribute(attributeIdentifier)) {
+ return m.getAttribute(attributeIdentifier);
+ }
+ Attribute attribute = getAttributeFromMixinsIfExists(m.getRelations(), attributeIdentifier);
+ if (attribute != null) {
+ return attribute;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Removes attribute from entity.
+ *
+ * @param attributeIdentifier identifier of the attribute to be removed
+ */
+ public void removeAttribute(String attributeIdentifier) {
+ attributes.remove(attributeIdentifier);
+ }
+
+ /**
+ * Checks whether entity has given attribute.
+ *
+ * @param attribute attribute to be looked up
+ * @return true if entity has given attribute, false otherwise
+ */
+ public boolean containsAttribute(Attribute attribute) {
+ return attributes.containsAttribute(attribute);
+ }
+
+ /**
+ * Checks whether entity has given attribute.
+ *
+ * @param attributeName name of the attribute to be looked up
+ * @return true if entity has given attribute, false otherwise
+ */
+ public boolean containsAttribute(String attributeName) {
+ return attributes.containsAttribute(attributeName);
+ }
+
+ /**
+ * Returns value of given attribute.
+ *
+ * @param attribute attribute which value will be returned
+ * @return value of given attribute
+ */
+ public String getValue(Attribute attribute) {
+ return attributes.getValue(attribute);
+ }
+
+ /**
+ * Returns value of given attribute.
+ *
+ * @param attributeName name of the attribute which value will be returned
+ * @return value of given attribute
+ */
+ public String getValue(String attributeName) {
+ return attributes.getValue(attributeName);
+ }
+
+ /**
+ * Returns all entity's attributes and their values in form of map.
+ *
+ * @return all entity's attributes and their values in form of map
+ */
+ public Map<Attribute, String> getAttributes() {
+ return attributes.getAttributes();
+ }
+
+ /**
+ * Removes all entity's attributes.
+ */
+ public void clearAttributes() {
+ attributes.clear();
+ }
+
+ /**
+ * Returns text representation of entity's attributes in one line.
+ *
+ * @return text representation of entity's attributes in one line
+ */
+ protected String attributesToOneLineText() {
+ return attributes.toOneLineText();
+ }
+
+ /**
+ * Returns a text representation of entity's attributes with prefix.
+ *
+ * @return text representation of entity's attributes with prefix
+ */
+ protected String attributesToPrefixText() {
+ return attributes.toPrefixText();
+ }
+
+ /**
+ * Returns an occi text representation of entity's attributes in form of
+ * headers.
+ *
+ * @return occi text representation of entity's attributes in form of
+ * headers
+ */
+ protected Headers attributesToHeaders() {
+ return attributes.toHeaders();
+ }
+
+ /**
+ * Checks whether the entity has given mixin.
+ *
+ * @param mixin mixin to be looked up
+ * @return true if entity has given mixin, false otherwise
+ */
+ public boolean containsMixin(Mixin mixin) {
+ return mixins.contains(mixin);
+ }
+
+ /**
+ * Checks whether the entity has given mixin.
+ *
+ * @param mixinIdentifier identifier of mixin to be looked up
+ * @return true if entity has given mixin, false otherwise
+ */
+ public boolean containsMixin(String mixinIdentifier) {
+ return mixins.contains(mixinIdentifier);
+ }
+
+ /**
+ * Adds mixin to the entity.
+ *
+ * @param mixin mixin to be added
+ * @return true if the addition was successful, false otherwise
+ */
+ public boolean addMixin(Mixin mixin) {
+ return mixins.add(mixin);
+ }
+
+ /**
+ * Adds all the mixins from given collection to the entity.
+ *
+ * @param mixins collection of mixins
+ * @return true if the addition was successful, false otherwise
+ */
+ public boolean addMixins(Collection<Mixin> mixins) {
+ return this.mixins.addAll(mixins);
+ }
+
+ /**
+ * Returns mixin form entity.
+ *
+ * @param mixinIdentifier identifier of requested mixin
+ * @return mixin form entity
+ */
+ public Mixin getMixin(String mixinIdentifier) {
+ return mixins.get(mixinIdentifier);
+ }
+
+ /**
+ * Removes mixin from entity.
+ *
+ * @param mixin mixin to be removed
+ * @return true if the removal was successful, false otherwise
+ */
+ public boolean removeMixin(Mixin mixin) {
+ return mixins.remove(mixin);
+ }
+
+ /**
+ * Removes all mixins from entity.
+ */
+ public void clearMixins() {
+ mixins.clear();
+ }
+
+ /**
+ * Returns all mixins from entity in form of a set.
+ *
+ * @return all mixins from entity in form of a set
+ */
+ public Set<Mixin> getMixins() {
+ return mixins.getSet();
+ }
+
+ /**
+ * @see Object#hashCode()
+ * @return entity's hash code
+ */
+ @Override
+ public int hashCode() {
+ int hash = 7;
+ hash = 89 * hash + Objects.hashCode(getId());
+ hash = 89 * hash + Objects.hashCode(this.kind);
+ return hash;
+ }
+
+ /**
+ * @see Object#equals(java.lang.Object)
+ * @param obj object to compare entity with
+ * @return true if two entity are equal, false otherwise
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof Entity)) {
+ return false;
+ }
+ final Entity other = (Entity) obj;
+ if (!Objects.equals(getId(), other.getId())) {
+ return false;
+ }
+ if (!Objects.equals(this.kind, other.kind)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Resturns string representation of the entity
+ *
+ * @see Object#toString()
+ * @return string representation of the entity
+ */
+ @Override
+ public String toString() {
+ return "Entity{" + "class=" + getClass().getName() + ", id=" + getId() + ", kind=" + kind + ", title=" + getTitle() + ", mixins=" + mixins + ", attributes=" + attributes + '}';
+ }
+
+ /**
+ * Renders entity to its plain text form as described in OCCI standard.
+ *
+ * @return plain text form of entity
+ * @throws RenderingException
+ */
+ public abstract String toText() throws RenderingException;
+
+ /**
+ * Renders entity to its occi text form as described in OCCI standard in
+ * form of headers.
+ *
+ * @return occi text form of entity
+ * @throws RenderingException
+ */
+ public abstract Headers toHeaders() throws RenderingException;
+
+ /**
+ * Renders entity to its JSON form as described in OCCI standard.
+ *
+ * @return JSON form of entity
+ */
+ public abstract String toJSON();
+
+ /**
+ * Comapres two entities lexicographically based on their identifier.
+ *
+ * @see Comparable#compareTo(java.lang.Object)
+ */
+ @Override
+ public int compareTo(Entity e) {
+ return getIdentifier().compareTo(e.getIdentifier());
+ }
+
+ /**
+ * Returns entity's default kind identifier (scheme+term). For Entity class
+ * this equals to 'http://schemas.ogf.org/occi/core#entity'.
+ *
+ * @return entity's default kind identifier
+ */
+ public String getDefaultKindIdentifier() {
+ return KIND_IDENTIFIER_DEFAULT;
+ }
+
+ /**
+ * Returns entity's default attributes. For Entity class those are
+ * attributes occi.core.id and occi.core.title.
+ *
+ * @return list of entity's default attributes
+ */
+ public static List<Attribute> getDefaultAttributes() {
+ List<Attribute> list = new ArrayList<>();
+ list.add(new Attribute(ID_ATTRIBUTE_NAME, true, true));
+ list.add(new Attribute(TITLE_ATTRIBUTE_NAME, false, false));
+
+ return list;
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.core;
+
+import cz.cesnet.cloud.occi.collection.SetCover;
+import java.net.URI;
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * Class representing an OCCI Kind.
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class Kind extends Category {
+
+ private final SetCover<Kind> related = new SetCover<>();
+ private String entityType;
+ private Kind parentKind = null;
+
+ /**
+ * Constructor. Creates new kind with scheme, term, title, location and
+ * attributes.
+ *
+ * @param scheme kind's scheme. Cannot be null.
+ * @param term kind's term. Cannot be null nor empty.
+ * @param title kind's title
+ * @param location kind's location
+ * @param attributes kind's attributes
+ */
+ public Kind(URI scheme, String term, String title, URI location, Collection<Attribute> attributes) {
+ super(scheme, term, title, location, attributes);
+ }
+
+ /**
+ * Constructor. Creates new kind with scheme and term.
+ *
+ * @param scheme kind's scheme. Cannot be null.
+ * @param term kind's term. Cannot be null nor empty.
+ */
+ public Kind(URI scheme, String term) {
+ this(scheme, term, null, null, null);
+ }
+
+ /**
+ * Returns kind's entity type.
+ *
+ * @return kind's entity type
+ */
+ public String getEntityType() {
+ return entityType;
+ }
+
+ /**
+ * Sets kind's entity type.
+ *
+ * @param entityType kind's entity type
+ */
+ public void setEntityType(String entityType) {
+ this.entityType = entityType;
+ }
+
+ /**
+ * Returns kind's parent kind. For example kind
+ * 'http://schemas.ogf.org/occi/infrastructure#compute' has parent kind
+ * 'http://schemas.ogf.org/occi/core#resource'.
+ *
+ * @return kind's parent kind
+ */
+ public Kind getParentKind() {
+ return parentKind;
+ }
+
+ /**
+ * Sets kind's parent kind.
+ *
+ * @param parentKind kind's parent kind
+ */
+ public void setParentKind(Kind parentKind) {
+ this.parentKind = parentKind;
+ }
+
+ /**
+ * Checks whether this kind is in relation with given kind.
+ *
+ * @param kind kind to chcek relation with
+ * @return true if there is relation between kinds, false otherwise
+ */
+ public boolean relatesTo(Kind kind) {
+ return related.contains(kind);
+ }
+
+ /**
+ * Checks whether this kind is in relation with given kind.
+ *
+ * @param kindIdentifier identifier of kind to chcek relation with
+ * @return true if there is relation between kinds, false otherwise
+ */
+ public boolean relatesTo(String kindIdentifier) {
+ return related.contains(kindIdentifier);
+ }
+
+ /**
+ * Creates a relation with given kind.
+ *
+ * @param kind kind to create a relation with
+ * @return true if the relation was created successfully, false otherwise
+ */
+ public boolean addRelation(Kind kind) {
+ return related.add(kind);
+ }
+
+ /**
+ * Creates a relation with given kind.
+ *
+ * @param kindIdentifier identifier of kind to create a relation with
+ * @return true if the relation was created successfully, false otherwise
+ */
+ public Kind getRelatedKind(String kindIdentifier) {
+ return related.get(kindIdentifier);
+ }
+
+ /**
+ * Removes relation with given kind.
+ *
+ * @param kind kind with which relation will be removed
+ * @return true if the relation was removed successfully, false otherwise
+ */
+ public boolean removeRelation(Kind kind) {
+ return related.remove(kind);
+ }
+
+ /**
+ * Remove all relations.
+ */
+ public void clearRelations() {
+ related.clear();
+ }
+
+ /**
+ * Returns all related kinds in form of set.
+ *
+ * @return all related kinds in form of set
+ */
+ public Set<Kind> getRelations() {
+ return related.getSet();
+ }
+
+ /**
+ * Resturns string representation of kind
+ *
+ * @see Object#toString()
+ * @return string representation of kind
+ */
+ @Override
+ public String toString() {
+ return "Kind{" + "term=" + getTerm() + ", scheme=" + getScheme() + ", title=" + getTitle() + ", location=" + getLocation() + ", attributes=" + getAttributes() + ", related=" + related + '}';
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.core;
+
+import com.sun.net.httpserver.Headers;
+import cz.cesnet.cloud.occi.Model;
+import cz.cesnet.cloud.occi.exception.InvalidAttributeValueException;
+import cz.cesnet.cloud.occi.exception.RenderingException;
+import cz.cesnet.cloud.occi.renderer.TextRenderer;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Class representing an OCCI Link.
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class Link extends Entity {
+
+ public static final String SOURCE_ATTRIBUTE_NAME = "occi.core.source";
+ public static final String TARGET_ATTRIBUTE_NAME = "occi.core.target";
+ public static final URI SCHEME_DEFAULT = Category.SCHEME_CORE_DEFAULT;
+ public static final String TERM_DEFAULT = "link";
+ public static final String KIND_IDENTIFIER_DEFAULT = SCHEME_DEFAULT + TERM_DEFAULT;
+ private String relation;
+
+ /**
+ * Constructor.
+ *
+ * @param id occi.core.id attribute. Cannot be null.
+ * @param kind link's kind. Cannot be null.
+ * @param title occi.core.title attribute
+ * @param model link's model
+ * @throws InvalidAttributeValueException in case of invalid id or title
+ * value
+ */
+ public Link(String id, Kind kind, String title, Model model) throws InvalidAttributeValueException {
+ super(id, kind, title, model);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param id occi.core.id attribute. Cannot be null.
+ * @param kind link's kind. Cannot be null.
+ * @throws InvalidAttributeValueException in case of invalid id value
+ */
+ public Link(String id, Kind kind) throws InvalidAttributeValueException {
+ super(id, kind);
+ }
+
+ /**
+ * Returns link's source (value of occi.core.source attribute).
+ *
+ * @return link's source
+ */
+ public String getSource() {
+ return getValue(SOURCE_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets link's source.
+ *
+ * @param source link's source. Cannot be null.
+ * @throws InvalidAttributeValueException in case source value is invalid
+ */
+ public void setSource(Resource source) throws InvalidAttributeValueException {
+ if (source == null) {
+ throw new NullPointerException("source cannot be null");
+ }
+ addAttribute(SOURCE_ATTRIBUTE_NAME, source.getLocation());
+ }
+
+ /**
+ * Sets link's source.
+ *
+ * @param sourceLocation location of link's source
+ * @throws InvalidAttributeValueException in case source value is invalid
+ */
+ public void setSource(String sourceLocation) throws InvalidAttributeValueException {
+ addAttribute(SOURCE_ATTRIBUTE_NAME, sourceLocation);
+ }
+
+ /**
+ * Returns link's target (value of occi.core.terget attribute).
+ *
+ * @return link's target
+ */
+ public String getTarget() {
+ return getValue(TARGET_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets link's target.
+ *
+ * @param target link's target. Cannot be null.
+ * @throws InvalidAttributeValueException in case target value is invalid
+ */
+ public void setTarget(Resource target) throws InvalidAttributeValueException {
+ if (target == null) {
+ throw new NullPointerException("target cannot be null");
+ }
+ addAttribute(TARGET_ATTRIBUTE_NAME, target.getLocation());
+ }
+
+ /**
+ * Sets link's target.
+ *
+ * @param targetLocation location of link's target
+ * @throws InvalidAttributeValueException in case target value is invalid
+ */
+ public void setTarget(String targetLocation) throws InvalidAttributeValueException {
+ addAttribute(TARGET_ATTRIBUTE_NAME, targetLocation);
+ }
+
+ /**
+ * Returns link's relation.
+ *
+ * @return link's relation
+ */
+ public String getRelation() {
+ return relation;
+ }
+
+ /**
+ * Sets link's relation.
+ *
+ * @param relation
+ */
+ public void setRelation(String relation) {
+ this.relation = relation;
+ }
+
+ /**
+ * Returns link's default identifier 'http://schemas.ogf.org/occi/core#link'
+ *
+ * @return link's default identifier
+ */
+ @Override
+ public String getDefaultKindIdentifier() {
+ return KIND_IDENTIFIER_DEFAULT;
+ }
+
+ public static List<Attribute> getDefaultAttributes() {
+ List<Attribute> list = new ArrayList<>();
+ list.addAll(Entity.getDefaultAttributes());
+ list.add(new Attribute(SOURCE_ATTRIBUTE_NAME, true, false));
+ list.add(new Attribute(TARGET_ATTRIBUTE_NAME, true, false));
+
+ return list;
+ }
+
+ public static Kind getDefaultKind() {
+ Kind kind = new Kind(SCHEME_DEFAULT, TERM_DEFAULT, "Link", URI.create("/link/"), Link.getDefaultAttributes());
+ return kind;
+ }
+
+ /**
+ * Returns a plain text representation of link instance as described in OCCI
+ * standard.
+ *
+ * @return plain text representation of link instance
+ */
+ @Override
+ public String toText() {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append(getKind().toText(false));
+
+ List<Mixin> mixinList = new ArrayList<>(getMixins());
+ Collections.sort(mixinList);
+ for (Mixin m : mixinList) {
+ sb.append("\n");
+ sb.append(m.toText(false));
+ }
+
+ String attributesString = attributesToPrefixText();
+ if (!attributesString.isEmpty()) {
+ sb.append("\n");
+ sb.append(attributesString);
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Returns an occi text representation of link instance as described in OCCI
+ * standard in form of headers.
+ *
+ * @return plain text representation of link instance
+ */
+ @Override
+ public Headers toHeaders() {
+ Headers headers = new Headers();
+
+ headers.putAll(getKind().toHeaders(false));
+
+ List<Mixin> mixinList = new ArrayList<>(getMixins());
+ Collections.sort(mixinList);
+ for (Mixin m : mixinList) {
+ Headers mixinHeaders = m.toHeaders(false);
+ for (String name : mixinHeaders.keySet()) {
+ for (String value : mixinHeaders.get(name)) {
+ headers.add(name, value);
+ }
+ }
+ }
+
+ Headers attributeHeaders = attributesToHeaders();
+ if (!attributeHeaders.isEmpty()) {
+ headers.putAll(attributeHeaders);
+ }
+
+ return headers;
+ }
+
+ /**
+ * Returns an inline plain text representation of link instance as described
+ * in OCCI standard.
+ *
+ * @return inline plain text representation of link instance
+ * @throws RenderingException
+ */
+ public String toInlineText() throws RenderingException {
+ StringBuilder sb = new StringBuilder("Link: ");
+ sb.append(inlineTextBody());
+
+ return sb.toString();
+ }
+
+ /**
+ * Returns an inline occi text representation of link instance as described
+ * in OCCI standard in form of headers.
+ *
+ * @return inline occi text representation of link instance in form of
+ * headers
+ * @throws RenderingException
+ */
+ public Headers toInlineHeaders() throws RenderingException {
+ Headers headers = new Headers();
+ headers.add("Link", inlineTextBody());
+
+ return headers;
+ }
+
+ private String inlineTextBody() throws RenderingException {
+ StringBuilder sb = new StringBuilder("");
+ if (getTarget() == null || getTarget().isEmpty()) {
+ throw new RenderingException("Link " + this + " is missing a target attribute.");
+ }
+ sb.append(TextRenderer.surroundString(getTarget(), "<", ">;"));
+
+ if (relation == null || relation.isEmpty()) {
+ throw new RenderingException("Link " + this + " is missing a relation.");
+ }
+ sb.append("rel");
+ sb.append(TextRenderer.surroundString(relation));
+
+ if (getKind().getLocation() != null && getId() != null && !getId().isEmpty()) {
+ sb.append("self");
+ sb.append(TextRenderer.surroundString(getKind().getLocation().toString() + getId()));
+ }
+
+ sb.append("category");
+ sb.append("=\"");
+ sb.append(getKind().getIdentifier());
+ for (Mixin mixin : getMixins()) {
+ sb.append(" ");
+ sb.append(mixin.getIdentifier());
+ }
+ sb.append("\";");
+
+ sb.append(attributesToOneLineText());
+
+ return sb.toString();
+ }
+
+ /**
+ * Returns a JSON representation of link instance as described in OCCI
+ * standard. NOT IMPLEMENTED YET!
+ *
+ * @return JSON representation of link instance
+ */
+ @Override
+ public String toJSON() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.core;
+
+import cz.cesnet.cloud.occi.collection.SetCover;
+import java.net.URI;
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * Class representing an OCCI Mixin.
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class Mixin extends Category {
+
+ private final SetCover<Mixin> related = new SetCover<>();
+
+ /**
+ * Constructor. Creates new mixin with scheme, term, title, location and
+ * attributes.
+ *
+ * @param scheme mixin's scheme. Cannot be null.
+ * @param term mixin's term. Cannot be null nor empty.
+ * @param title mixin's title
+ * @param location mixin's location
+ * @param attributes mixin's attributes
+ */
+ public Mixin(URI scheme, String term, String title, URI location, Collection<Attribute> attributes) {
+ super(scheme, term, title, location, attributes);
+ }
+
+ /**
+ * Constructor. Creates new mixin with scheme and term.
+ *
+ * @param scheme mixin's scheme. Cannot be null.
+ * @param term mixin's term. Cannot be null nor empty.
+ */
+ public Mixin(URI scheme, String term) {
+ this(scheme, term, null, null, null);
+ }
+
+ /**
+ * Checks whether this mixin is in relation with given mixin.
+ *
+ * @param mixin mixin to chcek relation with
+ * @return true if there is relation between mixins, false otherwise
+ */
+ public boolean relatesTo(Mixin mixin) {
+ return related.contains(mixin);
+ }
+
+ /**
+ * Checks whether this mixin is in relation with given mixin.
+ *
+ * @param mixinIdentifier identifier of mixin to chcek relation with
+ * @return true if there is relation between mixins, false otherwise
+ */
+ public boolean relatesTo(String mixinIdentifier) {
+ return related.contains(mixinIdentifier);
+ }
+
+ /**
+ * Creates a relation with given mixin.
+ *
+ * @param mixin mixin to create a relation with
+ * @return true if the relation was created successfully, false otherwise
+ */
+ public boolean addRelation(Mixin mixin) {
+ return related.add(mixin);
+ }
+
+ /**
+ * Creates a relation with given mixin.
+ *
+ * @param mixinIdentifier identifier of mixin to create a relation with
+ * @return true if the relation was created successfully, false otherwise
+ */
+ public Mixin getRelatedMixin(String mixinIdentifier) {
+ return related.get(mixinIdentifier);
+ }
+
+ /**
+ * Removes relation with given mixin.
+ *
+ * @param mixin mixin with which relation will be removed
+ * @return true if the relation was removed successfully, false otherwise
+ */
+ public boolean removeRelation(Mixin mixin) {
+ return related.remove(mixin);
+ }
+
+ /**
+ * Remove all relations.
+ */
+ public void clearRelations() {
+ related.clear();
+ }
+
+ /**
+ * Returns all related mixins in form of set.
+ *
+ * @return all related mixins in form of set
+ */
+ public Set<Mixin> getRelations() {
+ return related.getSet();
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.core;
+
+import com.sun.net.httpserver.Headers;
+import cz.cesnet.cloud.occi.Model;
+import cz.cesnet.cloud.occi.collection.SetCover;
+import cz.cesnet.cloud.occi.exception.InvalidAttributeValueException;
+import cz.cesnet.cloud.occi.exception.RenderingException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class representing an OCCI Resource.
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class Resource extends Entity {
+
+ public static final String SUMMARY_ATTRIBUTE_NAME = "occi.core.summary";
+ public static final URI SCHEME_DEFAULT = Category.SCHEME_CORE_DEFAULT;
+ public static final String TERM_DEFAULT = "resource";
+ public static final String KIND_IDENTIFIER_DEFAULT = SCHEME_DEFAULT + TERM_DEFAULT;
+ private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(Resource.class);
+ private final SetCover<Link> links = new SetCover<>();
+ private final SetCover<Action> actions = new SetCover<>();
+
+ /**
+ * Constructor.
+ *
+ * @param id occi.core.id attribute. Cannot be null.
+ * @param kind resource's kind. Cannot be null.
+ * @param title occi.core.title attribute
+ * @param model resource's model
+ * @param summary resource's summary
+ * @throws InvalidAttributeValueException in case of invalid id, title or
+ * summary value
+ */
+ public Resource(String id, Kind kind, String title, Model model, String summary) throws InvalidAttributeValueException {
+ super(id, kind, title, model);
+
+ addAttribute(SUMMARY_ATTRIBUTE_NAME, summary);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param id occi.core.id attribute. Cannot be null.
+ * @param kind resource's kind. Cannot be null.
+ * @throws InvalidAttributeValueException in case of invalid id value
+ */
+ public Resource(String id, Kind kind) throws InvalidAttributeValueException {
+ super(id, kind);
+ }
+
+ /**
+ * Returns resource's summary.
+ *
+ * @return resource's summary
+ */
+ public String getSummary() {
+ return getValue(SUMMARY_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets resource's summary.
+ *
+ * @param summary resource's summary
+ * @throws InvalidAttributeValueException in case of invalid summary value
+ */
+ public void setSummary(String summary) throws InvalidAttributeValueException {
+ addAttribute(SUMMARY_ATTRIBUTE_NAME, summary);
+ }
+
+ /**
+ * Checks whether resource contains given link.
+ *
+ * @param link link to be looked up
+ * @return true is resource contains given link, false otherwise
+ */
+ public boolean containsLink(Link link) {
+ return links.contains(link);
+ }
+
+ /**
+ * Checks whether resource contains link which kind has given term.
+ *
+ * @param term term of link's kind
+ * @return true is resource contains given link, false otherwise
+ */
+ public boolean containsLink(String term) {
+ for (Link link : links.getSet()) {
+ if (link.getKind().getTerm().equals(term)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks whether resource contains link which kind has given identifier.
+ *
+ * @param identifier identifier of link's kind
+ * @return true is resource contains given link, false otherwise
+ */
+ public boolean containsLink(URI identifier) {
+ String identifierString = identifier.toString();
+ for (Link link : links.getSet()) {
+ if (link.getKind().getIdentifier().equals(identifierString)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Adds link to the resource and automatically sets link's source to
+ * resource.
+ *
+ * @param link to be added
+ * @return true if addition was successful, false otherwise
+ */
+ public boolean addLink(Link link) {
+ if (link.getSource() == null) {
+ try {
+ link.setSource(this);
+ } catch (InvalidAttributeValueException ex) {
+ LOGGER.error("This should not be happening!");
+ }
+ }
+ return links.add(link);
+ }
+
+ /**
+ * Adds links to the resource and automatically sets all links' sources to
+ * resource.
+ *
+ * @param links collections of links to be added
+ * @return true if addition was successful, false otherwise
+ */
+ public boolean addLinks(Collection<Link> links) {
+ for (Link link : links) {
+ if (link.getSource() == null) {
+ try {
+ link.setSource(this);
+ } catch (InvalidAttributeValueException ex) {
+ LOGGER.error("This should not be happening!");
+ }
+ }
+ }
+ return this.links.addAll(links);
+ }
+
+ /**
+ * Returns resources' links which kind has given term.
+ *
+ * @param term term of link's kind
+ * @return resource's link
+ */
+ public Set<Link> getLinks(String term) {
+ Set<Link> set = new HashSet<>();
+ for (Link link : links.getSet()) {
+ if (link.getKind().getTerm().equals(term)) {
+ set.add(link);
+ }
+ }
+
+ return set;
+ }
+
+ /**
+ * Returns resources' links which kind has given identifier.
+ *
+ * @param identifier identifier of link's kind
+ * @return resource's link
+ */
+ public Set<Link> getLinks(URI identifier) {
+ String identifierString = identifier.toString();
+ Set<Link> set = new HashSet<>();
+ for (Link link : links.getSet()) {
+ if (link.getKind().getIdentifier().equals(identifierString)) {
+ set.add(link);
+ }
+ }
+
+ return set;
+ }
+
+ /**
+ * Removes link from resource.
+ *
+ * @param link link to be removed
+ * @return true if the removal was successful, false otherwise
+ */
+ public boolean removeLink(Link link) {
+ return links.remove(link);
+ }
+
+ /**
+ * Removes all links from resource.
+ */
+ public void clearLinks() {
+ links.clear();
+ }
+
+ /**
+ * Returns all resource's links in form of set.
+ *
+ * @return all resource's links in form of set
+ */
+ public Set<Link> getLinks() {
+ return links.getSet();
+ }
+
+ /**
+ * Checks whether resource contains given action.
+ *
+ * @param action action to be looked up
+ * @return true is resource contains given action, false otherwise
+ */
+ public boolean containsAction(Action action) {
+ return actions.contains(action);
+ }
+
+ /**
+ * Checks whether resource contains given action.
+ *
+ * @param actionIdentifier identifier of action to be looked up
+ * @return true is resource contains given action, false otherwise
+ */
+ public boolean containsAction(String actionIdentifier) {
+ return actions.contains(actionIdentifier);
+ }
+
+ /**
+ * Adds action to the resource.
+ *
+ * @param action to be added
+ * @return true if addition was successful, false otherwise
+ */
+ public boolean addAction(Action action) {
+ return actions.add(action);
+ }
+
+ /**
+ * Adds actions to the resource.
+ *
+ * @param actions collections of actions to be added
+ * @return true if addition was successful, false otherwise
+ */
+ public boolean addActions(Collection<Action> actions) {
+ return this.actions.addAll(actions);
+ }
+
+ /**
+ * Returns resource's action.
+ *
+ * @param actionIdentifier identifier of requested action
+ * @return resource's action
+ */
+ public Action getAction(String actionIdentifier) {
+ return actions.get(actionIdentifier);
+ }
+
+ /**
+ * Removes action from resource.
+ *
+ * @param action action to be removed
+ * @return true if the removal was successful, false otherwise
+ */
+ public boolean removeAction(Action action) {
+ return actions.remove(action);
+ }
+
+ /**
+ * Removes all actions from resource.
+ */
+ public void clearActions() {
+ actions.clear();
+ }
+
+ /**
+ * Returns all resource's actions in form of set.
+ *
+ * @return all resource's actions in form of set
+ */
+ public Set<Action> getActions() {
+ return actions.getSet();
+ }
+
+ /**
+ * Returns resource's location.
+ *
+ * @return resource's location
+ */
+ public String getLocation() {
+ return getKind().getLocation().toString() + getId();
+ }
+
+ /**
+ * Returns resource's default identifier
+ * 'http://schemas.ogf.org/occi/core#resource'
+ *
+ * @return resource's default identifier
+ */
+ @Override
+ public String getDefaultKindIdentifier() {
+ return KIND_IDENTIFIER_DEFAULT;
+ }
+
+ public static List<Attribute> getDefaultAttributes() {
+ List<Attribute> list = new ArrayList<>();
+ list.addAll(Entity.getDefaultAttributes());
+ list.add(new Attribute(SUMMARY_ATTRIBUTE_NAME, false, false));
+
+ return list;
+ }
+
+ public static Kind getDefaultKind() {
+ Kind kind = new Kind(SCHEME_DEFAULT, TERM_DEFAULT, "Resource", URI.create("/resource/"), Resource.getDefaultAttributes());
+ return kind;
+ }
+
+ /**
+ * Resturns string representation of resource
+ *
+ * @see Object#toString()
+ * @return string representation of resource
+ */
+ @Override
+ public String toString() {
+ return "Resource{" + "class=" + getClass().getName() + ", id=" + getId() + ", kind=" + getKind() + ", title=" + getTitle() + ", mixins=" + getMixins() + ", attributes=" + getAttributes() + ", links" + links + '}';
+ }
+
+ /**
+ * Returns a plain text representation of resource instance as described in
+ * OCCI standard.
+ *
+ * @return plain text representation of resource instance
+ * @throws RenderingException
+ */
+ @Override
+ public String toText() throws RenderingException {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append(getKind().toText(false));
+
+ List<Mixin> mixinList = new ArrayList<>(getMixins());
+ Collections.sort(mixinList);
+ for (Mixin m : mixinList) {
+ sb.append("\n");
+ sb.append(m.toText(false));
+ }
+
+ String attributesString = attributesToPrefixText();
+ if (!attributesString.isEmpty()) {
+ sb.append("\n");
+ sb.append(attributesString);
+ }
+
+ List<Link> linkList = new ArrayList<>(getLinks());
+ Collections.sort(linkList);
+ for (Link l : linkList) {
+ sb.append("\n");
+ sb.append(l.toInlineText());
+ }
+
+ List<Action> actionList = new ArrayList<>(getActions());
+ Collections.sort(actionList);
+ for (Action a : actionList) {
+ sb.append("\n");
+ sb.append(a.toText(getKind().getLocation().toString() + getId()));
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Returns a occi text representation of resource instance as described in
+ * OCCI standard in form of headers.
+ *
+ * @return plain text representation of resource instance
+ * @throws RenderingException
+ */
+ @Override
+ public Headers toHeaders() throws RenderingException {
+ Headers headers = new Headers();
+
+ headers.putAll(getKind().toHeaders(false));
+
+ List<Mixin> mixinList = new ArrayList<>(getMixins());
+ Collections.sort(mixinList);
+ for (Mixin m : mixinList) {
+ Headers mixinHeaders = m.toHeaders(false);
+ for (String name : mixinHeaders.keySet()) {
+ for (String value : mixinHeaders.get(name)) {
+ headers.add(name, value);
+ }
+ }
+ }
+
+ Headers attributeHeaders = attributesToHeaders();
+ if (!attributeHeaders.isEmpty()) {
+ headers.putAll(attributeHeaders);
+ }
+
+ List<Link> linkList = new ArrayList<>(getLinks());
+ Collections.sort(linkList);
+ for (Link l : linkList) {
+ Headers linkHeaders = l.toInlineHeaders();
+ for (String name : linkHeaders.keySet()) {
+ for (String value : linkHeaders.get(name)) {
+ headers.add(name, value);
+ }
+ }
+ }
+
+ List<Action> actionList = new ArrayList<>(getActions());
+ Collections.sort(actionList);
+ for (Action a : actionList) {
+ Headers actionHeaders = a.toHeaders(getKind().getLocation().toString() + getId());
+ for (String name : actionHeaders.keySet()) {
+ for (String value : actionHeaders.get(name)) {
+ headers.add(name, value);
+ }
+ }
+ }
+
+ return headers;
+ }
+
+ /**
+ * Returns a JSON representation of resource instance as described in OCCI
+ * standard. NOT IMPLEMENTED YET!
+ *
+ * @return JSON representation of resource instance
+ */
+ @Override
+ public String toJSON() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.exception;
+
+/**
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class AmbiguousIdentifierException extends Exception {
+
+ public AmbiguousIdentifierException(String message) {
+ super(message);
+ }
+
+ public AmbiguousIdentifierException(String message, Throwable ex) {
+ super(message, ex);
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.exception;
+
+/**
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class InvalidAttributeException extends Exception {
+
+ public InvalidAttributeException(String message) {
+ super(message);
+ }
+
+ public InvalidAttributeException(String message, Throwable ex) {
+ super(message, ex);
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.exception;
+
+/**
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class InvalidAttributeValueException extends Exception {
+
+ public InvalidAttributeValueException(String message) {
+ super(message);
+ }
+
+ public InvalidAttributeValueException(String message, Throwable ex) {
+ super(message, ex);
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.exception;
+
+/**
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class ParsingException extends Exception {
+
+ public ParsingException(String message) {
+ super(message);
+ }
+
+ public ParsingException(String message, Throwable ex) {
+ super(message, ex);
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.exception;
+
+/**
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class RenderingException extends Exception {
+
+ public RenderingException(String message) {
+ super(message);
+ }
+
+ public RenderingException(String message, Throwable ex) {
+ super(message, ex);
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.infrastructure;
+
+import cz.cesnet.cloud.occi.Model;
+import cz.cesnet.cloud.occi.core.Attribute;
+import cz.cesnet.cloud.occi.core.Category;
+import cz.cesnet.cloud.occi.core.Kind;
+import cz.cesnet.cloud.occi.core.Resource;
+import cz.cesnet.cloud.occi.exception.InvalidAttributeValueException;
+import cz.cesnet.cloud.occi.infrastructure.enumeration.ComputeState;
+import cz.cesnet.cloud.occi.infrastructure.enumeration.Architecture;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class representing an OCCI Compute
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class Compute extends Resource {
+
+ public static final String ARCHITECTURE_ATTRIBUTE_NAME = "occi.compute.architecture";
+ public static final String CORES_ATTRIBUTE_NAME = "occi.compute.cores";
+ public static final String HOSTNAME_ATTRIBUTE_NAME = "occi.compute.hostname";
+ public static final String SPEED_ATTRIBUTE_NAME = "occi.compute.speed";
+ public static final String MEMORY_ATTRIBUTE_NAME = "occi.compute.memory";
+ public static final String STATE_ATTRIBUTE_NAME = "occi.compute.state";
+ public static final URI SCHEME_DEFAULT = Category.SCHEME_INFRASTRUCTURE_DEFAULT;
+ public static final String TERM_DEFAULT = "compute";
+ public static final String KIND_IDENTIFIER_DEFAULT = SCHEME_DEFAULT + TERM_DEFAULT;
+
+ /**
+ * Constructor.
+ *
+ * @param id occi.core.id attribute. Cannot be null.
+ * @param kind compute's kind. Cannot be null.
+ * @param title occi.core.title attribute
+ * @param model compute's model
+ * @param summary compute's summary
+ * @throws InvalidAttributeValueException in case of invalid id, title or
+ * summary value
+ */
+ public Compute(String id, Kind kind, String title, Model model, String summary) throws InvalidAttributeValueException {
+ super(id, kind, title, model, summary);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param id occi.core.id attribute. Cannot be null.
+ * @param kind compute's kind. Cannot be null.
+ * @throws InvalidAttributeValueException in case of invalid id value
+ */
+ public Compute(String id, Kind kind) throws InvalidAttributeValueException {
+ super(id, kind);
+ }
+
+ /**
+ * Returns compute's state (attribute occi.compute.state).
+ *
+ * @return compute's state
+ */
+ public String getState() {
+ return getValue(STATE_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets compute's state.
+ *
+ * @param state compute's state. Cannot be null.
+ * @throws InvalidAttributeValueException in case state's value is invalid
+ */
+ public void setState(ComputeState state) throws InvalidAttributeValueException {
+ if (state == null) {
+ throw new NullPointerException("state cannot be null");
+ }
+ addAttribute(STATE_ATTRIBUTE_NAME, state.toString());
+ }
+
+ /**
+ * Sets compute's state.
+ *
+ * @param stateName compute's state. Cannot be null.
+ * @throws InvalidAttributeValueException in case state's value is invalid
+ */
+ public void setState(String stateName) throws InvalidAttributeValueException {
+ addAttribute(STATE_ATTRIBUTE_NAME, stateName);
+ }
+
+ /**
+ * Returns compute's memory (attribute occi.compute.memory).
+ *
+ * @return compute's memory
+ */
+ public String getMemory() {
+ return getValue(MEMORY_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets compute's memory.
+ *
+ * @param memory compute's memory
+ * @throws InvalidAttributeValueException in case value of memory is invalid
+ */
+ public void setMemory(float memory) throws InvalidAttributeValueException {
+ addAttribute(MEMORY_ATTRIBUTE_NAME, String.valueOf(memory));
+ }
+
+ /**
+ * Sets compute's memory.
+ *
+ * @param memory compute's memory
+ * @throws InvalidAttributeValueException in case value of memory is invalid
+ */
+ public void setMemory(String memory) throws InvalidAttributeValueException {
+ addAttribute(MEMORY_ATTRIBUTE_NAME, memory);
+ }
+
+ /**
+ * Returns compute's speed (attribute occi.compute.speed).
+ *
+ * @return compute's speed
+ */
+ public String getSpeed() {
+ return getValue(SPEED_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets compute's speed.
+ *
+ * @param speed compute's speed
+ * @throws InvalidAttributeValueException in case value of speed is invalid
+ */
+ public void setSpeed(float speed) throws InvalidAttributeValueException {
+ addAttribute(SPEED_ATTRIBUTE_NAME, String.valueOf(speed));
+ }
+
+ /**
+ * Sets compute's speed.
+ *
+ * @param speed compute's speed
+ * @throws InvalidAttributeValueException in case value of speed is invalid
+ */
+ public void setSpeed(String speed) throws InvalidAttributeValueException {
+ addAttribute(SPEED_ATTRIBUTE_NAME, speed);
+ }
+
+ /**
+ * Returns compute's hostname (attribute occi.compute.hostname).
+ *
+ * @return compute's hostname
+ */
+ public String getHostname() {
+ return getValue(HOSTNAME_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets compute's hostname.
+ *
+ * @param hostname compute's hostname
+ * @throws InvalidAttributeValueException in case value of hostname is
+ * invalid
+ */
+ public void setHostname(String hostname) throws InvalidAttributeValueException {
+ addAttribute(HOSTNAME_ATTRIBUTE_NAME, hostname);
+ }
+
+ /**
+ * Returns number of compute's cores (attribute occi.compute.cores).
+ *
+ * @return number of compute's cores
+ */
+ public String getCores() {
+ return getValue(CORES_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets number of compute's cores.
+ *
+ * @param cores number of compute's cores
+ * @throws InvalidAttributeValueException in case value of cores is invalid
+ */
+ public void setCores(int cores) throws InvalidAttributeValueException {
+ addAttribute(CORES_ATTRIBUTE_NAME, String.valueOf(cores));
+ }
+
+ /**
+ * Sets number of compute's cores.
+ *
+ * @param cores number of compute's cores
+ * @throws InvalidAttributeValueException in case value of cores is invalid
+ */
+ public void setCores(String cores) throws InvalidAttributeValueException {
+ addAttribute(CORES_ATTRIBUTE_NAME, cores);
+ }
+
+ /**
+ * Returns compute's architecture (attribute occi.compute.architecture).
+ *
+ * @return compute's architecture
+ */
+ public String getArchitecture() {
+ return getValue(ARCHITECTURE_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets compute's architecture
+ *
+ * @param architecture compute's architecture. Cannot be null.
+ * @throws InvalidAttributeValueException in case value of architecture is
+ * invalid
+ */
+ public void setArchitecture(Architecture architecture) throws InvalidAttributeValueException {
+ if (architecture == null) {
+ throw new NullPointerException("architecture cannot be null");
+ }
+ addAttribute(ARCHITECTURE_ATTRIBUTE_NAME, architecture.toString());
+ }
+
+ /**
+ * Sets compute's architecture
+ *
+ * @param architectureName compute's architecture
+ * @throws InvalidAttributeValueException in case value of architecture is
+ * invalid
+ */
+ public void setArchitecture(String architectureName) throws InvalidAttributeValueException {
+ addAttribute(ARCHITECTURE_ATTRIBUTE_NAME, architectureName);
+ }
+
+ /**
+ * Returns compute's default identifier
+ * 'http://schemas.ogf.org/occi/infrastructure#compute'
+ *
+ * @return compute's default identifier
+ */
+ @Override
+ public String getDefaultKindIdentifier() {
+ return KIND_IDENTIFIER_DEFAULT;
+ }
+
+ /**
+ * Returns compute's default attributes. For Compute class those are
+ * attributes occi.compute.architecture, occi.compute.cores,
+ * occi.compute.hostname, occi.compute.speed, occi.compute.memory and
+ * occi.compute.state.
+ *
+ * @return list of compute's default attributes
+ */
+ public static List<Attribute> getDefaultAttributes() {
+ List<Attribute> list = new ArrayList<>();
+ list.addAll(Resource.getDefaultAttributes());
+ list.add(new Attribute(ARCHITECTURE_ATTRIBUTE_NAME, false, false));
+ list.add(new Attribute(CORES_ATTRIBUTE_NAME, false, false));
+ list.add(new Attribute(HOSTNAME_ATTRIBUTE_NAME, false, false));
+ list.add(new Attribute(SPEED_ATTRIBUTE_NAME, false, false));
+ list.add(new Attribute(MEMORY_ATTRIBUTE_NAME, false, false));
+ list.add(new Attribute(STATE_ATTRIBUTE_NAME, true, true));
+
+ return list;
+ }
+
+ /**
+ * Returns compute's default kind instance.
+ *
+ * @return compute's default kind
+ */
+ public static Kind getDefaultKind() {
+ Kind kind = new Kind(SCHEME_DEFAULT, TERM_DEFAULT, "Compute Resource", URI.create("/compute/"), Compute.getDefaultAttributes());
+ return kind;
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.infrastructure;
+
+import cz.cesnet.cloud.occi.Model;
+import cz.cesnet.cloud.occi.core.Attribute;
+import cz.cesnet.cloud.occi.core.Kind;
+import cz.cesnet.cloud.occi.core.Mixin;
+import cz.cesnet.cloud.occi.exception.InvalidAttributeValueException;
+import cz.cesnet.cloud.occi.infrastructure.enumeration.Allocation;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class representing an OCCI IPNetwork
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class IPNetwork extends Network {
+
+ public static final String ADDRESS_ATTRIBUTE_NAME = "occi.network.address";
+ public static final String GATEWAY_ATTRIBUTE_NAME = "occi.network.gateway";
+ public static final String ALLOCATION_ATTRIBUTE_NAME = "occi.network.allocation";
+ public static final URI SCHEME_DEFAULT = URI.create("http://schemas.ogf.org/occi/infrastructure/network#");
+ public static final String TERM_DEFAULT = "ipnetwork";
+ public static final String MIXIN_IDENTIFIER_DEFAULT = SCHEME_DEFAULT + TERM_DEFAULT;
+
+ /**
+ * Constructor.
+ *
+ * @param id occi.core.id attribute. Cannot be null.
+ * @param kind ipnetwork's kind. Cannot be null.
+ * @param title occi.core.title attribute
+ * @param model ipnetwork's model
+ * @param summary ipnetwork's summary
+ * @throws InvalidAttributeValueException in case of invalid id, title or
+ * summary value
+ */
+ public IPNetwork(String id, Kind kind, String title, Model model, String summary) throws InvalidAttributeValueException {
+ super(id, kind, title, model, summary);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param id occi.core.id attribute. Cannot be null.
+ * @param kind ipnetwork's kind. Cannot be null.
+ * @throws InvalidAttributeValueException in case of invalid id value
+ */
+ public IPNetwork(String id, Kind kind) throws InvalidAttributeValueException {
+ super(id, kind);
+ }
+
+ /**
+ * Returns ipnetwork's address (attribute occi.network.address).
+ *
+ * @return ipnetwork's address
+ */
+ public String getAddress() {
+ return getValue(ADDRESS_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets ipnetwork's address.
+ *
+ * @param address ipnetwork's address
+ * @throws InvalidAttributeValueException in case value for address is
+ * invalid
+ */
+ public void setAddress(String address) throws InvalidAttributeValueException {
+ addAttribute(ADDRESS_ATTRIBUTE_NAME, address);
+ }
+
+ /**
+ * Returns ipnetwork's gateway (attribute occi.network.gateway).
+ *
+ * @return ipnetwork's gateway
+ */
+ public String getGateway() {
+ return getValue(GATEWAY_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets ipnetwork's gateway
+ *
+ * @param gateway ipnetwork's gateway
+ * @throws InvalidAttributeValueException in case value for gateway is
+ * invalid
+ */
+ public void setGateway(String gateway) throws InvalidAttributeValueException {
+ addAttribute(GATEWAY_ATTRIBUTE_NAME, gateway);
+ }
+
+ /**
+ * Returns ipnetwork's allocation (attribute occi.network.allocation).
+ *
+ * @return ipnetwork's allocation
+ */
+ public String getAllocation() {
+ return getValue(ALLOCATION_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets ipnetwork's allocation.
+ *
+ * @param allocation ipnetwork's allocation. Cannot be null.
+ * @throws InvalidAttributeValueException in case value for allocation is
+ * invalid
+ */
+ public void setAllocation(Allocation allocation) throws InvalidAttributeValueException {
+ if (allocation == null) {
+ throw new NullPointerException("allocation cannot be null");
+ }
+ addAttribute(ALLOCATION_ATTRIBUTE_NAME, allocation.toString());
+ }
+
+ /**
+ * Sets ipnetwork's allocation.
+ *
+ * @param allocationName ipnetwork's allocation. Cannot be null.
+ * @throws InvalidAttributeValueException in case value for allocation is
+ * invalid
+ */
+ public void setAllocation(String allocationName) throws InvalidAttributeValueException {
+ addAttribute(ALLOCATION_ATTRIBUTE_NAME, allocationName);
+ }
+
+ /**
+ * Returns ipnetwork's default identifier
+ * 'http://schemas.ogf.org/occi/infrastructure/network#ipnetworking'
+ *
+ * @return ipnetwork's default identifier
+ */
+ @Override
+ public String getDefaultKindIdentifier() {
+ return MIXIN_IDENTIFIER_DEFAULT;
+ }
+
+ /**
+ * Returns ipnetwork's default attributes. For IPNetwork class those are
+ * attributes occi.network.address, occi.network.gateway and
+ * occi.network.allocation.
+ *
+ * @return list of ipnetwork's default attributes
+ */
+ public static List<Attribute> getDefaultAttributes() {
+ List<Attribute> list = new ArrayList<>();
+ list.add(new Attribute(ADDRESS_ATTRIBUTE_NAME, false, false));
+ list.add(new Attribute(GATEWAY_ATTRIBUTE_NAME, false, false));
+ list.add(new Attribute(ALLOCATION_ATTRIBUTE_NAME, false, false));
+
+ return list;
+ }
+
+ /**
+ * Returns ipnetwork's default mixin instance.
+ *
+ * @return ipnetwork's default mixin
+ */
+ public static Mixin getDefaultMixin() {
+ Mixin mixin = new Mixin(SCHEME_DEFAULT, TERM_DEFAULT, "IP Network Mixin", URI.create("/mixins/ipnetwork/"), IPNetwork.getDefaultAttributes());
+ return mixin;
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.infrastructure;
+
+import cz.cesnet.cloud.occi.Model;
+import cz.cesnet.cloud.occi.core.Attribute;
+import cz.cesnet.cloud.occi.core.Kind;
+import cz.cesnet.cloud.occi.core.Mixin;
+import cz.cesnet.cloud.occi.exception.InvalidAttributeValueException;
+import cz.cesnet.cloud.occi.infrastructure.enumeration.Allocation;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class representing an OCCI IPNetworkInterface
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class IPNetworkInterface extends NetworkInterface {
+
+ public static final String ADDRESS_ATTRIBUTE_NAME = "occi.networkinterface.address";
+ public static final String GATEWAY_ATTRIBUTE_NAME = "occi.networkinterface.gateway";
+ public static final String ALLOCATION_ATTRIBUTE_NAME = "occi.networkinterface.allocation";
+ public static final URI SCHEME_DEFAULT = URI.create("http://schemas.ogf.org/occi/infrastructure/networkinterface#");
+ public static final String TERM_DEFAULT = "ipnetworkinterface";
+ public static final String MIXIN_IDENTIFIER_DEFAULT = SCHEME_DEFAULT + TERM_DEFAULT;
+
+ /**
+ * Constructor.
+ *
+ * @param id occi.core.id attribute. Cannot be null.
+ * @param kind ipnetwork interface's kind. Cannot be null.
+ * @param title occi.core.title attribute
+ * @param model network interface's model
+ * @throws InvalidAttributeValueException in case of invalid id or title
+ * value
+ */
+ public IPNetworkInterface(String id, Kind kind, String title, Model model) throws InvalidAttributeValueException {
+ super(id, kind, title, model);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param id occi.core.id attribute. Cannot be null.
+ * @param kind ipnetwork interface's kind. Cannot be null.
+ * @throws InvalidAttributeValueException in case of invalid id value
+ */
+ public IPNetworkInterface(String id, Kind kind) throws InvalidAttributeValueException {
+ super(id, kind);
+ }
+
+ /**
+ * Returns ipnetwork interface's address (attribute
+ * occi.networkinterface.address).
+ *
+ * @return ipnetwork interface's address
+ */
+ public String getAddress() {
+ return getValue(ADDRESS_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets ipnetwork interface's address.
+ *
+ * @param address ipnetwork interface's address
+ * @throws InvalidAttributeValueException in case value for address is
+ * invalid
+ */
+ public void setAddress(String address) throws InvalidAttributeValueException {
+ addAttribute(ADDRESS_ATTRIBUTE_NAME, address);
+ }
+
+ /**
+ * Returns ipnetwork interface's gateway (attribute
+ * occi.networkinterface.gateway).
+ *
+ * @return ipnetwork interface's gateway
+ */
+ public String getGateway() {
+ return getValue(GATEWAY_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets ipnetwork interface's gateway
+ *
+ * @param gateway ipnetwork interface's gateway
+ * @throws InvalidAttributeValueException in case value for gateway is
+ * invalid
+ */
+ public void setGateway(String gateway) throws InvalidAttributeValueException {
+ addAttribute(GATEWAY_ATTRIBUTE_NAME, gateway);
+ }
+
+ /**
+ * Returns ipnetwork interface's allocation (attribute
+ * occi.networkinterface.allocation).
+ *
+ * @return ipnetwork interface's allocation
+ */
+ public String getAllocation() {
+ return getValue(ALLOCATION_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets ipnetwork interface's allocation.
+ *
+ * @param allocation ipnetwork interface's allocation. Cannot be null.
+ * @throws InvalidAttributeValueException in case value for allocation is
+ * invalid
+ */
+ public void setAllocation(Allocation allocation) throws InvalidAttributeValueException {
+ if (allocation == null) {
+ throw new NullPointerException("allocation cannot be null");
+ }
+ addAttribute(ALLOCATION_ATTRIBUTE_NAME, allocation.toString());
+ }
+
+ /**
+ * Sets ipnetwork interface's allocation.
+ *
+ * @param allocationName ipnetwork interface's allocation. Cannot be null.
+ * @throws InvalidAttributeValueException in case value for allocation is
+ * invalid
+ */
+ public void setAllocation(String allocationName) throws InvalidAttributeValueException {
+ addAttribute(ALLOCATION_ATTRIBUTE_NAME, allocationName);
+ }
+
+ /**
+ * Returns ipnetworkinterface's default identifier
+ * 'http://schemas.ogf.org/occi/infrastructure/networkinterface#ipnetworkinterface'
+ *
+ * @return ipnetworkinterface's default identifier
+ */
+ @Override
+ public String getDefaultKindIdentifier() {
+ return MIXIN_IDENTIFIER_DEFAULT;
+ }
+
+ /**
+ * Returns ipnetworkinterface's default attributes. For IPNetworkInterface
+ * class those are attributes occi.networkinterface.address,
+ * occi.networkinterface.gateway and occi.networkinterface.allocation.
+ *
+ * @return list of ipnetworkinterface's default attributes
+ */
+ public static List<Attribute> getDefaultAttributes() {
+ List<Attribute> list = new ArrayList<>();
+ list.add(new Attribute(ADDRESS_ATTRIBUTE_NAME, true, false));
+ list.add(new Attribute(GATEWAY_ATTRIBUTE_NAME, false, false));
+ list.add(new Attribute(ALLOCATION_ATTRIBUTE_NAME, true, false));
+
+ return list;
+ }
+
+ /**
+ * Returns ipnetworkinterface's default mixin instance.
+ *
+ * @return ipnetworkinterface's default mixin
+ */
+ public static Mixin getDefaultMixin() {
+ Mixin mixin = new Mixin(SCHEME_DEFAULT, TERM_DEFAULT, "IP Networkinterface Mixin", URI.create("/mixins/ipnetworkinterface/"), IPNetworkInterface.getDefaultAttributes());
+ return mixin;
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.infrastructure;
+
+import cz.cesnet.cloud.occi.Model;
+import cz.cesnet.cloud.occi.core.Attribute;
+import cz.cesnet.cloud.occi.core.Category;
+import cz.cesnet.cloud.occi.core.Kind;
+import cz.cesnet.cloud.occi.core.Resource;
+import cz.cesnet.cloud.occi.exception.InvalidAttributeValueException;
+import cz.cesnet.cloud.occi.infrastructure.enumeration.NetworkState;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class representing an OCCI Network
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class Network extends Resource {
+
+ public static final String VLAN_ATTRIBUTE_NAME = "occi.network.vlan";
+ public static final String LABEL_ATTRIBUTE_NAME = "occi.network.label";
+ public static final String STATE_ATTRIBUTE_NAME = "occi.network.state";
+ public static final URI SCHEME_DEFAULT = Category.SCHEME_INFRASTRUCTURE_DEFAULT;
+ public static final String TERM_DEFAULT = "network";
+ public static final String KIND_IDENTIFIER_DEFAULT = SCHEME_DEFAULT + TERM_DEFAULT;
+
+ /**
+ * Constructor.
+ *
+ * @param id occi.core.id attribute. Cannot be null.
+ * @param kind network's kind. Cannot be null.
+ * @param title occi.core.title attribute
+ * @param model network's model
+ * @param summary network's summary
+ * @throws InvalidAttributeValueException in case of invalid id, title or
+ * summary value
+ */
+ public Network(String id, Kind kind, String title, Model model, String summary) throws InvalidAttributeValueException {
+ super(id, kind, title, model, summary);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param id occi.core.id attribute. Cannot be null.
+ * @param kind network's kind. Cannot be null.
+ * @throws InvalidAttributeValueException in case of invalid id value
+ */
+ public Network(String id, Kind kind) throws InvalidAttributeValueException {
+ super(id, kind);
+ }
+
+ /**
+ * Returns network's vlan number (attribute occi.network.vlan).
+ *
+ * @return network's vlan number
+ */
+ public String getVlan() {
+ return getValue(VLAN_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets network's vlan number.
+ *
+ * @param vlan network's vlan number
+ * @throws InvalidAttributeValueException in case value for vlan is invalid
+ */
+ public void setVlan(int vlan) throws InvalidAttributeValueException {
+ addAttribute(VLAN_ATTRIBUTE_NAME, String.valueOf(vlan));
+ }
+
+ /**
+ * Sets network's vlan number.
+ *
+ * @param vlan network's vlan number
+ * @throws InvalidAttributeValueException in case value for vlan is invalid
+ */
+ public void setVlan(String vlan) throws InvalidAttributeValueException {
+ addAttribute(VLAN_ATTRIBUTE_NAME, vlan);
+ }
+
+ /**
+ * Returns network's label (attribute occi.network.label).
+ *
+ * @return network's label
+ */
+ public String getLabel() {
+ return getValue(LABEL_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets network's label.
+ *
+ * @param label network's label
+ * @throws InvalidAttributeValueException in case value for label is invalid
+ */
+ public void setLabel(String label) throws InvalidAttributeValueException {
+ addAttribute(LABEL_ATTRIBUTE_NAME, label);
+ }
+
+ /**
+ * Returns network's state (attribute occi.network.state).
+ *
+ * @return network's state
+ */
+ public String getState() {
+ return getValue(STATE_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets network's state.
+ *
+ * @param state network's state. Cannot be null.
+ * @throws InvalidAttributeValueException in case value for state is invalid
+ */
+ public void setState(NetworkState state) throws InvalidAttributeValueException {
+ if (state == null) {
+ throw new NullPointerException("state cannot be null");
+ }
+ addAttribute(STATE_ATTRIBUTE_NAME, state.toString());
+ }
+
+ /**
+ * Sets network's state.
+ *
+ * @param stateName network's state
+ * @throws InvalidAttributeValueException in case value for state is invalid
+ */
+ public void setState(String stateName) throws InvalidAttributeValueException {
+ addAttribute(STATE_ATTRIBUTE_NAME, stateName);
+ }
+
+ /**
+ * Returns network's default identifier
+ * 'http://schemas.ogf.org/occi/infrastructure#network'
+ *
+ * @return network's default identifier
+ */
+ @Override
+ public String getDefaultKindIdentifier() {
+ return KIND_IDENTIFIER_DEFAULT;
+ }
+
+ /**
+ * Returns network's default attributes. For Network class those are
+ * attributes occi.network.vlan, occi.network.label, occi.network.state.
+ *
+ * @return list of network's default attributes
+ */
+ public static List<Attribute> getDefaultAttributes() {
+ List<Attribute> list = new ArrayList<>();
+ list.addAll(Resource.getDefaultAttributes());
+ list.add(new Attribute(VLAN_ATTRIBUTE_NAME, false, false));
+ list.add(new Attribute(LABEL_ATTRIBUTE_NAME, false, false));
+ list.add(new Attribute(STATE_ATTRIBUTE_NAME, true, true));
+
+ return list;
+ }
+
+ /**
+ * Returns network's default kind instance.
+ *
+ * @return network's default kind
+ */
+ public static Kind getDefaultKind() {
+ Kind kind = new Kind(SCHEME_DEFAULT, TERM_DEFAULT, "Network Resource", URI.create("/network/"), Network.getDefaultAttributes());
+ return kind;
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.infrastructure;
+
+import cz.cesnet.cloud.occi.Model;
+import cz.cesnet.cloud.occi.core.Attribute;
+import cz.cesnet.cloud.occi.core.Category;
+import cz.cesnet.cloud.occi.core.Kind;
+import cz.cesnet.cloud.occi.core.Link;
+import cz.cesnet.cloud.occi.exception.InvalidAttributeValueException;
+import cz.cesnet.cloud.occi.infrastructure.enumeration.NetworkState;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class representing an OCCI NetworkInterface
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class NetworkInterface extends Link {
+
+ public static final String INTERFACE_ATTRIBUTE_NAME = "occi.networkinterface.interface";
+ public static final String MAC_ATTRIBUTE_NAME = "occi.networkinterface.mac";
+ public static final String STATE_ATTRIBUTE_NAME = "occi.networkinterface.state";
+ public static final URI SCHEME_DEFAULT = Category.SCHEME_INFRASTRUCTURE_DEFAULT;
+ public static final String TERM_DEFAULT = "networkinterface";
+ public static final String KIND_IDENTIFIER_DEFAULT = SCHEME_DEFAULT + TERM_DEFAULT;
+
+ /**
+ * Constructor.
+ *
+ * @param id occi.core.id attribute. Cannot be null.
+ * @param kind network interface's kind. Cannot be null.
+ * @param title occi.core.title attribute
+ * @param model network interface's model
+ * @throws InvalidAttributeValueException in case of invalid id or title
+ * value
+ */
+ public NetworkInterface(String id, Kind kind, String title, Model model) throws InvalidAttributeValueException {
+ super(id, kind, title, model);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param id occi.core.id attribute. Cannot be null.
+ * @param kind network interface's kind. Cannot be null.
+ * @throws InvalidAttributeValueException in case of invalid id value
+ */
+ public NetworkInterface(String id, Kind kind) throws InvalidAttributeValueException {
+ super(id, kind);
+ }
+
+ /**
+ * Returns network interface's interface (attribute
+ * occi.networkinterface.interface).
+ *
+ * @return network interface's interface
+ */
+ public String getNetworkInterface() {
+ return getValue(INTERFACE_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets network interface's interface
+ *
+ * @param networkInterface network interface's interface
+ * @throws InvalidAttributeValueException in case value for interface is
+ * invalid
+ */
+ public void setNetworkInterface(String networkInterface) throws InvalidAttributeValueException {
+ addAttribute(INTERFACE_ATTRIBUTE_NAME, networkInterface);
+ }
+
+ /**
+ * Returns network interface's mac address.
+ *
+ * @return network interface's mac address
+ */
+ public String getMac() {
+ return getValue(MAC_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets network interface's mac address
+ *
+ * @param mac network interface's mac address
+ * @throws InvalidAttributeValueException in case value for mac address is
+ * invalid
+ */
+ public void setMac(String mac) throws InvalidAttributeValueException {
+ addAttribute(MAC_ATTRIBUTE_NAME, mac);
+ }
+
+ /**
+ * Returns network interface's state.
+ *
+ * @return network interface's state
+ */
+ public String getState() {
+ return getValue(STATE_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets network interface's state.
+ *
+ * @param state network interface's state. Cannot be null.
+ * @throws InvalidAttributeValueException in case value for state is invalid
+ */
+ public void setState(NetworkState state) throws InvalidAttributeValueException {
+ if (state == null) {
+ throw new NullPointerException("state cannot be null");
+ }
+ addAttribute(STATE_ATTRIBUTE_NAME, state.toString());
+ }
+
+ /**
+ * Sets network interface's state.
+ *
+ * @param stateName network interface's state. Cannot be null.
+ * @throws InvalidAttributeValueException in case value for state is invalid
+ */
+ public void setState(String stateName) throws InvalidAttributeValueException {
+ addAttribute(STATE_ATTRIBUTE_NAME, stateName);
+ }
+
+ /**
+ * Returns networkinterface's default identifier
+ * 'http://schemas.ogf.org/occi/infrastructure#networkinterface'
+ *
+ * @return networkinterface's default identifier
+ */
+ @Override
+ public String getDefaultKindIdentifier() {
+ return KIND_IDENTIFIER_DEFAULT;
+ }
+
+ /**
+ * Returns networkinterface's default attributes. For NetworkInterface class
+ * those are attributes occi.networkinterface.interface,
+ * occi.networkinterface.mac and occi.networkinterface.state.
+ *
+ * @return list of networkinterface's default attributes
+ */
+ public static List<Attribute> getDefaultAttributes() {
+ List<Attribute> list = new ArrayList<>();
+ list.addAll(Link.getDefaultAttributes());
+ list.add(new Attribute(INTERFACE_ATTRIBUTE_NAME, true, true));
+ list.add(new Attribute(MAC_ATTRIBUTE_NAME, true, false));
+ list.add(new Attribute(STATE_ATTRIBUTE_NAME, true, true));
+
+ return list;
+ }
+
+ /**
+ * Returns networkinterface's default kind instance.
+ *
+ * @return networkinterface's default kind
+ */
+ public static Kind getDefaultKind() {
+ Kind kind = new Kind(SCHEME_DEFAULT, TERM_DEFAULT, "Networkinterface", URI.create("/networkinterface/"), NetworkInterface.getDefaultAttributes());
+ return kind;
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.infrastructure;
+
+import cz.cesnet.cloud.occi.Model;
+import cz.cesnet.cloud.occi.core.Attribute;
+import cz.cesnet.cloud.occi.core.Category;
+import cz.cesnet.cloud.occi.core.Kind;
+import cz.cesnet.cloud.occi.core.Resource;
+import cz.cesnet.cloud.occi.exception.InvalidAttributeValueException;
+import cz.cesnet.cloud.occi.infrastructure.enumeration.StorageState;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class representing an OCCI Storage.
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class Storage extends Resource {
+
+ public static final String SIZE_ATTRIBUTE_NAME = "occi.storage.size";
+ public static final String STATE_ATTRIBUTE_NAME = "occi.storage.state";
+ public static final URI SCHEME_DEFAULT = Category.SCHEME_INFRASTRUCTURE_DEFAULT;
+ public static final String TERM_DEFAULT = "storage";
+ public static final String KIND_IDENTIFIER_DEFAULT = SCHEME_DEFAULT + TERM_DEFAULT;
+
+ /**
+ * Constructor.
+ *
+ * @param id occi.core.id attribute. Cannot be null.
+ * @param kind storage's kind. Cannot be null.
+ * @param title occi.core.title attribute
+ * @param model storage's model
+ * @param summary storage's summary
+ * @throws InvalidAttributeValueException in case of invalid id, title or
+ * summary value
+ */
+ public Storage(String id, Kind kind, String title, Model model, String summary) throws InvalidAttributeValueException {
+ super(id, kind, title, model, summary);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param id occi.core.id attribute. Cannot be null.
+ * @param kind storage's kind. Cannot be null.
+ * @throws InvalidAttributeValueException in case of invalid id value
+ */
+ public Storage(String id, Kind kind) throws InvalidAttributeValueException {
+ super(id, kind);
+ }
+
+ /**
+ * Returns storage's size (attribute occi.storage.size).
+ *
+ * @return storage's size
+ */
+ public String getSize() {
+ return getValue(SIZE_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets storage's size.
+ *
+ * @param size storage's size
+ * @throws InvalidAttributeValueException in case value for size is invalid
+ */
+ public void setSize(float size) throws InvalidAttributeValueException {
+ addAttribute(SIZE_ATTRIBUTE_NAME, String.valueOf(size));
+ }
+
+ /**
+ * Sets storage's size.
+ *
+ * @param size storage's size
+ * @throws InvalidAttributeValueException in case value for size is invalid
+ */
+ public void setSize(String size) throws InvalidAttributeValueException {
+ addAttribute(SIZE_ATTRIBUTE_NAME, size);
+ }
+
+ /**
+ * Returns storage's state (attribute occi.storage.state).
+ *
+ * @return storage's state
+ */
+ public String getState() {
+ return getValue(STATE_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets storage's state.
+ *
+ * @param state storage's state. Cannot be null.
+ * @throws InvalidAttributeValueException in case value for state is invalid
+ */
+ public void setState(StorageState state) throws InvalidAttributeValueException {
+ if (state == null) {
+ throw new NullPointerException("state cannot be null");
+ }
+ addAttribute(STATE_ATTRIBUTE_NAME, state.toString());
+ }
+
+ /**
+ * Sets storage's state.
+ *
+ * @param stateName storage's state
+ * @throws InvalidAttributeValueException in case value for state is invalid
+ */
+ public void setState(String stateName) throws InvalidAttributeValueException {
+ addAttribute(STATE_ATTRIBUTE_NAME, stateName);
+ }
+
+ /**
+ * Returns storage's default scheme
+ * 'http://schemas.ogf.org/occi/infrastructure#'
+ *
+ * @return storage's default scheme
+ */
+ public static URI getSchemeDefault() {
+ return Category.SCHEME_INFRASTRUCTURE_DEFAULT;
+ }
+
+ /**
+ * Returns storage's default term 'storage'.
+ *
+ * @return storage's default term
+ */
+ public static String getTermDefault() {
+ return "storage";
+ }
+
+ /**
+ * Returns storage's default identifier
+ * 'http://schemas.ogf.org/occi/infrastructure#storage'
+ *
+ * @return storage's default identifier
+ */
+ @Override
+ public String getDefaultKindIdentifier() {
+ return KIND_IDENTIFIER_DEFAULT;
+ }
+
+ /**
+ * Returns storage's default attributes. For Storage class those are
+ * attributes occi.storage.size and occi.storage.state.
+ *
+ * @return list of storage's default attributes
+ */
+ public static List<Attribute> getDefaultAttributes() {
+ List<Attribute> list = new ArrayList<>();
+ list.addAll(Resource.getDefaultAttributes());
+ list.add(new Attribute(SIZE_ATTRIBUTE_NAME, true, false));
+ list.add(new Attribute(STATE_ATTRIBUTE_NAME, true, true));
+
+ return list;
+ }
+
+ /**
+ * Returns storage's default kind instance.
+ *
+ * @return storage's default kind
+ */
+ public static Kind getDefaultKind() {
+ Kind kind = new Kind(SCHEME_DEFAULT, TERM_DEFAULT, "Storage Resource", URI.create("/storage/"), Storage.getDefaultAttributes());
+ return kind;
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.infrastructure;
+
+import cz.cesnet.cloud.occi.Model;
+import cz.cesnet.cloud.occi.core.Attribute;
+import cz.cesnet.cloud.occi.core.Category;
+import cz.cesnet.cloud.occi.core.Kind;
+import cz.cesnet.cloud.occi.core.Link;
+import cz.cesnet.cloud.occi.exception.InvalidAttributeValueException;
+import cz.cesnet.cloud.occi.infrastructure.enumeration.StorageLinkState;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class representing an OCCI StorageLink
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class StorageLink extends Link {
+
+ public static final String DEVICE_ID_ATTRIBUTE_NAME = "occi.storagelink.deviceid";
+ public static final String MOUNTPOINT_ATTRIBUTE_NAME = "occi.storagelink.mountpoint";
+ public static final String STATE_ATTRIBUTE_NAME = "occi.storagelink.state";
+ public static final URI SCHEME_DEFAULT = Category.SCHEME_INFRASTRUCTURE_DEFAULT;
+ public static final String TERM_DEFAULT = "storagelink";
+ public static final String KIND_IDENTIFIER_DEFAULT = SCHEME_DEFAULT + TERM_DEFAULT;
+
+ /**
+ * Constructor.
+ *
+ * @param id occi.core.id attribute. Cannot be null.
+ * @param kind storage link's kind. Cannot be null.
+ * @param title occi.core.title attribute
+ * @param model storage link's model
+ * @throws InvalidAttributeValueException in case of invalid id or title
+ * value
+ */
+ public StorageLink(String id, Kind kind, String title, Model model) throws InvalidAttributeValueException {
+ super(id, kind, title, model);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param id occi.core.id attribute. Cannot be null.
+ * @param kind storage link's kind. Cannot be null.
+ * @throws InvalidAttributeValueException in case of invalid id value
+ */
+ public StorageLink(String id, Kind kind) throws InvalidAttributeValueException {
+ super(id, kind);
+ }
+
+ /**
+ * Returns storage link's device id (attribute occi.storagelink.deviceid).
+ *
+ * @return storage link's device id
+ */
+ public String getDeviceId() {
+ return getValue(DEVICE_ID_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets storage link's device id.
+ *
+ * @param id storage link's device id
+ * @throws InvalidAttributeValueException in case value for devide id is
+ * invalid
+ */
+ public void setDeviceId(String id) throws InvalidAttributeValueException {
+ addAttribute(DEVICE_ID_ATTRIBUTE_NAME, id);
+ }
+
+ /**
+ * Returns storage link's mountpoint (attribute
+ * occi.storagelink.mountpoint).
+ *
+ * @return storage link's mountpoint
+ */
+ public String getMountpoint() {
+ return getValue(MOUNTPOINT_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets storage link's mountpoint
+ *
+ * @param mountpoint storage link's mountpoint
+ * @throws InvalidAttributeValueException in case value for moutnpoint is
+ * invalid
+ */
+ public void setMountpoint(String mountpoint) throws InvalidAttributeValueException {
+ addAttribute(MOUNTPOINT_ATTRIBUTE_NAME, mountpoint);
+ }
+
+ /**
+ * Returns storage link's state (attribute occi.storagelink.state).
+ *
+ * @return storage link's state
+ */
+ public String getState() {
+ return getValue(STATE_ATTRIBUTE_NAME);
+ }
+
+ /**
+ * Sets storage link's state.
+ *
+ * @param state storage link's state. Cannot be null.
+ * @throws InvalidAttributeValueException in case value for state is invalid
+ */
+ public void setState(StorageLinkState state) throws InvalidAttributeValueException {
+ if (state == null) {
+ throw new NullPointerException("state cannot be null");
+ }
+ addAttribute(STATE_ATTRIBUTE_NAME, state.toString());
+ }
+
+ /**
+ * Sets storage link's state.
+ *
+ * @param stateName storage link's state
+ * @throws InvalidAttributeValueException in case value for state is invalid
+ */
+ public void setState(String stateName) throws InvalidAttributeValueException {
+ addAttribute(STATE_ATTRIBUTE_NAME, stateName);
+ }
+
+ /**
+ * Returns storagelink's default identifier
+ * 'http://schemas.ogf.org/occi/infrastructure#storagelink'
+ *
+ * @return storagelink's default identifier
+ */
+ @Override
+ public String getDefaultKindIdentifier() {
+ return KIND_IDENTIFIER_DEFAULT;
+ }
+
+ /**
+ * Returns storagelink's default attributes. For StorageLink class those are
+ * attributes occi.storagelink.deviceid, occi.storagelink.mountpoint and
+ * occi.storagelink.state.
+ *
+ * @return list of storagelink's default attributes
+ */
+ public static List<Attribute> getDefaultAttributes() {
+ List<Attribute> list = new ArrayList<>();
+ list.addAll(Storage.getDefaultAttributes());
+ list.add(new Attribute(DEVICE_ID_ATTRIBUTE_NAME, true, false));
+ list.add(new Attribute(MOUNTPOINT_ATTRIBUTE_NAME, false, false));
+ list.add(new Attribute(STATE_ATTRIBUTE_NAME, true, true));
+
+ return list;
+ }
+
+ /**
+ * Returns storagelink's default kind instance.
+ *
+ * @return storagelink's default kind
+ */
+ public static Kind getDefaultKind() {
+ Kind kind = new Kind(SCHEME_DEFAULT, TERM_DEFAULT, "Storage Link", URI.create("/storagelink/"), StorageLink.getDefaultAttributes());
+ return kind;
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.infrastructure.enumeration;
+
+/**
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public enum Allocation {
+
+ DYNAMIC, STATIC;
+
+ @Override
+ public String toString() {
+ return this.name().toLowerCase();
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.infrastructure.enumeration;
+
+/**
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public enum Architecture {
+
+ X_86, X_64;
+
+ @Override
+ public String toString() {
+ return this.name().toLowerCase();
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.infrastructure.enumeration;
+
+/**
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public enum ComputeState {
+
+ ACTIVE, INACTIVE, SUSPENDED;
+
+ @Override
+ public String toString() {
+ return this.name().toLowerCase();
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.infrastructure.enumeration;
+
+/**
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public enum NetworkState {
+
+ ACTIVE, INACTIVE;
+
+ @Override
+ public String toString() {
+ return this.name().toLowerCase();
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.infrastructure.enumeration;
+
+/**
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public enum StorageLinkState {
+
+ ACTIVE, INACTIVE;
+
+ @Override
+ public String toString() {
+ return this.name().toLowerCase();
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.infrastructure.enumeration;
+
+/**
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public enum StorageState {
+
+ ONLINE, OFFLINE, BACKUP, SNAPSHOT, RESIZE, DEGRADED;
+
+ @Override
+ public String toString() {
+ return this.name().toLowerCase();
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.parser;
+
+/**
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public enum CollectionType {
+
+ RESOURCE, LINK, ACTION;
+}
--- /dev/null
+package cz.cesnet.cloud.occi.parser;
+
+import com.sun.net.httpserver.Headers;
+import cz.cesnet.cloud.occi.Collection;
+import cz.cesnet.cloud.occi.Model;
+import cz.cesnet.cloud.occi.exception.ParsingException;
+import java.net.URI;
+import java.util.List;
+
+/**
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class JSONParser implements Parser {
+
+ @Override
+ public Model parseModel(String mediaType, String body, Headers headers) throws ParsingException {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public Collection parseCollection(String mediaType, String body, Headers headers, CollectionType collectionType) throws ParsingException {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public List<URI> parseLocations(String mediaType, String body, Headers headers) throws ParsingException {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.parser;
+
+/**
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class MediaType {
+
+ public static final String APPLICATION_JSON = "application/json";
+ public static final String TEXT_OCCI = "text/occi";
+ public static final String TEXT_PLAIN = "text/plain";
+ public static final String TEXT_URI_LIST = "text/uri-list";
+}
--- /dev/null
+package cz.cesnet.cloud.occi.parser;
+
+import com.sun.net.httpserver.Headers;
+import cz.cesnet.cloud.occi.Collection;
+import cz.cesnet.cloud.occi.Model;
+import cz.cesnet.cloud.occi.exception.ParsingException;
+import java.net.URI;
+import java.util.List;
+
+/**
+ * Interface for parser of OCCI messages.
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public interface Parser {
+
+ /**
+ * Parses an OCCI model either from body or headers depending on mediaType.
+ *
+ * @param mediaType media type of the parsed server response
+ * @param body body of the server response
+ * @param headers headers of the server response
+ * @return OCCI model
+ * @throws ParsingException when error occures during the parsing
+ */
+ Model parseModel(String mediaType, String body, Headers headers) throws ParsingException;
+
+ /**
+ * Parses an OCCI entity either from body or headers depending on mediaType
+ * and collectionType.
+ *
+ * @param mediaType media type of the parsed server response
+ * @param body body of the server response
+ * @param headers headers of the server response
+ * @param collectionType collection type representing entities that will be
+ * parsed from the response
+ * @return collection of parsed entities
+ * @throws ParsingException when error occures during the parsing
+ */
+ Collection parseCollection(String mediaType, String body, Headers headers, CollectionType collectionType) throws ParsingException;
+
+ /**
+ * Parses a list of locations either from body or headers depending on
+ * mediaType.
+ *
+ * @param mediaType media type of the parsed server response
+ * @param body body of the server response
+ * @param headers headers of the server response
+ * @return list of locations
+ * @throws ParsingException when error occures during the parsing
+ */
+ List<URI> parseLocations(String mediaType, String body, Headers headers) throws ParsingException;
+}
--- /dev/null
+package cz.cesnet.cloud.occi.parser;
+
+import com.sun.net.httpserver.Headers;
+import cz.cesnet.cloud.occi.Collection;
+import cz.cesnet.cloud.occi.Model;
+import cz.cesnet.cloud.occi.core.Action;
+import cz.cesnet.cloud.occi.core.ActionInstance;
+import cz.cesnet.cloud.occi.core.Attribute;
+import cz.cesnet.cloud.occi.core.Category;
+import cz.cesnet.cloud.occi.core.Entity;
+import cz.cesnet.cloud.occi.core.Kind;
+import cz.cesnet.cloud.occi.core.Link;
+import cz.cesnet.cloud.occi.core.Mixin;
+import cz.cesnet.cloud.occi.core.Resource;
+import cz.cesnet.cloud.occi.exception.InvalidAttributeValueException;
+import cz.cesnet.cloud.occi.exception.ParsingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class TextParser implements Parser {
+
+ //regular expression groups
+ public static final String GROUP_TERM = "term";
+ public static final String GROUP_SCHEME = "scheme";
+ public static final String GROUP_CLASS = "class";
+ public static final String GROUP_TITLE = "title";
+ public static final String GROUP_REL = "rel";
+ public static final String GROUP_LOCATION = "location";
+ public static final String GROUP_ATTRIBUTES = "attributes";
+ public static final String GROUP_ACTIONS = "actions";
+ public static final String GROUP_URI = "uri";
+ public static final String GROUP_SELF = "self";
+ public static final String GROUP_CATEGORY = "category";
+
+ //regular expressions
+ public static final String REGEXP_LOALPHA = "[a-z]";
+ public static final String REGEXP_ALPHA = "[a-zA-Z]";
+ public static final String REGEXP_DIGIT = "[0-9]";
+ public static final String REGEXP_INT = REGEXP_DIGIT + "+";
+ public static final String REGEXP_FLOAT = REGEXP_INT + "\\." + REGEXP_INT;
+ public static final String REGEXP_NUMBER = REGEXP_FLOAT + "|" + REGEXP_INT;
+ public static final String REGEXP_BOOL = "\\b(?<!\\|)true(?!\\|)\\b|\\b(?<!\\|)false(?!\\|)\\b";
+ public static final String REGEXP_QUOTED_STRING = "([^\"\\\\]|\\.)*";
+ public static final String REGEXP_URI = "(?x-mi:([a-zA-Z][\\-+.a-zA-Z\\d]*):(?:((?:[\\-_.!~*'()a-zA-Z\\d;?:@&=+$,]|%[a-fA-F\\d]{2})(?:[\\-_.!~*'()a-zA-Z\\d;\\/?:@&=+$,\\[\\]]|%[a-fA-F\\d]{2})*)|(?:(?:\\/\\/(?:(?:(?:((?:[\\-_.!~*'()a-zA-Z\\d;:&=+$,]|%[a-fA-F\\d]{2})*)@)?(?:((?:(?:[a-zA-Z0-9\\-.]|%[0-9a-fA-F][0-9a-fA-F])+|\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|\\[(?:(?:[a-fA-F\\d]{1,4}:)*(?:[a-fA-F\\d]{1,4}|\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})|(?:(?:[a-fA-F\\d]{1,4}:)*[a-fA-F\\d]{1,4})?::(?:(?:[a-fA-F\\d]{1,4}:)*(?:[a-fA-F\\d]{1,4}|\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}))?)\\]))(?::(\\d*))?))?|((?:[\\-_.!~*'()a-zA-Z\\d$,;:@&=+]|%[a-fA-F\\d]{2})+))|(?!\\/\\/))(\\/(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*(?:;(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*)*(?:\\/(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*(?:;(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*)*)*)?)(?:\\?((?:[\\-_.!~*'()a-zA-Z\\d;\\/?:@&=+$,\\[\\]]|%[a-fA-F\\d]{2})*))?)(?:\\#((?:[\\-_.!~*'()a-zA-Z\\d;\\/?:@&=+$,\\[\\]]|%[a-fA-F\\d]{2})*))?)";
+ public static final String REGEXP_URI_REF = "(?:[a-zA-Z][\\-+.a-zA-Z\\d]*:(?:(?:\\/\\/(?:(?:(?:[\\-_.!~*'()a-zA-Z\\d;:&=+$,]|%[a-fA-F\\d]{2})*@)?(?:(?:[a-zA-Z0-9\\-.]|%[0-9a-fA-F][0-9a-fA-F])+|\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|\\[(?:(?:[a-fA-F\\d]{1,4}:)*(?:[a-fA-F\\d]{1,4}|\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})|(?:(?:[a-fA-F\\d]{1,4}:)*[a-fA-F\\d]{1,4})?::(?:(?:[a-fA-F\\d]{1,4}:)*(?:[a-fA-F\\d]{1,4}|\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}))?)\\])(?::\\d*)?|(?:[\\-_.!~*'()a-zA-Z\\d$,;:@&=+]|%[a-fA-F\\d]{2})+)(?:\\/(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*(?:;(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*)*(?:\\/(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*(?:;(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*)*)*)?|\\/(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*(?:;(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*)*(?:\\/(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*(?:;(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*)*)*)(?:\\?(?:(?:[\\-_.!~*'()a-zA-Z\\d;\\/?:@&=+$,\\[\\]]|%[a-fA-F\\d]{2})*))?|(?:[\\-_.!~*'()a-zA-Z\\d;?:@&=+$,]|%[a-fA-F\\d]{2})(?:[\\-_.!~*'()a-zA-Z\\d;\\/?:@&=+$,\\[\\]]|%[a-fA-F\\d]{2})*)|(?:\\/\\/(?:(?:(?:[\\-_.!~*'()a-zA-Z\\d;:&=+$,]|%[a-fA-F\\d]{2})*@)?(?:(?:[a-zA-Z0-9\\-.]|%[0-9a-fA-F][0-9a-fA-F])+|\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|\\[(?:(?:[a-fA-F\\d]{1,4}:)*(?:[a-fA-F\\d]{1,4}|\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})|(?:(?:[a-fA-F\\d]{1,4}:)*[a-fA-F\\d]{1,4})?::(?:(?:[a-fA-F\\d]{1,4}:)*(?:[a-fA-F\\d]{1,4}|\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}))?)\\])(?::\\d*)?|(?:[\\-_.!~*'()a-zA-Z\\d$,;:@&=+]|%[a-fA-F\\d]{2})+)(?:\\/(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*(?:;(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*)*(?:\\/(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*(?:;(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*)*)*)?|\\/(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*(?:;(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*)*(?:\\/(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*(?:;(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*)*)*|(?:[\\-_.!~*'()a-zA-Z\\d;@&=+$,]|%[a-fA-F\\d]{2})+(?:\\/(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*(?:;(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*)*(?:\\/(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*(?:;(?:[\\-_.!~*'()a-zA-Z\\d:@&=+$,]|%[a-fA-F\\d]{2})*)*)*)?)(?:\\?(?:[\\-_.!~*'()a-zA-Z\\d;\\/?:@&=+$,\\[\\]]|%[a-fA-F\\d]{2})*)?)?(?:#(?:[\\-_.!~*'()a-zA-Z\\d;\\/?:@&=+$,\\[\\]]|%[a-fA-F\\d]{2})*)?";
+ public static final String REGEXP_TERM = "(" + REGEXP_ALPHA + "|" + REGEXP_DIGIT + ")(" + REGEXP_LOALPHA + "|" + REGEXP_DIGIT + "|-|_)*";
+
+ public static final String REGEXP_SCHEME = REGEXP_URI + "#";
+ public static final String REGEXP_TYPE_IDENTIFIER = REGEXP_SCHEME + REGEXP_TERM;
+ public static final String REGEXP_CLASS = "\\b(?<!\\|)action(?!\\|)\\b|\\b(?<!\\|)mixin(?!\\|)\\b|\\b(?<!\\|)kind(?!\\|)\\b";
+ public static final String REGEXP_TYPE_IDENTIFIER_LIST = REGEXP_TYPE_IDENTIFIER + "(\\s+" + REGEXP_TYPE_IDENTIFIER + ")*";
+ public static final String REGEXP_ATTRIBUTE_COMPONENT = REGEXP_LOALPHA + "(" + REGEXP_LOALPHA + "|" + REGEXP_DIGIT + "|-|_)*";
+ public static final String REGEXP_ATTRIBUTE_NAME = REGEXP_ATTRIBUTE_COMPONENT + "(\\." + REGEXP_ATTRIBUTE_COMPONENT + ")*";
+ public static final String REGEXP_ATTRIBUTE_PROPERTIES = "\\{(?:required immutable|immutable required|required|immutable)\\}";
+ public static final String REGEXP_ATTRIBUTE_DEF = "(?:" + REGEXP_ATTRIBUTE_NAME + ")(?:" + REGEXP_ATTRIBUTE_PROPERTIES + ")?";
+ public static final String REGEXP_ATTRIBUTE_LIST = REGEXP_ATTRIBUTE_DEF + "(\\s+" + REGEXP_ATTRIBUTE_DEF + ")*";
+ public static final String REGEXP_ATTRIBUTE_REPR = REGEXP_ATTRIBUTE_NAME + "=(\"" + REGEXP_QUOTED_STRING + "\"|" + REGEXP_NUMBER + "|" + REGEXP_BOOL + ");?";
+ public static final String REGEXP_ACTION = REGEXP_TYPE_IDENTIFIER;
+ public static final String REGEXP_ACTION_LIST = REGEXP_ACTION + "(\\s+" + REGEXP_ACTION + ")*";
+ public static final String REGEXP_RESOURCE_TYPE = REGEXP_TYPE_IDENTIFIER + "(\\s+" + REGEXP_TYPE_IDENTIFIER + ")*";
+ public static final String REGEXP_LINK_INSTANCE = REGEXP_URI_REF;
+ public static final String REGEXP_LINK_TYPE = REGEXP_TYPE_IDENTIFIER + "(\\s+" + REGEXP_TYPE_IDENTIFIER + ")*";
+
+ public static final String REGEXP_CATEGORY = "(?<" + GROUP_TERM + ">" + REGEXP_TERM + ")" // term (mandatory)
+ + ";\\s*scheme=\"(?<" + GROUP_SCHEME + ">" + REGEXP_SCHEME + ")(?:" + REGEXP_TERM + ")?\"" // scheme (mandatory)
+ + ";\\s*class=\"?(?<" + GROUP_CLASS + ">" + REGEXP_CLASS + ")\"?" // class (mandatory)
+ + "(;\\s*title=\"(?<" + GROUP_TITLE + ">" + REGEXP_QUOTED_STRING + ")\")?" // title (optional)
+ + "(;\\s*rel=\"(?<" + GROUP_REL + ">" + REGEXP_TYPE_IDENTIFIER_LIST + ")\")?" // rel (optional)
+ + "(;\\s*location=\"(?<" + GROUP_LOCATION + ">" + REGEXP_URI_REF + ")\")?" // location (optional)
+ + "(;\\s*attributes=\"(?<" + GROUP_ATTRIBUTES + ">" + REGEXP_ATTRIBUTE_LIST + ")\")?" // attributes (optional)
+ + "(;\\s*actions=\"(?<" + GROUP_ACTIONS + ">" + REGEXP_ACTION_LIST + ")\")?" // actions (optional)
+ + ";?"; // additional semicolon at the end (not specified, for interoperability)
+
+ public static final String REGEXP_ATTRIBUTES = "(" + REGEXP_ATTRIBUTE_DEF + ")";
+
+ public static final String REGEXP_LINK = "\\<(?<" + GROUP_URI + ">" + REGEXP_URI_REF + ")\\>" // uri (mandatory)
+ + ";\\s*rel=\"(?<" + GROUP_REL + ">" + REGEXP_RESOURCE_TYPE + ")\"" // rel (mandatory)
+ + "(;\\s*self=\"(?<" + GROUP_SELF + ">" + REGEXP_LINK_INSTANCE + ")\")?" // self (optional)
+ + "(;\\s*category=\"(?<" + GROUP_CATEGORY + ">(;?\\s*(" + REGEXP_LINK_TYPE + "))+)\")?" // category (optional)
+ + "(;\\s*(?<" + GROUP_ATTRIBUTES + ">(;?\\s*" + REGEXP_ATTRIBUTE_REPR + ")*))?" // attributes (optional)
+ + ";?"; // additional semicolon at the end (not specified, for interoperability)
+
+ public static final Pattern PATTERN_CATEGORY = Pattern.compile(REGEXP_CATEGORY);
+ public static final Pattern PATTERN_ATTRIBUTES = Pattern.compile(REGEXP_ATTRIBUTES);
+ public static final Pattern PATTERN_LINK = Pattern.compile(REGEXP_LINK);
+
+ public static final String CATEGORY_HEADER = "category";
+ public static final String LINK_HEADER = "link";
+ public static final String ATTRIBUTE_HEADER = "x-occi-attribute";
+ public static final String LOCATION_HEADER = "location";
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(TextParser.class);
+
+ /**
+ * @see Parser#parseModel(java.lang.String, java.lang.String,
+ * com.sun.net.httpserver.Headers)
+ */
+ @Override
+ public Model parseModel(String mediaType, String body, Headers headers) throws ParsingException {
+ LOGGER.debug("Parsing model...");
+
+ switch (mediaType) {
+ case MediaType.TEXT_OCCI:
+ return parseModelFromHeaders(headers);
+ case MediaType.TEXT_PLAIN:
+ return parseModelFromBody(body);
+ default:
+ throw new ParsingException("Unknown media type '" + mediaType + "'.");
+ }
+ }
+
+ private Model parseModelFromBody(String body) throws ParsingException {
+ LOGGER.debug("Reading response body.");
+
+ body = body.trim();
+ String replaced = Pattern.compile("Category:\\s*", Pattern.CASE_INSENSITIVE).matcher(body).replaceAll("");
+
+ String[] lines = replaced.split("[\\r\\n]+");
+ return parseModelFromArray(lines);
+ }
+
+ private Model parseModelFromHeaders(Headers headers) throws ParsingException {
+ LOGGER.debug("Reading response headers.");
+
+ if (!headers.containsKey(CATEGORY_HEADER)) {
+ throw new ParsingException("No header '" + CATEGORY_HEADER + "' among headers.");
+ }
+
+ String[] categories = headers.getFirst(CATEGORY_HEADER).split(",");
+ return parseModelFromArray(categories);
+ }
+
+ private Model parseModelFromArray(String[] lines) throws ParsingException {
+ Model model = new Model();
+ Map<String, List<Kind>> kindMapping = new HashMap<>();
+ Map<String, List<Mixin>> mixinMapping = new HashMap<>();
+
+ for (String line : lines) {
+ LOGGER.debug("Matching line '{}' against category pattern.", line);
+ Matcher matcher = PATTERN_CATEGORY.matcher(line);
+ if (!matcher.find()) {
+ throw new ParsingException("Invalid line: " + line);
+ }
+ String term = matcher.group(GROUP_TERM);
+ String scheme = matcher.group(GROUP_SCHEME);
+ String categoryClass = matcher.group(GROUP_CLASS);
+ String location = matcher.group(GROUP_LOCATION);
+ LOGGER.debug("Match: term={}, scheme={}, class={}, title={}, rel={}, location={}, attributes={}, actions={}",
+ term, scheme, categoryClass, matcher.group(GROUP_TITLE), matcher.group(GROUP_REL), location, matcher.group(GROUP_ATTRIBUTES), matcher.group(GROUP_ACTIONS));
+
+ if (term == null || term.isEmpty()) {
+ throw new ParsingException("No term found.");
+ }
+ if (scheme == null || scheme.isEmpty()) {
+ throw new ParsingException("No scheme found.");
+ }
+ if (categoryClass == null || categoryClass.isEmpty()) {
+ throw new ParsingException("No class found.");
+ }
+
+ switch (categoryClass) {
+ case "kind":
+ if (location == null || location.isEmpty()) {
+ throw new ParsingException("No location found.");
+ }
+ model = addKind(matcher, kindMapping, model);
+ break;
+ case "mixin":
+ model = addMixin(matcher, mixinMapping, model);
+ break;
+ case "action":
+ model = addAction(matcher, model);
+ break;
+ default:
+ throw new ParsingException("Unknown class type.");
+ }
+ }
+
+ if (!kindMapping.isEmpty()) {
+ List<Kind> defaultKinds = createDefaultKinds();
+ for (Kind kind : defaultKinds) {
+ if (model.containsKind(kind)) {
+ continue;
+ }
+
+ model.addKind(kind);
+
+ for (String identifier : kindMapping.keySet()) {
+ if (identifier.equals(kind.getIdentifier())) {
+ List<Kind> kinds = kindMapping.remove(identifier);
+ for (Kind k : kinds) {
+ k.setParentKind(kind);
+ k.addRelation(kind);
+ }
+ }
+ }
+ }
+
+ if (!kindMapping.isEmpty()) {
+ throw new ParsingException("Unknown kind relations found: " + kindMapping);
+ }
+ }
+
+ if (!mixinMapping.isEmpty()) {
+ throw new ParsingException("Unknown mixins relations found: " + mixinMapping);
+ }
+
+ return model;
+ }
+
+ private Model addKind(Matcher matcher, Map<String, List<Kind>> mapping, Model model) throws ParsingException {
+ LOGGER.debug("Adding kind...");
+ String actions = matcher.group(GROUP_ACTIONS);
+ String rel = matcher.group(GROUP_REL);
+ String term = matcher.group(GROUP_TERM);
+
+ Kind kind = createKind(matcher);
+ kind = (Kind) connectActions(actions, kind, model);
+
+ if (rel != null && !rel.isEmpty()) {
+ if (!model.containsKind(rel)) {
+ LOGGER.debug("Unexpected relation " + rel + " in kind " + term + ". Storing for later mapping");
+ if (mapping.containsKey(rel)) {
+ List<Kind> kinds = mapping.get(rel);
+ kinds.add(kind);
+ } else {
+ List<Kind> kinds = new ArrayList<>();
+ kinds.add(kind);
+ mapping.put(rel, kinds);
+ }
+ } else {
+ Kind k = model.getKind(rel);
+ LOGGER.debug("Creating relation between {} and {}.", kind, k);
+ kind.setParentKind(k);
+ kind.addRelation(k);
+ }
+ }
+
+ String identifier = kind.getIdentifier();
+ if (mapping.containsKey(identifier)) {
+ List<Kind> kinds = mapping.remove(identifier);
+ for (Kind k : kinds) {
+ k.setParentKind(kind);
+ k.addRelation(kind);
+ }
+ }
+
+ model.addKind(kind);
+ return model;
+ }
+
+ private Model addMixin(Matcher matcher, Map<String, List<Mixin>> mapping, Model model) throws ParsingException {
+ LOGGER.debug("Adding mixin...");
+ String actions = matcher.group(GROUP_ACTIONS);
+ String rel = matcher.group(GROUP_REL);
+ String term = matcher.group(GROUP_TERM);
+
+ Mixin mixin = createMixin(matcher);
+ mixin = (Mixin) connectActions(actions, mixin, model);
+
+ if (rel != null && !rel.isEmpty()) {
+ if (!model.containsMixin(rel)) {
+ LOGGER.debug("Unexpected relation " + rel + " in mixin " + term + ". Storing for later mapping");
+ if (mapping.containsKey(rel)) {
+ List<Mixin> mixins = mapping.get(rel);
+ mixins.add(mixin);
+ } else {
+ List<Mixin> mixins = new ArrayList<>();
+ mixins.add(mixin);
+ mapping.put(rel, mixins);
+ }
+ } else {
+ Mixin m = model.getMixin(rel);
+ LOGGER.debug("Creating relation between {} and {}.", mixin, m);
+ mixin.addRelation(m);
+ }
+ }
+
+ String identifier = mixin.getIdentifier();
+ if (mapping.containsKey(identifier)) {
+ List<Mixin> mixins = mapping.remove(identifier);
+ for (Mixin m : mixins) {
+ m.addRelation(mixin);
+ }
+ }
+
+ model.addMixin(mixin);
+ return model;
+ }
+
+ private Model addAction(Matcher matcher, Model model) throws ParsingException {
+ LOGGER.debug("Adding action...");
+ String term = matcher.group(GROUP_TERM);
+ String scheme = matcher.group(GROUP_SCHEME);
+ String title = matcher.group(GROUP_TITLE);
+ String attributes = matcher.group(GROUP_ATTRIBUTES);
+
+ String actionIdentifier = scheme + term;
+ if (model.containsAction(actionIdentifier)) {
+ Set<Attribute> parsedAttributes = parseAttributes(attributes);
+
+ Action action = model.getAction(actionIdentifier);
+ action.setTitle(title);
+ for (Attribute attribute : parsedAttributes) {
+ action.addAttribute(attribute);
+ }
+ } else {
+ Action action = createAction(matcher);
+ model.addAction(action);
+ }
+
+ return model;
+ }
+
+ private Category connectActions(String actions, Category category, Model model) throws ParsingException {
+ LOGGER.debug("Connecting actions...");
+ if (actions == null || actions.isEmpty()) {
+ return category;
+ }
+
+ String[] splitedActions = actions.split("\\s+");
+ for (String actionIdentifier : splitedActions) {
+ LOGGER.debug("Action identifier: {}", actionIdentifier);
+ Action action;
+ if (model != null && model.containsAction(actionIdentifier)) {
+ action = model.getAction(actionIdentifier);
+ } else {
+ try {
+ String[] splitedAction = actionIdentifier.split("#");
+ if (splitedAction.length != 2) {
+ throw new ParsingException("Invalid action identifier: " + actionIdentifier + ".");
+ }
+ action = new Action(new URI(splitedAction[0] + "#"), splitedAction[1]);
+ } catch (URISyntaxException ex) {
+ throw new ParsingException("Invalid category scheme: " + actionIdentifier + ".", ex);
+ }
+ }
+
+ category.addAction(action);
+ }
+
+ return category;
+ }
+
+ private Set<Attribute> parseAttributes(String attributes) {
+ LOGGER.debug("Parsing attributes: {}", attributes);
+ Set<Attribute> attributeSet = new HashSet<>();
+ if (attributes == null || attributes.isEmpty()) {
+ return attributeSet;
+ }
+
+ Matcher matcher = PATTERN_ATTRIBUTES.matcher(attributes);
+ while (matcher.find()) {
+ String attributeString = matcher.group();
+ LOGGER.debug("Found attribute represented by string: {}", attributeString);
+ Attribute attribute = parseAttribute(attributeString);
+ attributeSet.add(attribute);
+ }
+
+ return attributeSet;
+ }
+
+ private Attribute parseAttribute(String attributeString) {
+ String[] splitedAttribute = attributeString.split("\\{");
+ Attribute attribute = new Attribute(splitedAttribute[0]);
+ if (splitedAttribute.length == 2) {
+ if (splitedAttribute[1].contains("immutable")) {
+ attribute.setImmutable(true);
+ }
+ if (splitedAttribute[1].contains("required")) {
+ attribute.setRequired(true);
+ }
+ }
+
+ LOGGER.debug("New attribute: {}", attribute);
+ return attribute;
+ }
+
+ private List<Kind> createDefaultKinds() {
+ List<Kind> defaultKinds = new ArrayList<>();
+
+ Set<Attribute> attributes = new HashSet<>();
+ attributes.add(new Attribute(Entity.ID_ATTRIBUTE_NAME, true, true));
+ attributes.add(new Attribute(Entity.TITLE_ATTRIBUTE_NAME, false, false));
+ Kind entity = new Kind(Entity.SCHEME_DEFAULT, Entity.TERM_DEFAULT, "Entity", URI.create("/entity/"), attributes);
+ defaultKinds.add(entity);
+
+ attributes = new HashSet<>();
+ attributes.add(new Attribute(Resource.SUMMARY_ATTRIBUTE_NAME, false, false));
+ Kind resource = new Kind(Resource.SCHEME_DEFAULT, Resource.TERM_DEFAULT, "Resource", URI.create("/resource/"), attributes);
+ resource.setParentKind(entity);
+ resource.addRelation(entity);
+ defaultKinds.add(resource);
+
+ attributes = new HashSet<>();
+ attributes.add(new Attribute(Link.SOURCE_ATTRIBUTE_NAME, true, false));
+ attributes.add(new Attribute(Link.TARGET_ATTRIBUTE_NAME, true, false));
+ Kind link = new Kind(Link.SCHEME_DEFAULT, Link.TERM_DEFAULT, "Link", URI.create("/link/"), attributes);
+ link.setParentKind(entity);
+ link.addRelation(entity);
+ defaultKinds.add(link);
+
+ return defaultKinds;
+ }
+
+ /**
+ * @see Parser#parseLocations(java.lang.String, java.lang.String,
+ * com.sun.net.httpserver.Headers)
+ */
+ @Override
+ public List<URI> parseLocations(String mediaType, String body, Headers headers) throws ParsingException {
+ LOGGER.debug("Parsing location...");
+
+ switch (mediaType) {
+ case MediaType.TEXT_OCCI:
+ return parseLocationsFromHeaders(headers);
+ case MediaType.TEXT_URI_LIST:
+ case MediaType.TEXT_PLAIN:
+ return parseLocationsFromBody(body);
+ default:
+ throw new ParsingException("Unknown media type '" + mediaType + "'.");
+ }
+ }
+
+ private List<URI> parseLocationsFromHeaders(Headers headers) throws ParsingException {
+ LOGGER.debug("Reading response headers.");
+
+ if (!headers.containsKey(LOCATION_HEADER)) {
+ throw new ParsingException("No header '" + LOCATION_HEADER + "' among headers.");
+ }
+
+ String[] locations = headers.getFirst(LOCATION_HEADER).split(",");
+ return makeURIList(locations);
+ }
+
+ private List<URI> parseLocationsFromBody(String body) throws ParsingException {
+ LOGGER.debug("Reading response body.");
+
+ body = body.trim();
+ String replaced = Pattern.compile("X-OCCI-Location:\\s*", Pattern.CASE_INSENSITIVE).matcher(body).replaceAll("");
+ String[] lines = replaced.split("[\\r\\n]+");
+ return makeURIList(lines);
+ }
+
+ private List<URI> makeURIList(String[] locations) throws ParsingException {
+
+ List<URI> locationsURI = new ArrayList<>();
+ for (String location : locations) {
+ try {
+ locationsURI.add(new URI(location));
+ } catch (URISyntaxException ex) {
+ throw new ParsingException("Invalid location: " + location + ".", ex);
+ }
+ }
+
+ return locationsURI;
+ }
+
+ /**
+ * @see Parser#parseCollection(java.lang.String, java.lang.String,
+ * com.sun.net.httpserver.Headers,
+ * cz.cesnet.cloud.occi.parser.CollectionType)
+ */
+ @Override
+ public Collection parseCollection(String mediaType, String body, Headers headers, CollectionType collectionType) throws ParsingException {
+ LOGGER.debug("Parsing collection...");
+
+ switch (mediaType) {
+ case MediaType.TEXT_OCCI:
+ return parseCollectionFromHeaders(headers, collectionType);
+ case MediaType.TEXT_PLAIN:
+ return parseCollectionFromBody(body, collectionType);
+ default:
+ throw new ParsingException("Unknown media type '" + mediaType + "'.");
+ }
+ }
+
+ private Collection parseCollectionFromHeaders(Headers headers, CollectionType collectionType) throws ParsingException {
+ LOGGER.debug("Reading headers.");
+
+ if (!headers.containsKey(CATEGORY_HEADER)) {
+ throw new ParsingException("No '" + CATEGORY_HEADER + "' header.");
+ }
+
+ List<String> lines = new ArrayList<>();
+ lines.addAll(Arrays.asList(headers.getFirst(CATEGORY_HEADER).split(",")));
+
+ if (headers.containsKey(ATTRIBUTE_HEADER)) {
+ lines.addAll(Arrays.asList(headers.getFirst(ATTRIBUTE_HEADER).split(",")));
+ }
+
+ if (headers.containsKey(LINK_HEADER)) {
+ lines.addAll(Arrays.asList(headers.getFirst(LINK_HEADER).split(",")));
+ }
+
+ return parseCollectionFromArray(lines.toArray(new String[0]), collectionType);
+ }
+
+ private Collection parseCollectionFromBody(String body, CollectionType collectionType) throws ParsingException {
+ LOGGER.debug("Reading body.");
+
+ body = body.trim();
+ String replaced = Pattern.compile("Category:\\s*", Pattern.CASE_INSENSITIVE).matcher(body).replaceAll("");
+ replaced = Pattern.compile("Link:\\s*", Pattern.CASE_INSENSITIVE).matcher(body).replaceAll("");
+ replaced = Pattern.compile("X-OCCI-Attribute:\\s*", Pattern.CASE_INSENSITIVE).matcher(body).replaceAll("");
+ String[] lines = replaced.split("[\\r\\n]+");
+
+ return parseCollectionFromArray(lines, collectionType);
+ }
+
+ private Collection parseCollectionFromArray(String[] lines, CollectionType collectionType) throws ParsingException {
+ Collection collection = new Collection();
+ Kind kind;
+ Set<Mixin> mixins = new HashSet<>();
+ List<String> rawAttributes = new ArrayList<>();
+ Map<String, String> attributesWithValues = null;
+
+ switch (collectionType) {
+ //expecting resource instance
+ case RESOURCE:
+ Set<Link> links = new HashSet<>();
+ Set<Action> actionLinks = new HashSet<>();
+
+ kind = lookForKind(lines[0]);
+ lines = Arrays.copyOfRange(lines, 1, lines.length);
+
+ for (String line : lines) {
+ //looking for mixin lines
+ if (lookForMixins(line, mixins)) {
+ continue;
+ }
+ //looking for attribute lines
+ if (lookForAttributes(line, rawAttributes)) {
+ continue;
+ }
+ //looking for link lines
+ lookForLinks(line, links, actionLinks);
+ }
+
+ attributesWithValues = parseAttributesWithValues(rawAttributes.toArray(new String[0]));
+ if (!attributesWithValues.containsKey(Resource.ID_ATTRIBUTE_NAME)) {
+ throw new ParsingException("No id found. Cannot construct a resource.");
+ }
+
+ Resource resource = null;
+ try {
+ resource = new Resource(attributesWithValues.get(Entity.ID_ATTRIBUTE_NAME), kind);
+
+ attributesWithValues.remove(Entity.ID_ATTRIBUTE_NAME);
+ resource.addMixins(mixins);
+ resource.addLinks(links);
+ resource.addActions(actionLinks);
+ resource.addAttributes(attributesWithValues);
+ } catch (InvalidAttributeValueException ex) {
+ throw new ParsingException("Invalid attribute value found", ex);
+ }
+ collection.addResource(resource);
+
+ break;
+ case LINK:
+ kind = lookForKind(lines[0]);
+ lines = Arrays.copyOfRange(lines, 1, lines.length);
+
+ for (String line : lines) {
+ //looking for mixin lines
+ if (lookForMixins(line, mixins)) {
+ continue;
+ }
+ //looking for attribute lines
+ lookForAttributes(line, rawAttributes);
+ }
+
+ attributesWithValues = parseAttributesWithValues(rawAttributes.toArray(new String[0]));
+ if (!attributesWithValues.containsKey(Resource.ID_ATTRIBUTE_NAME)) {
+ throw new ParsingException("No id found. Cannot construct a resource.");
+ }
+
+ Link link = null;
+ try {
+ link = new Link(attributesWithValues.get(Entity.ID_ATTRIBUTE_NAME), kind);
+
+ attributesWithValues.remove(Entity.ID_ATTRIBUTE_NAME);
+ link.addMixins(mixins);
+ link.addAttributes(attributesWithValues);
+ } catch (InvalidAttributeValueException ex) {
+ throw new ParsingException("Invalid attribute value found", ex);
+ }
+ collection.addLink(link);
+ break;
+ case ACTION:
+ ActionInstance actionInstance = lookForActionInstance(lines[0]);
+ lines = Arrays.copyOfRange(lines, 1, lines.length);
+
+ for (String line : lines) {
+ //looking for attribute lines
+ lookForAttributes(line, rawAttributes);
+ }
+
+ attributesWithValues = parseAttributesWithValues(rawAttributes.toArray(new String[0]));
+ actionInstance.addAttributes(attributesWithValues);
+
+ collection.addAction(actionInstance);
+ break;
+ default:
+ throw new ParsingException("Unknown collection type'" + collectionType + "'.");
+ }
+
+ return collection;
+ }
+
+ private Kind lookForKind(String line) throws ParsingException {
+ LOGGER.debug("Matching line '{}' against category pattern.", line);
+ Matcher matcher = PATTERN_CATEGORY.matcher(line);
+
+ if (!matcher.find()) {
+ throw new ParsingException("No kind specification found.");
+ }
+
+ LOGGER.debug("Match: term={}, scheme={}, class={}, title={}, rel={}, location={}, attributes={}, actions={}",
+ matcher.group(GROUP_TERM), matcher.group(GROUP_SCHEME),
+ matcher.group(GROUP_CLASS), matcher.group(GROUP_TITLE),
+ matcher.group(GROUP_REL), matcher.group(GROUP_LOCATION),
+ matcher.group(GROUP_ATTRIBUTES), matcher.group(GROUP_ACTIONS));
+
+ String actions = matcher.group(GROUP_ACTIONS);
+ String categoryClass = matcher.group(GROUP_CLASS);
+
+ if (!categoryClass.equals("kind")) {
+ throw new ParsingException("No kind specification found.");
+ }
+
+ Kind kind = createKind(matcher);
+ connectActions(actions, kind, null);
+
+ return kind;
+ }
+
+ private boolean lookForMixins(String line, Set<Mixin> mixins) throws ParsingException {
+ LOGGER.debug("Matching line '{}' against category pattern.", line);
+ Matcher matcher = PATTERN_CATEGORY.matcher(line);
+
+ if (matcher.find()) {
+ LOGGER.debug("Match: term={}, scheme={}, class={}, title={}, rel={}, location={}, attributes={}, actions={}",
+ matcher.group(GROUP_TERM), matcher.group(GROUP_SCHEME),
+ matcher.group(GROUP_CLASS), matcher.group(GROUP_TITLE),
+ matcher.group(GROUP_REL), matcher.group(GROUP_LOCATION),
+ matcher.group(GROUP_ATTRIBUTES), matcher.group(GROUP_ACTIONS));
+
+ String categoryClass = matcher.group(GROUP_CLASS);
+ String actions = matcher.group(GROUP_ACTIONS);
+
+ switch (categoryClass) {
+ case "mixin":
+ Mixin mixin = createMixin(matcher);
+ connectActions(actions, mixin, null);
+ mixins.add(mixin);
+ break;
+ default:
+ throw new ParsingException("Unknown category class '" + categoryClass + "'.");
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ private boolean lookForAttributes(String line, List<String> attributes) {
+ LOGGER.debug("Matching line '{}' against attribute pattern.", line);
+ if (line.matches(REGEXP_ATTRIBUTE_REPR)) {
+ attributes.add(line);
+ return true;
+ }
+
+ return false;
+ }
+
+ private void lookForLinks(String line, Set<Link> links, Set<Action> actionLinks) throws ParsingException {
+ LOGGER.debug("Matching line '{}' against link pattern.", line);
+ Matcher matcher = PATTERN_LINK.matcher(line);
+
+ if (matcher.find()) {
+ LOGGER.debug("Match: uri={}, rel={}, self={}, category={}, attributes={}",
+ matcher.group(GROUP_URI), matcher.group(GROUP_REL),
+ matcher.group(GROUP_SELF), matcher.group(GROUP_CATEGORY),
+ matcher.group(GROUP_ATTRIBUTES));
+
+ if (matcher.group(GROUP_URI).contains("?action=")) {
+ Action action = createAction(matcher.group(GROUP_REL));
+ actionLinks.add(action);
+ } else {
+ Link link = createLink(matcher);
+ links.add(link);
+ }
+ }
+ }
+
+ private ActionInstance lookForActionInstance(String line) throws ParsingException {
+ LOGGER.debug("Matching line '{}' against category pattern.", line);
+ Matcher matcher = PATTERN_CATEGORY.matcher(line);
+
+ if (!matcher.find()) {
+ throw new ParsingException("No action specification found.");
+ }
+
+ LOGGER.debug("Match: term={}, scheme={}, class={}, title={}, rel={}, location={}, attributes={}, actions={}",
+ matcher.group(GROUP_TERM), matcher.group(GROUP_SCHEME),
+ matcher.group(GROUP_CLASS), matcher.group(GROUP_TITLE),
+ matcher.group(GROUP_REL), matcher.group(GROUP_LOCATION),
+ matcher.group(GROUP_ATTRIBUTES), matcher.group(GROUP_ACTIONS));
+
+ String categoryClass = matcher.group(GROUP_CLASS);
+
+ if (!categoryClass.equals("action")) {
+ throw new ParsingException("No action specification found.");
+ }
+
+ Action action = createAction(matcher);
+ ActionInstance actionInstance = new ActionInstance(action);
+
+ return actionInstance;
+ }
+
+ private Map<String, String> parseAttributesWithValues(String[] attributes) throws ParsingException {
+ LOGGER.debug("Parsing attributes with values");
+ Map<String, String> result = new HashMap<>();
+
+ for (String attribute : attributes) {
+ String trimmedAttribute = attribute.trim();
+ LOGGER.debug("Attribute represented by string: {}", trimmedAttribute);
+ String[] parts = trimmedAttribute.split("=", 2);
+ if (parts.length != 2) {
+ throw new ParsingException("Wrong attribute format.");
+ }
+
+ String name = parts[0];
+ String value = parts[1].replaceAll("\"", "");
+ if (value.endsWith(";")) {
+ value = value.substring(0, value.length() - 1);
+ }
+
+ result.put(name, value);
+ }
+
+ return result;
+ }
+
+ private Kind createKind(Matcher matcher) throws ParsingException {
+ String term = matcher.group(GROUP_TERM);
+ String scheme = matcher.group(GROUP_SCHEME);
+ String title = matcher.group(GROUP_TITLE);
+ String location = matcher.group(GROUP_LOCATION);
+ String attributes = matcher.group(GROUP_ATTRIBUTES);
+
+ try {
+ Set<Attribute> parsedAttributes = parseAttributes(attributes);
+ URI locationUri = null;
+ if (location != null) {
+ locationUri = new URI(location);
+ locationUri = new URI(locationUri.getPath());
+ }
+ Kind kind = new Kind(new URI(scheme), term, title, locationUri, parsedAttributes);
+
+ return kind;
+ } catch (URISyntaxException ex) {
+ throw new ParsingException("Invalid shceme or location.", ex);
+ }
+ }
+
+ private Mixin createMixin(Matcher matcher) throws ParsingException {
+ String term = matcher.group(GROUP_TERM);
+ String scheme = matcher.group(GROUP_SCHEME);
+ String title = matcher.group(GROUP_TITLE);
+ String location = matcher.group(GROUP_LOCATION);
+ String attributes = matcher.group(GROUP_ATTRIBUTES);
+
+ try {
+ URI locationUri = null;
+ if (location == null || location.isEmpty()) {
+ locationUri = new URI("/mixin/" + term);
+ locationUri = new URI(locationUri.getPath());
+ } else {
+ locationUri = new URI(location);
+ locationUri = new URI(locationUri.getPath());
+ }
+ Set<Attribute> parsedAttributes = parseAttributes(attributes);
+ Mixin mixin = new Mixin(new URI(scheme), term, title, locationUri, parsedAttributes);
+
+ return mixin;
+ } catch (URISyntaxException ex) {
+ throw new ParsingException("Invalid shceme or location.", ex);
+ }
+ }
+
+ private Link createLink(Matcher matcher) throws ParsingException {
+ String uri = matcher.group(GROUP_URI);
+ String rel = matcher.group(GROUP_REL);
+ String self = matcher.group(GROUP_SELF);
+ String category = matcher.group(GROUP_CATEGORY);
+ String attributes = matcher.group(GROUP_ATTRIBUTES);
+
+ try {
+ Kind kind;
+ List<Mixin> mixins = new ArrayList<>();
+ if (category != null && !category.isEmpty()) {
+ String[] categories = category.split(" ");
+ String[] kindCategory = categories[0].split("#");
+ if (kindCategory.length != 2) {
+ throw new ParsingException("Invalid link category: " + category);
+ }
+ kind = new Kind(new URI(kindCategory[0] + "#"), kindCategory[1]);
+
+ if (categories.length > 1) {
+ for (int i = 1; i < categories.length; i++) {
+ String[] splitedCategory = categories[i].split("#");
+ if (splitedCategory.length != 2) {
+ throw new ParsingException("Invalid link category: " + category);
+ }
+ Mixin mixin = new Mixin(new URI(splitedCategory[0] + "#"), splitedCategory[1]);
+ mixins.add(mixin);
+ }
+ }
+ } else {
+ kind = new Kind(Link.SCHEME_DEFAULT, Link.TERM_DEFAULT);
+ }
+
+ Link link;
+ if (self != null && !self.isEmpty()) {
+ String[] splitedSelf = divideUriByLastSegment(self);
+ kind.setLocation(new URI(splitedSelf[1]));
+ link = new Link(splitedSelf[0], kind);
+ } else {
+ link = new Link(UUID.randomUUID().toString(), kind);
+ }
+
+ link.addMixins(mixins);
+
+ link.setTarget(uri);
+ link.setRelation(rel);
+ Map<String, String> attributesWithValues = parseAttributesWithValues(attributes.split(";"));
+ for (String name : attributesWithValues.keySet()) {
+ link.addAttribute(name, attributesWithValues.get(name));
+ // ***********HACK*********
+ if (name.equals("occi.core.id")) {
+ String value = attributesWithValues.get(name);
+ value = value.substring(value.lastIndexOf('/') + 1);
+ link.addAttribute(name, value);
+ }
+ // ***********HACK*********
+ }
+
+ return link;
+ } catch (InvalidAttributeValueException ex) {
+ throw new ParsingException("Invalid attribute value found", ex);
+ } catch (URISyntaxException ex) {
+ throw new ParsingException("Invalid shceme or location.", ex);
+ }
+ }
+
+ private Action createAction(String rel) throws ParsingException {
+ if (rel == null || rel.isEmpty()) {
+ throw new ParsingException("Link for action is missing 'rel' element.");
+ }
+
+ String[] splited = rel.split("#");
+ if (splited.length != 2) {
+ throw new ParsingException("Invalid relation specification: " + rel);
+ }
+
+ return createAction(splited[0] + "#", splited[1], null, null);
+ }
+
+ private Action createAction(Matcher matcher) throws ParsingException {
+ String term = matcher.group(GROUP_TERM);
+ String scheme = matcher.group(GROUP_SCHEME);
+ String title = matcher.group(GROUP_TITLE);
+ String attributes = matcher.group(GROUP_ATTRIBUTES);
+
+ return createAction(scheme, term, title, attributes);
+ }
+
+ private Action createAction(String scheme, String term, String title, String attributes) throws ParsingException {
+ Set<Attribute> parsedAttributes = parseAttributes(attributes);
+ Action action = null;
+ try {
+ action = new Action(new URI(scheme), term, title, parsedAttributes);
+ } catch (URISyntaxException ex) {
+ throw new ParsingException("Invalid URI.", ex);
+ }
+ return action;
+ }
+
+ public static String[] divideUriByLastSegment(String uri) {
+ String[] parts = new String[2];
+ parts[0] = uri.substring(uri.lastIndexOf('/') + 1);
+ parts[1] = uri.substring(0, uri.lastIndexOf('/') + 1);
+
+ return parts;
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.renderer;
+
+/**
+ * Helper class for rendering specific methods.
+ *
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public class TextRenderer {
+
+ /**
+ * Surrounds given string with prefix '="' and suffix '";'.
+ *
+ * @param string string to apply prefix and suffix to
+ * @return modified string
+ */
+ public static String surroundString(String string) {
+ return surroundString(string, "=\"", "\";");
+ }
+
+ /**
+ * Surround given string with given prefix and suffix.
+ *
+ * @param string string to apply prefix and suffix to
+ * @param prefix prefix to apply
+ * @param suffix suffix to apply
+ * @return modified string
+ */
+ public static String surroundString(String string, String prefix, String suffix) {
+ StringBuilder sb = new StringBuilder(string);
+ sb.append(suffix);
+ sb.insert(0, prefix);
+
+ return sb.toString();
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.type;
+
+/**
+ * @author Michal Kimle <kimle.michal@gmail.com>
+ */
+public interface Identifiable {
+
+ /**
+ * Returns identifier by which the object is recognized.
+ *
+ * @return object's identifier
+ */
+ public String getIdentifier();
+}
--- /dev/null
+package cz.cesnet.cloud.occi;
+
+import cz.cesnet.cloud.occi.core.Action;
+import cz.cesnet.cloud.occi.core.ActionInstance;
+import cz.cesnet.cloud.occi.core.Kind;
+import cz.cesnet.cloud.occi.core.Link;
+import cz.cesnet.cloud.occi.core.Resource;
+import java.net.URI;
+import static org.junit.Assert.assertEquals;
+import org.junit.Test;
+
+public class CollectionTest {
+
+ public CollectionTest() {
+ }
+
+ @Test
+ public void testSetModel() throws Exception {
+ Kind kind = new Kind(new URI("http://dummy.kind"), "term");
+ Resource resource = new Resource("resource_id", kind);
+ Link link = new Link("link_id", kind);
+ ActionInstance ai = new ActionInstance(new Action(new URI("http://dummy.action"), "term"));
+
+ Collection collection = new Collection();
+ collection.addAction(ai);
+ collection.addLink(link);
+ collection.addResource(resource);
+
+ Model model = new Model();
+ model.addKind(kind);
+
+ collection.setModel(model);
+
+ assertEquals(model, resource.getModel());
+ assertEquals(model, link.getModel());
+ assertEquals(model, ai.getModel());
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi;
+
+import cz.cesnet.cloud.occi.core.Action;
+import cz.cesnet.cloud.occi.core.ActionInstance;
+import cz.cesnet.cloud.occi.core.Attribute;
+import cz.cesnet.cloud.occi.core.Entity;
+import cz.cesnet.cloud.occi.core.Kind;
+import cz.cesnet.cloud.occi.core.Link;
+import cz.cesnet.cloud.occi.core.Mixin;
+import cz.cesnet.cloud.occi.core.Resource;
+import cz.cesnet.cloud.occi.exception.InvalidAttributeValueException;
+import cz.cesnet.cloud.occi.infrastructure.Compute;
+import cz.cesnet.cloud.occi.infrastructure.NetworkInterface;
+import cz.cesnet.cloud.occi.infrastructure.StorageLink;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class DataGenerator {
+
+ public static List<Kind> getMinimalKind() throws URISyntaxException {
+ List<Kind> kinds = new ArrayList<>();
+ Kind kind = new Kind(new URI("http://schemas.ogf.org/occi/core#"), "entity");
+ kind.setLocation(new URI("/entity/"));
+ kinds.add(kind);
+
+ return kinds;
+ }
+
+ public static List<Kind> getFiveKinds() throws URISyntaxException {
+ Set<Attribute> attributes = new HashSet<>();
+ List<Kind> kinds = new ArrayList<>();
+
+ Attribute a = new Attribute("occi.core.id");
+ attributes.add(a);
+ a = new Attribute("occi.core.title");
+ attributes.add(a);
+ Kind entity = new Kind(new URI("http://schemas.ogf.org/occi/core#"), "entity", "Entity", new URI("/entity/"), attributes);
+ kinds.add(entity);
+
+ attributes.clear();
+ a = new Attribute("occi.core.summary");
+ attributes.add(a);
+ Kind resource = new Kind(new URI("http://schemas.ogf.org/occi/core#"), "resource", "Resource", new URI("/resource/"), attributes);
+ resource.addRelation(entity);
+ resource.setParentKind(entity);
+ kinds.add(resource);
+
+ attributes.clear();
+ a = new Attribute("occi.core.target");
+ attributes.add(a);
+ a = new Attribute("occi.core.source");
+ attributes.add(a);
+ Kind link = new Kind(new URI("http://schemas.ogf.org/occi/core#"), "link", "Link", new URI("/link/"), attributes);
+ link.addRelation(entity);
+ link.setParentKind(entity);
+ kinds.add(link);
+
+ attributes.clear();
+ a = new Attribute("occi.compute.architecture", false, true);
+ attributes.add(a);
+ a = new Attribute("occi.compute.cores");
+ attributes.add(a);
+ a = new Attribute("occi.compute.hostname");
+ attributes.add(a);
+ a = new Attribute("occi.compute.speed");
+ attributes.add(a);
+ a = new Attribute("occi.compute.memory");
+ attributes.add(a);
+ a = new Attribute("occi.compute.state");
+ attributes.add(a);
+ Kind k = new Kind(new URI("http://schemas.ogf.org/occi/infrastructure#"), "compute", "Compute Resource", new URI("/compute/"), attributes);
+ Action ac = new Action(new URI("http://schemas.ogf.org/occi/infrastructure/compute/action#"), "start");
+ k.addAction(ac);
+ ac = new Action(new URI("http://schemas.ogf.org/occi/infrastructure/compute/action#"), "stop");
+ k.addAction(ac);
+ ac = new Action(new URI("http://schemas.ogf.org/occi/infrastructure/compute/action#"), "restart");
+ k.addAction(ac);
+ ac = new Action(new URI("http://schemas.ogf.org/occi/infrastructure/compute/action#"), "suspend");
+ k.addAction(ac);
+ k.addRelation(resource);
+ k.setParentKind(resource);
+ kinds.add(k);
+
+ attributes.clear();
+ a = new Attribute("occi.storagelink.deviceid", true, false);
+ attributes.add(a);
+ a = new Attribute("occi.storagelink.mountpoint");
+ attributes.add(a);
+ a = new Attribute("occi.storagelink.state", true, true);
+ attributes.add(a);
+ k = new Kind(new URI("http://schemas.ogf.org/occi/infrastructure#"), "storagelink", "Storage Link", new URI("/storagelink/"), attributes);
+ k.addRelation(link);
+ k.setParentKind(link);
+ kinds.add(k);
+
+ return kinds;
+ }
+
+ public static List<Mixin> getMinimalMixin() throws URISyntaxException {
+ List<Mixin> mixins = new ArrayList<>();
+ Mixin ostpl = new Mixin(new URI("http://schemas.ogf.org/occi/infrastructure#"), "os_tpl");
+ ostpl.setLocation(new URI("/mixins/os_tpl/"));
+ mixins.add(ostpl);
+
+ return mixins;
+ }
+
+ public static List<Mixin> getFiveMixins() throws URISyntaxException {
+ Set<Attribute> attributes = new HashSet<>();
+ List<Mixin> mixins = new ArrayList<>();
+
+ Mixin ostpl = new Mixin(new URI("http://schemas.ogf.org/occi/infrastructure#"), "os_tpl", "Operating System Template", new URI("/mixins/os_tpl/"), attributes);
+ mixins.add(ostpl);
+
+ attributes.clear();
+ Attribute a = new Attribute("occi.network.address", true, false);
+ attributes.add(a);
+ a = new Attribute("occi.network.gateway");
+ attributes.add(a);
+ a = new Attribute("occi.network.allocation");
+ attributes.add(a);
+ a = new Attribute("occi.network.state");
+ attributes.add(a);
+ Mixin m = new Mixin(new URI("http://schemas.ogf.org/occi/infrastructure/network#"), "ipnetwork", "IP Network Mixin", new URI("/mixins/ipnetwork/"), attributes);
+ mixins.add(m);
+
+ attributes.clear();
+ Mixin resourcetpl = new Mixin(new URI("http://schemas.ogf.org/occi/infrastructure#"), "resource_tpl", "Resource Template", new URI("/mixins/resource_tpl/"), attributes);
+ mixins.add(resourcetpl);
+
+ attributes.clear();
+ a = new Attribute("occi.compute.architecture");
+ attributes.add(a);
+ a = new Attribute("occi.compute.cores", true, true);
+ attributes.add(a);
+ a = new Attribute("occi.compute.speed");
+ attributes.add(a);
+ a = new Attribute("occi.compute.memory", false, true);
+ attributes.add(a);
+ m = new Mixin(new URI("https://occi.localhost/occi/infrastructure/resource_tpl#"), "larger", "Larger Instance - 4 cores and 10 GB of RAM", new URI("/mixins/larger/"), attributes);
+ m.addRelation(resourcetpl);
+ mixins.add(m);
+
+ attributes.clear();
+ m = new Mixin(new URI("https://occi.localhost/occi/infrastructure/os_tpl#"), "debianvm", "debianvm", new URI("/mixins/debianvm/"), attributes);
+ m.addRelation(ostpl);
+ mixins.add(m);
+
+ return mixins;
+ }
+
+ public static List<Action> getMinimalAction() throws URISyntaxException {
+ List<Action> actions = new ArrayList<>();
+ Action ac = new Action(new URI("http://schemas.ogf.org/occi/infrastructure/network/action#"), "up");
+ actions.add(ac);
+
+ return actions;
+ }
+
+ public static List<Action> getFiveActions() throws URISyntaxException {
+ List<Action> actions = new ArrayList<>();
+ Set<Attribute> attributes = new HashSet<>();
+
+ attributes.clear();
+ Attribute a = new Attribute("method");
+ attributes.add(a);
+ Action ac = new Action(new URI("http://schemas.ogf.org/occi/infrastructure/compute/action#"), "restart", "Restart Compute instance", attributes);
+ actions.add(ac);
+
+ attributes.clear();
+ a = new Attribute("method");
+ attributes.add(a);
+ ac = new Action(new URI("http://schemas.ogf.org/occi/infrastructure/compute/action#"), "suspend", "Suspend Compute instance", attributes);
+ actions.add(ac);
+
+ ac = new Action(new URI("http://schemas.ogf.org/occi/infrastructure/network/action#"), "up", "Activate network", null);
+ actions.add(ac);
+
+ ac = new Action(new URI("http://schemas.ogf.org/occi/infrastructure/network/action#"), "down", "Deactivate network", null);
+ actions.add(ac);
+
+ ac = new Action(new URI("http://schemas.ogf.org/occi/infrastructure/storage/action#"), "backup", "Backup Storage", null);
+ actions.add(ac);
+
+ return actions;
+ }
+
+ public static List<URI> getLocations() throws URISyntaxException {
+ List<URI> locations = new ArrayList<>();
+ locations.add(new URI("http://rocci-server-1-1-x.herokuapp.com:80/compute/87f3bfc3-42d4-4474-b45c-757e55e093e9"));
+ locations.add(new URI("http://rocci-server-1-1-x.herokuapp.com:80/compute/17679ebd-975f-4ea0-b42b-47405178c360"));
+ locations.add(new URI("http://rocci-server-1-1-x.herokuapp.com:80/compute/509afbd3-abff-427c-9b25-7913d17e5102"));
+
+ return locations;
+ }
+
+ public static Resource getResource() throws InvalidAttributeValueException, URISyntaxException {
+ Kind k = new Kind(new URI("http://schemas.ogf.org/occi/infrastructure#"), "compute", "compute resource", new URI("/compute/"), null);
+ Resource r = new Resource("87f3bfc3-42d4-4474-b45c-757e55e093e9", k);
+ r.setTitle("compute1");
+ r.addAttribute(Compute.ARCHITECTURE_ATTRIBUTE_NAME, "x86");
+ r.addAttribute(Compute.HOSTNAME_ATTRIBUTE_NAME, "compute1.example.org");
+ r.addAttribute(Compute.MEMORY_ATTRIBUTE_NAME, "1.7");
+ r.addAttribute(Compute.SPEED_ATTRIBUTE_NAME, "1.0");
+ r.addAttribute(Compute.STATE_ATTRIBUTE_NAME, "active");
+
+ List<Mixin> mixins = getFiveMixins();
+ for (Mixin mixin : mixins) {
+ r.addMixin(mixin);
+ }
+
+ List<Link> links = getLinks();
+ for (Link link : links) {
+ link.setSource(r);
+ r.addLink(link);
+ }
+
+ List<Action> actions = getActions();
+ for (Action action : actions) {
+ r.addAction(action);
+ }
+
+ return r;
+ }
+
+ public static List<Action> getActions() throws URISyntaxException {
+ List<Action> actions = new ArrayList<>();
+ actions.add(new Action(new URI("http://schemas.ogf.org/occi/infrastructure/compute/action#"), "start"));
+ actions.add(new Action(new URI("http://schemas.ogf.org/occi/infrastructure/compute/action#"), "stop"));
+
+ return actions;
+ }
+
+ public static List<Link> getLinks() throws URISyntaxException, InvalidAttributeValueException {
+ List<Link> links = new ArrayList<>();
+
+ Kind k = new Kind(new URI("http://schemas.ogf.org/occi/infrastructure#"), "networkinterface", null, new URI("/link/networkinterface/"), null);
+ Link l = new Link("456", k);
+ l.addAttribute(NetworkInterface.INTERFACE_ATTRIBUTE_NAME, "eth0");
+ l.addAttribute(NetworkInterface.MAC_ATTRIBUTE_NAME, "00:11:22:33:44:55");
+ l.addAttribute(NetworkInterface.STATE_ATTRIBUTE_NAME, "active");
+ l.setTarget("/network/123");
+ l.setRelation("http://schemas.ogf.org/occi/infrastructure#network");
+ links.add(l);
+
+ k = new Kind(new URI("http://schemas.ogf.org/occi/infrastructure#"), "storagelink", null, new URI("/link/storagelink/"), null);
+ l = new Link("789", k);
+ l.addAttribute(StorageLink.DEVICE_ID_ATTRIBUTE_NAME, "1234qwerty");
+ l.addAttribute(StorageLink.MOUNTPOINT_ATTRIBUTE_NAME, "/mnt/somewhere/");
+ l.addAttribute(StorageLink.STATE_ATTRIBUTE_NAME, "active");
+ l.setTarget("/storage/852");
+ l.setRelation("http://schemas.ogf.org/occi/infrastructure#storage");
+
+ Mixin m = new Mixin(new URI("http://opennebula.org/occi/infrastructure#"), "storagelink");
+ l.addMixin(m);
+
+ links.add(l);
+
+ return links;
+ }
+
+ public static Link getLink() throws InvalidAttributeValueException, URISyntaxException {
+ Kind k = new Kind(new URI("http://schemas.ogf.org/occi/infrastructure#"), "networkinterface", null, null, null);
+ Link l = new Link("87f3bfc3-42d4-4474-b45c-757e55e093e9", k);
+ l.addAttribute(NetworkInterface.INTERFACE_ATTRIBUTE_NAME, "eth0");
+ l.addAttribute(NetworkInterface.MAC_ATTRIBUTE_NAME, "00:11:22:33:44:55");
+ l.addAttribute(NetworkInterface.STATE_ATTRIBUTE_NAME, "active");
+ l.setSource("/vms/foo/vm1");
+ l.setTarget("/network/123");
+
+ List<Mixin> mixins = getFiveMixins();
+ for (Mixin mixin : mixins) {
+ l.addMixin(mixin);
+ }
+
+ return l;
+ }
+
+ public static ActionInstance getAction() throws InvalidAttributeValueException, URISyntaxException {
+ Action a = new Action(new URI("http://schemas.ogf.org/occi/infrastructure/storage/action#"), "backup", "Backup Storage", null);
+ ActionInstance ai = new ActionInstance(a);
+ ai.addAttribute(new Attribute(Entity.ID_ATTRIBUTE_NAME), "87f3bfc3-42d4-4474-b45c-757e55e093e9");
+ ai.addAttribute(new Attribute(NetworkInterface.INTERFACE_ATTRIBUTE_NAME), "eth0");
+ ai.addAttribute(new Attribute(NetworkInterface.MAC_ATTRIBUTE_NAME), "00:11:22:33:44:55");
+ ai.addAttribute(new Attribute(NetworkInterface.STATE_ATTRIBUTE_NAME), "active");
+ ai.addAttribute(new Attribute(Link.SOURCE_ATTRIBUTE_NAME), "/vms/foo/vm1");
+ ai.addAttribute(new Attribute(Link.TARGET_ATTRIBUTE_NAME), "/network/123");
+
+ return ai;
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi;
+
+import cz.cesnet.cloud.occi.core.Action;
+import cz.cesnet.cloud.occi.core.Kind;
+import cz.cesnet.cloud.occi.core.Mixin;
+import cz.cesnet.cloud.occi.exception.AmbiguousIdentifierException;
+import cz.cesnet.cloud.occi.parser.CollectionType;
+import java.net.URI;
+import static java.util.Collections.list;
+import java.util.HashSet;
+import java.util.Set;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ModelTest {
+
+ private Model model;
+
+ public ModelTest() {
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ model = new Model();
+
+ for (Kind kind : DataGenerator.getFiveKinds()) {
+ model.addKind(kind);
+ }
+
+ for (Mixin mixin : DataGenerator.getFiveMixins()) {
+ model.addMixin(mixin);
+ }
+
+ for (Action action : DataGenerator.getFiveActions()) {
+ model.addAction(action);
+ }
+ }
+
+ @Test
+ public void testFindKindWithURI() throws Exception {
+ assertEquals(DataGenerator.getFiveKinds().get(2), model.findKind(URI.create("http://schemas.ogf.org/occi/core#link")));
+ assertNull(model.findKind(URI.create("http://nonexisting.abc.org/icco/core#link")));
+ }
+
+ @Test
+ public void testFindKindWithString() throws Exception {
+ assertEquals(DataGenerator.getFiveKinds().get(2), model.findKind("link"));
+ assertNull(model.findKind("nonexisting"));
+ }
+
+ @Test
+ public void testInvalidFindKindWithString() throws Exception {
+ Kind link = new Kind(new URI("http://different.uri.same/term/core#"), "link", "Link", new URI("/link/"), null);
+ model.addKind(link);
+
+ try {
+ model.findKind("link");
+ fail();
+ } catch (AmbiguousIdentifierException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testFindRelatedKindsWithURI() throws Exception {
+ Set<Kind> set = new HashSet<>();
+ set.add(DataGenerator.getFiveKinds().get(1));
+ set.add(DataGenerator.getFiveKinds().get(2));
+
+ assertEquals(set, new HashSet(model.findRelatedKinds(URI.create("http://schemas.ogf.org/occi/core#entity"))));
+ }
+
+ @Test
+ public void testFindRelatedKindsWithString() throws Exception {
+ Set<Kind> set = new HashSet<>();
+ set.add(DataGenerator.getFiveKinds().get(1));
+ set.add(DataGenerator.getFiveKinds().get(2));
+
+ assertEquals(set, new HashSet(model.findRelatedKinds("entity")));
+ }
+
+ @Test
+ public void testInvalidFindRelatedKindsWithString() throws Exception {
+ Kind kind = new Kind(new URI("http://different.uri.same/term/core#"), "entity", "Entity", new URI("/entity/"), null);
+ model.addKind(kind);
+
+ try {
+ model.findRelatedKinds("entity");
+ fail();
+ } catch (AmbiguousIdentifierException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testFindKindTypeWithKind() throws Exception {
+ assertNull(model.findKindType(DataGenerator.getFiveKinds().get(0)));
+ assertEquals(CollectionType.RESOURCE, model.findKindType(DataGenerator.getFiveKinds().get(1)));
+ assertEquals(CollectionType.LINK, model.findKindType(DataGenerator.getFiveKinds().get(2)));
+ assertEquals(CollectionType.RESOURCE, model.findKindType(DataGenerator.getFiveKinds().get(3)));
+ assertEquals(CollectionType.LINK, model.findKindType(DataGenerator.getFiveKinds().get(4)));
+ }
+
+ @Test
+ public void testFindKindTypeWithString() throws Exception {
+ assertNull(model.findKindType("/entity/"));
+ assertEquals(CollectionType.RESOURCE, model.findKindType("/resource/"));
+ assertEquals(CollectionType.LINK, model.findKindType("/link/"));
+ assertEquals(CollectionType.RESOURCE, model.findKindType("/compute/"));
+ assertEquals(CollectionType.LINK, model.findKindType("/storagelink/"));
+ }
+
+ @Test
+ public void testFindMixinWithURI() throws Exception {
+ assertEquals(DataGenerator.getFiveMixins().get(2), model.findMixin(URI.create("http://schemas.ogf.org/occi/infrastructure#resource_tpl")));
+ assertNull(model.findMixin(URI.create("http://nonexisting.abc.org/icco/core#mixin")));
+ }
+
+ @Test
+ public void testFindMixinWithString() throws Exception {
+ assertEquals(DataGenerator.getFiveMixins().get(2), model.findMixin("resource_tpl"));
+ assertNull(model.findMixin("nonexisting"));
+ }
+
+ @Test
+ public void testInvalidFindMixinWithString() throws Exception {
+ Mixin resourcetpl = new Mixin(new URI("http://different.uri.same/term/core#"), "resource_tpl", "Resource Template", new URI("/mixins/resource_tpl/"), null);
+ model.addMixin(resourcetpl);
+
+ try {
+ model.findMixin("resource_tpl");
+ fail();
+ } catch (AmbiguousIdentifierException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testFindMixinWithStringAndString() throws Exception {
+ assertEquals(DataGenerator.getFiveMixins().get(3), model.findMixin("larger", "resource_tpl"));
+ assertNull(model.findMixin("larger", "nonexisting"));
+ assertNull(model.findMixin("nonexisting", "resource_tpl"));
+ }
+
+ @Test
+ public void testInvalidFindMixinWithStringAndString() throws Exception {
+ try {
+ Mixin m = new Mixin(new URI("http://different.uri.same/term/resource_tpl#"), "larger", "Larger Instance - 4 cores and 10 GB of RAM", new URI("/mixins/larger/"), null);
+ m.addRelation(model.findMixin("resource_tpl"));
+ model.addMixin(m);
+ model.findMixin("larger", "resource_tpl");
+ fail();
+ } catch (AmbiguousIdentifierException ex) {
+ //cool
+ }
+
+ try {
+ setUp();
+ Mixin resourcetpl = new Mixin(new URI("http://different.uri.same/term/core#"), "resource_tpl", "Resource Template", new URI("/mixins/resource_tpl/"), null);
+ model.addMixin(resourcetpl);
+ model.findMixin("larger", "resource_tpl");
+ fail();
+ } catch (AmbiguousIdentifierException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testFindMixinWithStringAndURI() throws Exception {
+ assertEquals(DataGenerator.getFiveMixins().get(3), model.findMixin("larger", URI.create("http://schemas.ogf.org/occi/infrastructure#resource_tpl")));
+ assertNull(model.findMixin("larger", URI.create("http://nonexisting.abc.org/icco/core#mixin")));
+ assertNull(model.findMixin("nonexisting", URI.create("http://schemas.ogf.org/occi/infrastructure#resource_tpl")));
+ }
+
+ @Test
+ public void testInvalidFindMixinWithStringAndURI() throws Exception {
+ try {
+ Mixin m = new Mixin(new URI("http://different.uri.same/term/resource_tpl#"), "larger", "Larger Instance - 4 cores and 10 GB of RAM", new URI("/mixins/larger/"), null);
+ m.addRelation(model.findMixin("resource_tpl"));
+ model.addMixin(m);
+ model.findMixin("larger", "resource_tpl");
+ fail();
+ } catch (AmbiguousIdentifierException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testFindRelatedMixinsWithURI() throws Exception {
+ Set<Mixin> set = new HashSet<>();
+ set.add(DataGenerator.getFiveMixins().get(4));
+ Mixin m = new Mixin(new URI("https://occi.localhost/occi/infrastructure/os_tpl#"), "archlinux", "archlinux", new URI("/mixins/archlinux/"), null);
+ m.addRelation(model.findMixin("os_tpl"));
+ model.addMixin(m);
+ set.add(m);
+
+ assertEquals(set, new HashSet(model.findRelatedMixins(URI.create("http://schemas.ogf.org/occi/infrastructure#os_tpl"))));
+ }
+
+ @Test
+ public void testFindRelatedMixinsWithString() throws Exception {
+ Set<Mixin> set = new HashSet<>();
+ set.add(DataGenerator.getFiveMixins().get(4));
+ Mixin m = new Mixin(new URI("https://occi.localhost/occi/infrastructure/os_tpl#"), "archlinux", "archlinux", new URI("/mixins/archlinux/"), null);
+ m.addRelation(model.findMixin("os_tpl"));
+ model.addMixin(m);
+ set.add(m);
+
+ assertEquals(set, new HashSet(model.findRelatedMixins("os_tpl")));
+ }
+
+ @Test
+ public void testInvalidFindRelatedMixinsWithString() throws Exception {
+ Mixin mixin = new Mixin(new URI("http://different.uri.same/term/core#"), "os_tpl", "Operating System Template", new URI("/mixins/os_tpl/"), null);
+ model.addMixin(mixin);
+
+ try {
+ model.findRelatedMixins("os_tpl");
+ fail();
+ } catch (AmbiguousIdentifierException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testFindActionWithString() throws Exception {
+ assertEquals(DataGenerator.getFiveActions().get(2), model.findAction("up"));
+ assertNull(model.findAction("nonexisting"));
+ }
+
+ @Test
+ public void testInvalidFindActionWithString() throws Exception {
+ Action ac = new Action(new URI("http://different.uri.same/term/network/action#"), "up", "Activate network", null);
+ model.addAction(ac);
+
+ try {
+ model.findAction("up");
+ fail();
+ } catch (AmbiguousIdentifierException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testFindActionWithURI() throws Exception {
+ assertEquals(DataGenerator.getFiveActions().get(2), model.findAction(URI.create("http://schemas.ogf.org/occi/infrastructure/network/action#up")));
+ assertNull(model.findAction(URI.create("http://nonexisting.abc.org/icco/core#action")));
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+
+public class TestHelper {
+
+ public static String readFile(String filename) throws IOException {
+ File f = new File(filename);
+ String fileContent = new String(Files.readAllBytes(f.toPath()));
+ return fileContent;
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.collection;
+
+import com.sun.net.httpserver.Headers;
+import cz.cesnet.cloud.occi.core.Attribute;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.Test;
+import static org.junit.Assert.*;
+import org.junit.Before;
+
+public class AttributeMapCoverTest {
+
+ private final AttributeMapCover attrMap = new AttributeMapCover();
+
+ @Before
+ public void setUp() {
+ attrMap.add(new Attribute("occi.core.id"), "87f3bfc3-42d4-4474-b45c-757e55e093e9");
+ attrMap.add(new Attribute("occi.core.title"), "compute1");
+ attrMap.add(new Attribute("occi.compute.architecture"), "x86");
+ attrMap.add(new Attribute("occi.compute.hostname"), "compute1.example.org");
+ attrMap.add(new Attribute("occi.compute.memory"), "1.7");
+ attrMap.add(new Attribute("occi.compute.speed"), "1.0");
+ }
+
+ @Test
+ public void testAdd() {
+ AttributeMapCover instance = new AttributeMapCover();
+ assertEquals(0, instance.size());
+ instance.add(new Attribute("name"), "value");
+ assertEquals(1, instance.size());
+ assertTrue(instance.containsAttribute("name"));
+ }
+
+ @Test
+ public void testInvalidAdd() {
+ AttributeMapCover instance = new AttributeMapCover();
+ try {
+ instance.add(null, "aaa");
+ fail();
+ } catch (NullPointerException ex) {
+ //cool
+ }
+
+ try {
+ instance.add(new Attribute("aaa"), null);
+ fail();
+ } catch (NullPointerException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testRemoveWithAttribute() {
+ assertEquals(6, attrMap.size());
+ attrMap.remove(new Attribute("occi.core.id"));
+ assertEquals(5, attrMap.size());
+ assertFalse(attrMap.containsAttribute("occi.core.id"));
+ }
+
+ @Test
+ public void testRemoveWithString() {
+ assertEquals(6, attrMap.size());
+ attrMap.remove("occi.core.id");
+ assertEquals(5, attrMap.size());
+ assertFalse(attrMap.containsAttribute("occi.core.id"));
+ }
+
+ @Test
+ public void testContainsAttributeWithAttribute() {
+ assertTrue(attrMap.containsAttribute(new Attribute("occi.core.id")));
+ assertTrue(attrMap.containsAttribute(new Attribute("occi.compute.architecture")));
+ assertFalse(attrMap.containsAttribute(new Attribute("nonexisting_attribute")));
+ }
+
+ @Test
+ public void testContainsAttributeWithString() {
+ assertTrue(attrMap.containsAttribute("occi.core.id"));
+ assertTrue(attrMap.containsAttribute("occi.compute.architecture"));
+ assertFalse(attrMap.containsAttribute("nonexisting_attribute"));
+ }
+
+ @Test
+ public void testGetValueWithAttribute() {
+ assertEquals("compute1", attrMap.getValue(new Attribute("occi.core.title")));
+ assertEquals("x86", attrMap.getValue(new Attribute("occi.compute.architecture")));
+ assertNull(attrMap.getValue(new Attribute("nonexisting_attribute")));
+ }
+
+ @Test
+ public void testGetValueWithString() {
+ assertEquals("compute1", attrMap.getValue("occi.core.title"));
+ assertEquals("x86", attrMap.getValue("occi.compute.architecture"));
+ assertNull(attrMap.getValue("nonexisting_attribute"));
+ }
+
+ @Test
+ public void testGetAttributes() {
+ Map<Attribute, String> map = new HashMap<>();
+ map.put(new Attribute("occi.core.id"), "87f3bfc3-42d4-4474-b45c-757e55e093e9");
+ map.put(new Attribute("occi.core.title"), "compute1");
+ map.put(new Attribute("occi.compute.architecture"), "x86");
+ map.put(new Attribute("occi.compute.hostname"), "compute1.example.org");
+ map.put(new Attribute("occi.compute.memory"), "1.7");
+ map.put(new Attribute("occi.compute.speed"), "1.0");
+
+ assertEquals(map, attrMap.getAttributes());
+ }
+
+ @Test
+ public void testClear() {
+ assertEquals(6, attrMap.size());
+ attrMap.clear();
+ assertEquals(0, attrMap.size());
+ }
+
+ @Test
+ public void testToOneLineText() {
+ String line = "occi.compute.architecture=\"x86\";occi.compute.hostname=\"compute1.example.org\";occi.compute.memory=1.7;occi.compute.speed=1.0;occi.core.id=\"87f3bfc3-42d4-4474-b45c-757e55e093e9\";occi.core.title=\"compute1\";";
+
+ assertEquals(line, attrMap.toOneLineText());
+ }
+
+ @Test
+ public void testToPrefixText() {
+ String line = "X-OCCI-Attribute: occi.compute.architecture=\"x86\"\nX-OCCI-Attribute: occi.compute.hostname=\"compute1.example.org\"\nX-OCCI-Attribute: occi.compute.memory=1.7\nX-OCCI-Attribute: occi.compute.speed=1.0\nX-OCCI-Attribute: occi.core.id=\"87f3bfc3-42d4-4474-b45c-757e55e093e9\"\nX-OCCI-Attribute: occi.core.title=\"compute1\"";
+
+ assertEquals(line, attrMap.toPrefixText());
+ }
+
+ @Test
+ public void testToHeaders() {
+ Headers headers = new Headers();
+ headers.add("X-OCCI-Attribute", "occi.compute.architecture=\"x86\"");
+ headers.add("X-OCCI-Attribute", "occi.compute.hostname=\"compute1.example.org\"");
+ headers.add("X-OCCI-Attribute", "occi.compute.memory=1.7");
+ headers.add("X-OCCI-Attribute", "occi.compute.speed=1.0");
+ headers.add("X-OCCI-Attribute", "occi.core.id=\"87f3bfc3-42d4-4474-b45c-757e55e093e9\"");
+ headers.add("X-OCCI-Attribute", "occi.core.title=\"compute1\"");
+
+ assertEquals(headers, attrMap.toHeaders());
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.collection;
+
+import cz.cesnet.cloud.occi.core.Mixin;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.junit.Test;
+import static org.junit.Assert.*;
+import org.junit.Before;
+
+public class SetCoverTest {
+
+ private SetCover<Mixin> set = new SetCover<>();
+
+ @Before
+ public void setUp() throws Exception {
+ set.add(new Mixin(new URI("http://dummy.mixin1/"), "term1"));
+ set.add(new Mixin(new URI("http://dummy.mixin2/"), "term2"));
+ set.add(new Mixin(new URI("http://dummy.mixin3/"), "term3"));
+ }
+
+ @Test
+ public void testContainsWithGenericType() throws Exception {
+ assertTrue(set.contains(new Mixin(new URI("http://dummy.mixin1/"), "term1")));
+ assertFalse(set.contains(new Mixin(new URI("http://nonexisting.mixin/"), "aaa")));
+ }
+
+ @Test
+ public void testContainsWithString() {
+ assertTrue(set.contains("http://dummy.mixin1/term1"));
+ assertFalse(set.contains("http://nonexisting.mixin/aaa"));
+ }
+
+ @Test
+ public void testAdd() throws Exception {
+ SetCover<Mixin> set = new SetCover<>();
+ assertEquals(0, set.size());
+ set.add(new Mixin(new URI("http://dummy.mixin1/"), "term1"));
+ assertEquals(1, set.size());
+ assertTrue(set.contains("http://dummy.mixin1/term1"));
+ }
+
+ @Test
+ public void testInvalidAdd() {
+ try {
+ set.add(null);
+ fail();
+ } catch (NullPointerException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testAddAll() throws Exception {
+ List<Mixin> list = new ArrayList<>();
+ list.add(new Mixin(new URI("http://dummy.mixin1/"), "term1"));
+ list.add(new Mixin(new URI("http://dummy.mixin2/"), "term2"));
+ list.add(new Mixin(new URI("http://dummy.mixin3/"), "term3"));
+
+ SetCover<Mixin> set = new SetCover<>();
+ assertEquals(0, set.size());
+ set.addAll(list);
+ assertEquals(3, set.size());
+ }
+
+ @Test
+ public void testInvalidAddAll() throws Exception {
+ List<Mixin> list = new ArrayList<>();
+ list.add(new Mixin(new URI("http://dummy.mixin1/"), "term1"));
+ list.add(null);
+ list.add(new Mixin(new URI("http://dummy.mixin3/"), "term3"));
+
+ try {
+ set.addAll(list);
+ fail();
+ } catch (NullPointerException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testGet() throws Exception {
+ assertEquals(new Mixin(new URI("http://dummy.mixin1/"), "term1"), set.get("http://dummy.mixin1/term1"));
+ assertNull(set.get("nonexisting_element"));
+ }
+
+ @Test
+ public void testRemove() throws Exception {
+ assertEquals(3, set.size());
+ set.remove(new Mixin(new URI("http://dummy.mixin1/"), "term1"));
+ assertEquals(2, set.size());
+ assertFalse(set.contains("http://dummy.mixin1/term1"));
+ }
+
+ @Test
+ public void testInvalidRemove() {
+ try {
+ set.remove(null);
+ fail();
+ } catch (NullPointerException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testClear() {
+ assertEquals(3, set.size());
+ set.clear();
+ assertEquals(0, set.size());
+ }
+
+ @Test
+ public void testGetSet() throws Exception {
+ Set<Mixin> expected = new HashSet<>();
+ expected.add(new Mixin(new URI("http://dummy.mixin1/"), "term1"));
+ expected.add(new Mixin(new URI("http://dummy.mixin2/"), "term2"));
+ expected.add(new Mixin(new URI("http://dummy.mixin3/"), "term3"));
+
+ assertEquals(expected, set.getSet());
+ }
+
+ @Test
+ public void testSize() throws Exception {
+ assertEquals(3, set.size());
+ set.add(new Mixin(new URI("http://dummy.mixin4/"), "term4"));
+ assertEquals(4, set.size());
+ set.remove(new Mixin(new URI("http://dummy.mixin2/"), "term2"));
+ assertEquals(3, set.size());
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.core;
+
+import com.sun.net.httpserver.Headers;
+import cz.cesnet.cloud.occi.DataGenerator;
+import cz.cesnet.cloud.occi.TestHelper;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.net.URI;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class ActionInstanceTest {
+
+ private static final String RESOURCE_PATH = "src/test/resources/rendering/text/";
+
+ @Test
+ public void testConstructor() throws Exception {
+ Action action = new Action(new URI("http://dummy.action/"), "term");
+ ActionInstance ai = new ActionInstance(action);
+ assertEquals(action, ai.getAction());
+ }
+
+ @Test
+ public void testInvalidConstructor() {
+ try {
+ ActionInstance ai = new ActionInstance(null);
+ fail();
+ } catch (NullPointerException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testInvalidSetAction() throws Exception {
+ try {
+ Action action = new Action(new URI("http://dummy.action/"), "term");
+ ActionInstance ai = new ActionInstance(action);
+ ai.setAction(null);
+ fail();
+ } catch (NullPointerException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testToText() throws Exception {
+ String expected = TestHelper.readFile(RESOURCE_PATH + "action_plain.txt");
+ ActionInstance ai = DataGenerator.getAction();
+
+ assertEquals(expected, ai.toText());
+ }
+
+ @Test
+ public void testToHeaders() throws Exception {
+ Headers headers = new Headers();
+ ActionInstance ai = DataGenerator.getAction();
+
+ headers.add("Category", TestHelper.readFile(RESOURCE_PATH + "action_headers_category.txt"));
+
+ try (BufferedReader br = new BufferedReader(new FileReader(RESOURCE_PATH + "action_headers_attributes.txt"))) {
+ String line = br.readLine();
+ while (line != null) {
+ headers.add("X-OCCI-Attribute", line);
+ line = br.readLine();
+ }
+ }
+
+ assertEquals(headers, ai.toHeaders());
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.core;
+
+import com.sun.net.httpserver.Headers;
+import cz.cesnet.cloud.occi.infrastructure.Compute;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.HashSet;
+import java.util.Set;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class ActionTest {
+
+ @Test
+ public void testFullConstructor() throws URISyntaxException {
+ Set<Attribute> attributes = new HashSet<>();
+ attributes.add(new Attribute("aaa"));
+ attributes.add(new Attribute("bbb"));
+ attributes.add(new Attribute("ccc"));
+ Action action = new Action(Compute.SCHEME_DEFAULT, "start", "Start", attributes);
+
+ assertEquals(action.getAttributes(), attributes);
+ assertEquals(action.getScheme(), Compute.SCHEME_DEFAULT);
+ assertEquals(action.getTerm(), "start");
+ assertEquals(action.getTitle(), "Start");
+ }
+
+ @Test
+ public void testMinimalConstructor() throws URISyntaxException {
+ Action action = new Action(Compute.SCHEME_DEFAULT, "start");
+
+ assertEquals(action.getScheme(), Compute.SCHEME_DEFAULT);
+ assertEquals(action.getTerm(), "start");
+ }
+
+ @Test
+ public void testInvalidConstructor() throws URISyntaxException {
+ try {
+ Action action = new Action(null, Entity.TERM_DEFAULT);
+ fail();
+ } catch (NullPointerException ex) {
+ //cool
+ }
+
+ try {
+ Action action = new Action(Category.SCHEME_CORE_DEFAULT, null);
+ fail();
+ } catch (NullPointerException ex) {
+ //cool
+ }
+
+ try {
+ Action action = new Action(Category.SCHEME_CORE_DEFAULT, "");
+ fail();
+ } catch (IllegalArgumentException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testToText() throws Exception {
+ String expected = "Link: </compute/123?action=start>;rel=\"http://schemas.ogf.org/occi/infrastructure/compute/action#start\";";
+ Action action = new Action(new URI("http://schemas.ogf.org/occi/infrastructure/compute/action#"), "start");
+
+ assertEquals(expected, action.toText("/compute/123"));
+ }
+
+ @Test
+ public void testToHeaders() throws Exception {
+ Headers headers = new Headers();
+ headers.add("Link", "</compute/123?action=start>;rel=\"http://schemas.ogf.org/occi/infrastructure/compute/action#start\";");
+
+ Action action = new Action(new URI("http://schemas.ogf.org/occi/infrastructure/compute/action#"), "start");
+
+ assertEquals(headers, action.toHeaders("/compute/123"));
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.core;
+
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class AttributeTest {
+
+ @Test
+ public void testConstructor() {
+ Attribute a = new Attribute("name", true, false, "type", "pattern", "defaultValue", "description");
+
+ assertEquals("name", a.getName());
+ assertEquals("type", a.getType());
+ assertEquals("pattern", a.getPattern());
+ assertEquals("defaultValue", a.getDefaultValue());
+ assertEquals("description", a.getDescription());
+ assertTrue(a.isRequired());
+ assertFalse(a.isImmutable());
+
+ a = new Attribute("name", true, false, "type", null, "defaultValue", "description");
+ assertEquals(".*", a.getPattern());
+ }
+
+ @Test
+ public void testInvalidConstructor() {
+ try {
+ Attribute a = new Attribute(null);
+ fail();
+ } catch (NullPointerException ex) {
+ //cool
+ }
+
+ try {
+ Attribute a = new Attribute("");
+ fail();
+ } catch (IllegalArgumentException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testInvalidSetName() {
+ try {
+ Attribute a = new Attribute("name");
+ a.setName(null);
+ fail();
+ } catch (NullPointerException ex) {
+ //cool
+ }
+
+ try {
+ Attribute a = new Attribute("name");
+ a.setName("");
+ fail();
+ } catch (IllegalArgumentException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testToText() {
+ Attribute a = new Attribute("attribute_name");
+ assertEquals(a.toText(), "attribute_name");
+
+ a.setRequired(true);
+ assertEquals(a.toText(), "attribute_name{required}");
+
+ a.setImmutable(true);
+ assertEquals(a.toText(), "attribute_name{required immutable}");
+
+ a.setRequired(false);
+ assertEquals(a.toText(), "attribute_name{immutable}");
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.core;
+
+import static org.junit.Assert.fail;
+import org.junit.Test;
+import org.junit.Before;
+
+public class CategoryTest {
+
+ private Category category;
+
+ @Before
+ public void setUp() {
+ category = new Category(Category.SCHEME_CORE_DEFAULT, Entity.TERM_DEFAULT);
+ }
+
+ @Test
+ public void testInvalidSetTerm() {
+ try {
+ category.setTerm(null);
+ fail();
+ } catch (NullPointerException ex) {
+ //cool
+ }
+
+ try {
+ category.setTerm("");
+ fail();
+ } catch (IllegalArgumentException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testInvalidSetScheme() {
+ try {
+ category.setScheme(null);
+ fail();
+ } catch (NullPointerException ex) {
+ //cool
+ }
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.core;
+
+import cz.cesnet.cloud.occi.Model;
+import cz.cesnet.cloud.occi.exception.InvalidAttributeValueException;
+import cz.cesnet.cloud.occi.infrastructure.NetworkInterface;
+import org.junit.Test;
+import static org.junit.Assert.*;
+import org.junit.Before;
+
+public class EntityTest {
+
+ private Entity entity;
+ private Kind kind;
+ private Model model;
+ private Mixin mixin;
+
+ @Before
+ public void setUp() throws Exception {
+ kind = new Kind(Entity.SCHEME_DEFAULT, Entity.TERM_DEFAULT);
+ mixin = new Mixin(NetworkInterface.SCHEME_DEFAULT, NetworkInterface.TERM_DEFAULT);
+ model = new Model();
+ model.addKind(kind);
+ entity = new Link("link_id", kind);
+ }
+
+ @Test
+ public void testConstructor() throws Exception {
+ Entity entity = new Link("entity_id", kind, "title", model);
+
+ assertEquals("entity_id", entity.getId());
+ assertEquals(kind, entity.getKind());
+ assertEquals("title", entity.getTitle());
+ assertEquals(model, entity.getModel());
+ }
+
+ @Test
+ public void testInvalidConstructor() throws Exception {
+ try {
+ Entity entity = new Link(null, kind, "title", model);
+ fail();
+ } catch (NullPointerException ex) {
+ //cool
+ }
+
+ try {
+ Entity entity = new Link("entity_id", null, "title", model);
+ fail();
+ } catch (NullPointerException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testInvalidSetId() throws Exception {
+ try {
+ entity.setId(null);
+ fail();
+ } catch (NullPointerException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testInvalidSetKind() throws Exception {
+ try {
+ entity.setKind(null);
+ fail();
+ } catch (NullPointerException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testAddAttribute() throws Exception {
+ Attribute attrKind = new Attribute("attrKind");
+ attrKind.setPattern("xyz");
+ kind.addAttribute(attrKind);
+ Attribute attrMixin = new Attribute("attrMixin");
+ attrMixin.setPattern("abc");
+ mixin.addAttribute(attrMixin);
+ entity.addMixin(mixin);
+
+ entity.addAttribute("attrKind", "xyz");
+ entity.addAttribute("attrMixin", "abc");
+ entity.addAttribute("nonexistingAttribute", "value");
+
+ assertEquals("xyz", entity.getValue("attrKind"));
+ assertEquals("xyz", entity.getValue(attrKind));
+ assertEquals("abc", entity.getValue("attrMixin"));
+ assertEquals("abc", entity.getValue(attrMixin));
+ assertEquals("value", entity.getValue("nonexistingAttribute"));
+ }
+
+ @Test
+ public void testInvalidAddAttribute() {
+ Attribute attrKind = new Attribute("attrKind");
+ attrKind.setPattern("xyz");
+ kind.addAttribute(attrKind);
+ Attribute attrMixin = new Attribute("attrMixin");
+ attrMixin.setPattern("abc");
+ mixin.addAttribute(attrMixin);
+ entity.addMixin(mixin);
+
+ try {
+ entity.addAttribute("attrKind", "abc");
+ fail();
+ } catch (InvalidAttributeValueException ex) {
+ //cool
+ }
+
+ try {
+ entity.addAttribute("attrMixin", "xyz");
+ fail();
+ } catch (InvalidAttributeValueException ex) {
+ //cool
+ }
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.core;
+
+import com.sun.net.httpserver.Headers;
+import cz.cesnet.cloud.occi.TestHelper;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.HashSet;
+import java.util.Set;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class KindTest {
+
+ private static final String RESOURCE_PATH = "src/test/resources/rendering/text/";
+
+ @Test
+ public void testFullConstructor() throws URISyntaxException {
+ Set<Attribute> attributes = new HashSet<>();
+ attributes.add(new Attribute("aaa"));
+ attributes.add(new Attribute("bbb"));
+ attributes.add(new Attribute("ccc"));
+ Kind kind = new Kind(Category.SCHEME_CORE_DEFAULT, Entity.TERM_DEFAULT, "title", new URI("/location/"), attributes);
+
+ assertEquals(kind.getAttributes(), attributes);
+ assertEquals(kind.getLocation(), new URI("/location/"));
+ assertEquals(kind.getScheme(), Category.SCHEME_CORE_DEFAULT);
+ assertEquals(kind.getTerm(), Entity.TERM_DEFAULT);
+ assertEquals(kind.getTitle(), "title");
+ }
+
+ @Test
+ public void testMinimalConstructor() throws URISyntaxException {
+ Kind kind = new Kind(Category.SCHEME_CORE_DEFAULT, Entity.TERM_DEFAULT);
+
+ assertEquals(kind.getScheme(), Category.SCHEME_CORE_DEFAULT);
+ assertEquals(kind.getTerm(), Entity.TERM_DEFAULT);
+ }
+
+ @Test
+ public void testInvalidConstructor() throws URISyntaxException {
+ try {
+ Kind kind = new Kind(null, Entity.TERM_DEFAULT);
+ fail();
+ } catch (NullPointerException ex) {
+ //cool
+ }
+
+ try {
+ Kind kind = new Kind(Category.SCHEME_CORE_DEFAULT, null);
+ fail();
+ } catch (NullPointerException ex) {
+ //cool
+ }
+
+ try {
+ Kind kind = new Kind(Category.SCHEME_CORE_DEFAULT, "");
+ fail();
+ } catch (IllegalArgumentException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testToText() throws Exception {
+ String[] lines = TestHelper.readFile(RESOURCE_PATH + "kind_plain.txt").split("\n");
+ Attribute at1 = new Attribute(Entity.ID_ATTRIBUTE_NAME);
+ Attribute at2 = new Attribute(Entity.TITLE_ATTRIBUTE_NAME);
+
+ Action a1 = new Action(new URI("http://schemas.ogf.org/occi/infrastructure/compute/action#"), "start");
+ Action a2 = new Action(new URI("http://schemas.ogf.org/occi/infrastructure/compute/action#"), "stop");
+
+ Kind kind = new Kind(Category.SCHEME_CORE_DEFAULT, Entity.TERM_DEFAULT);
+ assertEquals(lines[0], kind.toText());
+
+ kind.setTitle("Entity");
+ assertEquals(lines[1], kind.toText());
+
+ kind.setTitle(null);
+ kind.setLocation(new URI("/entity/"));
+ assertEquals(lines[2], kind.toText());
+
+ kind.setLocation(null);
+ kind.addAttribute(at1);
+ kind.addAttribute(at2);
+ assertEquals(lines[3], kind.toText());
+
+ kind = new Kind(Category.SCHEME_CORE_DEFAULT, Entity.TERM_DEFAULT);
+ kind.addAction(a1);
+ kind.addAction(a2);
+ assertEquals(lines[4], kind.toText());
+
+ kind.addAttribute(at1);
+ kind.addAttribute(at2);
+ kind.setTitle("Entity");
+ kind.setLocation(new URI("/entity/"));
+ assertEquals(lines[5], kind.toText());
+
+ kind.getAttribute(Entity.ID_ATTRIBUTE_NAME).setRequired(true);
+ assertEquals(lines[6], kind.toText());
+
+ kind.getAttribute(Entity.ID_ATTRIBUTE_NAME).setImmutable(true);
+ assertEquals(lines[7], kind.toText());
+
+ kind.getAttribute(Entity.TITLE_ATTRIBUTE_NAME).setImmutable(true);
+ assertEquals(lines[8], kind.toText());
+ }
+
+ @Test
+ public void testToHeaders() throws Exception {
+ String[] lines = TestHelper.readFile(RESOURCE_PATH + "kind_headers.txt").split("\n");
+ Attribute at1 = new Attribute(Entity.ID_ATTRIBUTE_NAME);
+ Attribute at2 = new Attribute(Entity.TITLE_ATTRIBUTE_NAME);
+
+ Action a1 = new Action(new URI("http://schemas.ogf.org/occi/infrastructure/compute/action#"), "start");
+ Action a2 = new Action(new URI("http://schemas.ogf.org/occi/infrastructure/compute/action#"), "stop");
+
+ Headers headers = new Headers();
+
+ Kind kind = new Kind(Category.SCHEME_CORE_DEFAULT, Entity.TERM_DEFAULT);
+ headers.add("Category", lines[0]);
+ assertEquals(headers, kind.toHeaders());
+
+ kind.setTitle("Entity");
+ headers.clear();
+ headers.add("Category", lines[1]);
+ assertEquals(headers, kind.toHeaders());
+
+ kind.setTitle(null);
+ kind.setLocation(new URI("/entity/"));
+ headers.clear();
+ headers.add("Category", lines[2]);
+ assertEquals(headers, kind.toHeaders());
+
+ kind.setLocation(null);
+ kind.addAttribute(at1);
+ kind.addAttribute(at2);
+ headers.clear();
+ headers.add("Category", lines[3]);
+ assertEquals(headers, kind.toHeaders());
+
+ kind = new Kind(Category.SCHEME_CORE_DEFAULT, Entity.TERM_DEFAULT);
+ kind.addAction(a1);
+ kind.addAction(a2);
+ headers.clear();
+ headers.add("Category", lines[4]);
+ assertEquals(headers, kind.toHeaders());
+
+ kind.addAttribute(at1);
+ kind.addAttribute(at2);
+ kind.setTitle("Entity");
+ kind.setLocation(new URI("/entity/"));
+ headers.clear();
+ headers.add("Category", lines[5]);
+ assertEquals(headers, kind.toHeaders());
+
+ kind.getAttribute(Entity.ID_ATTRIBUTE_NAME).setRequired(true);
+ headers.clear();
+ headers.add("Category", lines[6]);
+ assertEquals(headers, kind.toHeaders());
+
+ kind.getAttribute(Entity.ID_ATTRIBUTE_NAME).setImmutable(true);
+ headers.clear();
+ headers.add("Category", lines[7]);
+ assertEquals(headers, kind.toHeaders());
+
+ kind.getAttribute(Entity.TITLE_ATTRIBUTE_NAME).setImmutable(true);
+ headers.clear();
+ headers.add("Category", lines[8]);
+ assertEquals(headers, kind.toHeaders());
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.core;
+
+import com.sun.net.httpserver.Headers;
+import cz.cesnet.cloud.occi.TestHelper;
+import cz.cesnet.cloud.occi.exception.InvalidAttributeValueException;
+import cz.cesnet.cloud.occi.exception.RenderingException;
+import cz.cesnet.cloud.occi.infrastructure.Compute;
+import cz.cesnet.cloud.occi.infrastructure.NetworkInterface;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import org.junit.Test;
+
+public class LinkTest {
+
+ private static final String RESOURCE_PATH = "src/test/resources/rendering/text/";
+
+ @Test
+ public void testToText() throws Exception {
+ String expected = TestHelper.readFile(RESOURCE_PATH + "link_plain.txt");
+ Link link = prepareLink();
+
+ assertEquals(expected, link.toText());
+ }
+
+ @Test
+ public void testToHeaders() throws Exception {
+ Headers headers = new Headers();
+ Link link = prepareLink();
+
+ try (BufferedReader br = new BufferedReader(new FileReader(RESOURCE_PATH + "link_headers_categories.txt"))) {
+ String line = br.readLine();
+ while (line != null) {
+ headers.add("Category", line);
+ line = br.readLine();
+ }
+ }
+ try (BufferedReader br = new BufferedReader(new FileReader(RESOURCE_PATH + "link_headers_attributes.txt"))) {
+ String line = br.readLine();
+ while (line != null) {
+ headers.add("X-OCCI-Attribute", line);
+ line = br.readLine();
+ }
+ }
+
+ assertEquals(headers, link.toHeaders());
+ }
+
+ private Link prepareLink() throws Exception {
+ Kind rel = new Kind(Category.SCHEME_CORE_DEFAULT, Link.TERM_DEFAULT);
+ Kind kind = new Kind(new URI("http://schemas.ogf.org/occi/infrastructure/compute#"), "console", "Link to the VM's console", new URI("/console/"), null);
+ kind.addRelation(rel);
+
+ List<Attribute> attributes = new ArrayList<>();
+ attributes.add(new Attribute("occi.network.address"));
+ attributes.add(new Attribute("occi.network.gateway"));
+ attributes.add(new Attribute("occi.network.allocation"));
+ attributes.add(new Attribute("occi.network.state"));
+ Mixin m1 = new Mixin(new URI("http://schemas.ogf.org/occi/infrastructure/network#"), "ipnetwork", "IP Network Mixin", new URI("/mixins/ipnetwork/"), attributes);
+ Mixin m2 = new Mixin(Category.SCHEME_INFRASTRUCTURE_DEFAULT, "os_tpl", "Operating System Template", new URI("/mixins/os_tpl/"), null);
+ Mixin m3 = new Mixin(Category.SCHEME_INFRASTRUCTURE_DEFAULT, "resource_tpl", "Resource Template", new URI("/mixins/resource_tpl/"), null);
+
+ Link link = new Link("87f3bfc3-42d4-4474-b45c-757e55e093e9", kind, "compute1", null);
+ link.addMixin(m1);
+ link.addMixin(m2);
+ link.addMixin(m3);
+ link.addAttribute(Compute.ARCHITECTURE_ATTRIBUTE_NAME, "x86");
+ link.addAttribute(Compute.HOSTNAME_ATTRIBUTE_NAME, "compute1.example.org");
+ link.addAttribute(Compute.MEMORY_ATTRIBUTE_NAME, "1.7");
+ link.addAttribute(Compute.SPEED_ATTRIBUTE_NAME, "1.0");
+ link.addAttribute(Compute.STATE_ATTRIBUTE_NAME, "active");
+
+ return link;
+ }
+
+ @Test
+ public void testToInlineText() throws Exception {
+ String[] lines = TestHelper.readFile(RESOURCE_PATH + "inline_link_plain.txt").split("\n");
+
+ Kind kind = new Kind(NetworkInterface.SCHEME_DEFAULT, NetworkInterface.TERM_DEFAULT);
+ Link link = new Link("456", kind);
+ link.setRelation("http://schemas.ogf.org/occi/infrastructure#network");
+ link.setTarget("/network/123");
+ assertEquals(lines[0], link.toInlineText());
+
+ link.getKind().setLocation(new URI("/link/networkinterface/"));
+ assertEquals(lines[1], link.toInlineText());
+
+ link.getKind().setLocation(null);
+ link.addAttribute("occi.networkinterface.interface", "eth0");
+ link.addAttribute("occi.networkinterface.mac", "00:11:22:33:44:55");
+ link.addAttribute("occi.networkinterface.state", "active");
+ assertEquals(lines[2], link.toInlineText());
+
+ link.getKind().setLocation(new URI("/link/networkinterface/"));
+ assertEquals(lines[3], link.toInlineText());
+ }
+
+ @Test
+ public void testToInlineHeaders() throws Exception {
+ String[] lines = TestHelper.readFile(RESOURCE_PATH + "inline_link_headers.txt").split("\n");
+ Headers headers = new Headers();
+
+ Kind kind = new Kind(NetworkInterface.SCHEME_DEFAULT, NetworkInterface.TERM_DEFAULT);
+ Link link = new Link("456", kind);
+ link.setRelation("http://schemas.ogf.org/occi/infrastructure#network");
+ link.setTarget("/network/123");
+ headers.add("Link", lines[0]);
+ assertEquals(headers, link.toInlineHeaders());
+
+ link.getKind().setLocation(new URI("/link/networkinterface/"));
+ headers.clear();
+ headers.add("Link", lines[1]);
+ assertEquals(headers, link.toInlineHeaders());
+
+ link.getKind().setLocation(null);
+ link.addAttribute("occi.networkinterface.interface", "eth0");
+ link.addAttribute("occi.networkinterface.mac", "00:11:22:33:44:55");
+ link.addAttribute("occi.networkinterface.state", "active");
+ headers.clear();
+ headers.add("Link", lines[2]);
+ assertEquals(headers, link.toInlineHeaders());
+
+ link.getKind().setLocation(new URI("/link/networkinterface/"));
+ headers.clear();
+ headers.add("Link", lines[3]);
+ assertEquals(headers, link.toInlineHeaders());
+ }
+
+ @Test
+ public void testInvalidToInlineText() throws InvalidAttributeValueException {
+ try {
+ Kind kind = new Kind(NetworkInterface.SCHEME_DEFAULT, NetworkInterface.TERM_DEFAULT);
+ Link link = new Link("456", kind);
+ link.setRelation("http://schemas.ogf.org/occi/infrastructure#network");
+ link.toInlineText();
+ fail();
+ } catch (RenderingException ex) {
+ //cool
+ }
+
+ try {
+ Kind kind = new Kind(NetworkInterface.SCHEME_DEFAULT, NetworkInterface.TERM_DEFAULT);
+ Link link = new Link("456", kind);
+ link.setTarget("/network/123");
+ link.toInlineText();
+ fail();
+ } catch (RenderingException ex) {
+ //cool
+ }
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.core;
+
+import com.sun.net.httpserver.Headers;
+import cz.cesnet.cloud.occi.TestHelper;
+import cz.cesnet.cloud.occi.infrastructure.IPNetwork;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.HashSet;
+import java.util.Set;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class MixinTest {
+
+ private static final String RESOURCE_PATH = "src/test/resources/rendering/text/";
+
+ @Test
+ public void testFullConstructor() throws URISyntaxException {
+ Set<Attribute> attributes = new HashSet<>();
+ attributes.add(new Attribute("aaa"));
+ attributes.add(new Attribute("bbb"));
+ attributes.add(new Attribute("ccc"));
+ Mixin mixin = new Mixin(Category.SCHEME_CORE_DEFAULT, Entity.TERM_DEFAULT, "title", new URI("/location/"), attributes);
+
+ assertEquals(mixin.getAttributes(), attributes);
+ assertEquals(mixin.getLocation(), new URI("/location/"));
+ assertEquals(mixin.getScheme(), Category.SCHEME_CORE_DEFAULT);
+ assertEquals(mixin.getTerm(), Entity.TERM_DEFAULT);
+ assertEquals(mixin.getTitle(), "title");
+ }
+
+ @Test
+ public void testMinimalConstructor() throws URISyntaxException {
+ Mixin mixin = new Mixin(Category.SCHEME_CORE_DEFAULT, Entity.TERM_DEFAULT);
+
+ assertEquals(mixin.getScheme(), Category.SCHEME_CORE_DEFAULT);
+ assertEquals(mixin.getTerm(), Entity.TERM_DEFAULT);
+ }
+
+ @Test
+ public void testInvalidConstructor() throws URISyntaxException {
+ try {
+ Mixin mixin = new Mixin(null, Entity.TERM_DEFAULT);
+ fail();
+ } catch (NullPointerException ex) {
+ //cool
+ }
+
+ try {
+ Mixin mixin = new Mixin(Category.SCHEME_CORE_DEFAULT, null);
+ fail();
+ } catch (NullPointerException ex) {
+ //cool
+ }
+
+ try {
+ Mixin mixin = new Mixin(Category.SCHEME_CORE_DEFAULT, "");
+ fail();
+ } catch (IllegalArgumentException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testToText() throws Exception {
+ String[] lines = TestHelper.readFile(RESOURCE_PATH + "mixin_plain.txt").split("\n");
+ Attribute at1 = new Attribute(IPNetwork.ADDRESS_ATTRIBUTE_NAME);
+ Attribute at2 = new Attribute(IPNetwork.GATEWAY_ATTRIBUTE_NAME);
+ Attribute at3 = new Attribute(IPNetwork.ALLOCATION_ATTRIBUTE_NAME);
+ Attribute at4 = new Attribute(IPNetwork.STATE_ATTRIBUTE_NAME);
+ Action a1 = new Action(new URI("http://schemas.ogf.org/occi/infrastructure/compute/action#"), "start");
+ Action a2 = new Action(new URI("http://schemas.ogf.org/occi/infrastructure/compute/action#"), "stop");
+
+ Mixin mixin = new Mixin(IPNetwork.SCHEME_DEFAULT, IPNetwork.TERM_DEFAULT);
+ assertEquals(mixin.toText(), lines[0]);
+
+ mixin.setTitle("IP Network Mixin");
+ assertEquals(mixin.toText(), lines[1]);
+
+ mixin.setTitle(null);
+ mixin.setLocation(new URI("/mixins/ipnetwork/"));
+ assertEquals(mixin.toText(), lines[2]);
+
+ mixin.setLocation(null);
+ mixin.addAttribute(at1);
+ mixin.addAttribute(at2);
+ mixin.addAttribute(at3);
+ mixin.addAttribute(at4);
+ assertEquals(mixin.toText(), lines[3]);
+
+ mixin = new Mixin(IPNetwork.SCHEME_DEFAULT, IPNetwork.TERM_DEFAULT);
+ mixin.addAction(a1);
+ mixin.addAction(a2);
+ assertEquals(mixin.toText(), lines[4]);
+
+ mixin.addAttribute(at1);
+ mixin.addAttribute(at2);
+ mixin.addAttribute(at3);
+ mixin.addAttribute(at4);
+ mixin.getAttribute(IPNetwork.ADDRESS_ATTRIBUTE_NAME).setRequired(true);
+ mixin.getAttribute(IPNetwork.GATEWAY_ATTRIBUTE_NAME).setImmutable(true);
+ mixin.getAttribute(IPNetwork.ALLOCATION_ATTRIBUTE_NAME).setRequired(true);
+ mixin.getAttribute(IPNetwork.ALLOCATION_ATTRIBUTE_NAME).setImmutable(true);
+ mixin.setTitle("IP Network Mixin");
+ mixin.setLocation(new URI("/mixins/ipnetwork/"));
+ assertEquals(mixin.toText(), lines[5]);
+ }
+
+ @Test
+ public void testToHeaders() throws Exception {
+ String[] lines = TestHelper.readFile(RESOURCE_PATH + "mixin_headers.txt").split("\n");
+ Attribute at1 = new Attribute(IPNetwork.ADDRESS_ATTRIBUTE_NAME);
+ Attribute at2 = new Attribute(IPNetwork.GATEWAY_ATTRIBUTE_NAME);
+ Attribute at3 = new Attribute(IPNetwork.ALLOCATION_ATTRIBUTE_NAME);
+ Attribute at4 = new Attribute(IPNetwork.STATE_ATTRIBUTE_NAME);
+ Action a1 = new Action(new URI("http://schemas.ogf.org/occi/infrastructure/compute/action#"), "start");
+ Action a2 = new Action(new URI("http://schemas.ogf.org/occi/infrastructure/compute/action#"), "stop");
+
+ Headers headers = new Headers();
+
+ Mixin mixin = new Mixin(IPNetwork.SCHEME_DEFAULT, IPNetwork.TERM_DEFAULT);
+ headers.add("Category", lines[0]);
+ assertEquals(headers, mixin.toHeaders());
+
+ mixin.setTitle("IP Network Mixin");
+ headers.clear();
+ headers.add("Category", lines[1]);
+ assertEquals(headers, mixin.toHeaders());
+
+ mixin.setTitle(null);
+ mixin.setLocation(new URI("/mixins/ipnetwork/"));
+ headers.clear();
+ headers.add("Category", lines[2]);
+ assertEquals(headers, mixin.toHeaders());
+
+ mixin.setLocation(null);
+ mixin.addAttribute(at1);
+ mixin.addAttribute(at2);
+ mixin.addAttribute(at3);
+ mixin.addAttribute(at4);
+ headers.clear();
+ headers.add("Category", lines[3]);
+ assertEquals(headers, mixin.toHeaders());
+
+ mixin = new Mixin(IPNetwork.SCHEME_DEFAULT, IPNetwork.TERM_DEFAULT);
+ mixin.addAction(a1);
+ mixin.addAction(a2);
+ headers.clear();
+ headers.add("Category", lines[4]);
+ assertEquals(headers, mixin.toHeaders());
+
+ mixin.addAttribute(at1);
+ mixin.addAttribute(at2);
+ mixin.addAttribute(at3);
+ mixin.addAttribute(at4);
+ mixin.getAttribute(IPNetwork.ADDRESS_ATTRIBUTE_NAME).setRequired(true);
+ mixin.getAttribute(IPNetwork.GATEWAY_ATTRIBUTE_NAME).setImmutable(true);
+ mixin.getAttribute(IPNetwork.ALLOCATION_ATTRIBUTE_NAME).setRequired(true);
+ mixin.getAttribute(IPNetwork.ALLOCATION_ATTRIBUTE_NAME).setImmutable(true);
+ mixin.setTitle("IP Network Mixin");
+ mixin.setLocation(new URI("/mixins/ipnetwork/"));
+ headers.clear();
+ headers.add("Category", lines[5]);
+ assertEquals(headers, mixin.toHeaders());
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.core;
+
+import com.sun.net.httpserver.Headers;
+import cz.cesnet.cloud.occi.DataGenerator;
+import cz.cesnet.cloud.occi.TestHelper;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class ResourceTest {
+
+ private static final String RESOURCE_PATH = "src/test/resources/rendering/text/";
+
+ @Test
+ public void testToText() throws Exception {
+ String expected = TestHelper.readFile(RESOURCE_PATH + "resource_plain.txt");
+ Resource resource = DataGenerator.getResource();
+
+ assertEquals(expected, resource.toText());
+ }
+
+ @Test
+ public void testToHeaders() throws Exception {
+ Headers headers = new Headers();
+ Resource resource = DataGenerator.getResource();
+
+ try (BufferedReader br = new BufferedReader(new FileReader(RESOURCE_PATH + "resource_headers_categories.txt"))) {
+ String line = br.readLine();
+ while (line != null) {
+ headers.add("Category", line);
+ line = br.readLine();
+ }
+ }
+ try (BufferedReader br = new BufferedReader(new FileReader(RESOURCE_PATH + "resource_headers_attributes.txt"))) {
+ String line = br.readLine();
+ while (line != null) {
+ headers.add("X-OCCI-Attribute", line);
+ line = br.readLine();
+ }
+ }
+ try (BufferedReader br = new BufferedReader(new FileReader(RESOURCE_PATH + "resource_headers_links.txt"))) {
+ String line = br.readLine();
+ while (line != null) {
+ headers.add("Link", line);
+ line = br.readLine();
+ }
+ }
+
+ for (String name : headers.keySet()) {
+ System.out.println(name);
+ System.out.println(headers.get(name));
+ }
+ for (String name : resource.toHeaders().keySet()) {
+ System.out.println(name);
+ System.out.println(resource.toHeaders().get(name));
+ }
+
+ assertEquals(headers, resource.toHeaders());
+ }
+}
--- /dev/null
+package cz.cesnet.cloud.occi.parser;
+
+import com.sun.net.httpserver.Headers;
+import cz.cesnet.cloud.occi.Collection;
+import cz.cesnet.cloud.occi.DataGenerator;
+import cz.cesnet.cloud.occi.Model;
+import cz.cesnet.cloud.occi.TestHelper;
+import cz.cesnet.cloud.occi.core.Action;
+import cz.cesnet.cloud.occi.core.ActionInstance;
+import cz.cesnet.cloud.occi.core.Attribute;
+import cz.cesnet.cloud.occi.core.Kind;
+import cz.cesnet.cloud.occi.core.Link;
+import cz.cesnet.cloud.occi.core.Mixin;
+import cz.cesnet.cloud.occi.core.Resource;
+import cz.cesnet.cloud.occi.exception.ParsingException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import org.junit.Test;
+
+public class TextParserTest {
+
+ private static final String RESOURCE_PATH = "src/test/resources/parser/text/";
+
+ private Model populateModelWithKinds(List<Kind> kinds, Model initialModel) {
+ Model model;
+ if (initialModel == null) {
+ model = new Model();
+ } else {
+ model = initialModel;
+ }
+
+ for (Kind k : kinds) {
+ model.addKind(k);
+ }
+
+ return model;
+ }
+
+ private Model populateModelWithMixins(List<Mixin> mixins, Model initialModel) {
+ Model model;
+ if (initialModel == null) {
+ model = new Model();
+ } else {
+ model = initialModel;
+ }
+
+ for (Mixin k : mixins) {
+ model.addMixin(k);
+ }
+
+ return model;
+ }
+
+ private Model populateModelWithActions(List<Action> actions, Model initialModel) {
+ Model model;
+ if (initialModel == null) {
+ model = new Model();
+ } else {
+ model = initialModel;
+ }
+
+ for (Action k : actions) {
+ model.addAction(k);
+ }
+
+ return model;
+ }
+
+ @Test
+ public void testParseModelPlainKindsMinimal() throws Exception {
+ String body = TestHelper.readFile(RESOURCE_PATH + "model_plain_kinds_minimal.txt");
+ Headers headers = null;
+ TextParser instance = new TextParser();
+ Model expResult = populateModelWithKinds(DataGenerator.getMinimalKind(), null);
+ Model result = instance.parseModel(MediaType.TEXT_PLAIN, body, headers);
+ assertEquals(expResult, result);
+ assertKindsEqual(expResult.getKinds(), result.getKinds());
+ }
+
+ @Test
+ public void testParseModelPlainKindsFull() throws Exception {
+ String body = TestHelper.readFile(RESOURCE_PATH + "model_plain_kinds_full.txt");
+ Headers headers = null;
+ TextParser instance = new TextParser();
+ Model expResult = populateModelWithKinds(DataGenerator.getFiveKinds(), null);
+ Model result = instance.parseModel(MediaType.TEXT_PLAIN, body, headers);
+ assertEquals(expResult, result);
+ assertKindsEqual(expResult.getKinds(), result.getKinds());
+ }
+
+ @Test
+ public void testInvalidParseModelPlainKind() {
+ TextParser instance = new TextParser();
+
+ //kind without location
+ try {
+ String body = "Category: entity;scheme=\"http://schemas.ogf.org/occi/core#\";class=\"kind\";title=\"Entity\";attributes=\"occi.core.id occi.core.title\"";
+ instance.parseModel(MediaType.TEXT_PLAIN, body, null);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //kind with empty location
+ try {
+ String body = "Category: entity;scheme=\"http://schemas.ogf.org/occi/core#\";class=\"kind\";title=\"Entity\";location=\"\";attributes=\"occi.core.id occi.core.title\"";
+ instance.parseModel(MediaType.TEXT_PLAIN, body, null);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //kind with illegal scheme
+ try {
+ String body = "Category: entity;scheme=\"/\\/_)#@564...,p,pkl\";class=\"kind\";title=\"Entity\";location=\"/entity/\";attributes=\"occi.core.id occi.core.title\"";
+ instance.parseModel(MediaType.TEXT_PLAIN, body, null);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //kind with illegal location
+ try {
+ String body = "Category: entity;scheme=\"http://schemas.ogf.org/occi/core#\";class=\"kind\";title=\"Entity\";location=\"/\\/_)#@564...,p,pkl\";attributes=\"occi.core.id occi.core.title\"";
+ instance.parseModel(MediaType.TEXT_PLAIN, body, null);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testParseModelPlainMixinsMinimal() throws Exception {
+ String body = TestHelper.readFile(RESOURCE_PATH + "model_plain_mixins_minimal.txt");
+ Headers headers = null;
+ TextParser instance = new TextParser();
+ Model expResult = populateModelWithMixins(DataGenerator.getMinimalMixin(), null);
+ Model result = instance.parseModel(MediaType.TEXT_PLAIN, body, headers);
+ assertEquals(expResult, result);
+ assertMixinsEqual(expResult.getMixins(), result.getMixins());
+ }
+
+ @Test
+ public void testParseModelPlainMixinsFull() throws Exception {
+ String body = TestHelper.readFile(RESOURCE_PATH + "model_plain_mixins_full.txt");
+ Headers headers = null;
+ TextParser instance = new TextParser();
+ Model expResult = populateModelWithMixins(DataGenerator.getFiveMixins(), null);
+ Model result = instance.parseModel(MediaType.TEXT_PLAIN, body, headers);
+ assertEquals(expResult, result);
+ assertMixinsEqual(expResult.getMixins(), result.getMixins());
+ }
+
+ @Test
+ public void testInvalidParseModelPlainMixin() {
+ TextParser instance = new TextParser();
+ //mixin with illegal scheme
+ try {
+ String body = "Category: ipnetwork;scheme=\"/\\/_)#@564...,p,pkl\";class=\"mixin\";title=\"IP Network Mixin\";location=\"/mixins/ipnetwork/\";attributes=\"occi.network.address{required} occi.network.gateway occi.network.allocation occi.network.state\"";
+ instance.parseModel(MediaType.TEXT_PLAIN, body, null);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testParseModelPlainActionsMinimal() throws Exception {
+ String body = TestHelper.readFile(RESOURCE_PATH + "model_plain_actions_minimal.txt");
+ Headers headers = null;
+ TextParser instance = new TextParser();
+ Model expResult = populateModelWithActions(DataGenerator.getMinimalAction(), null);
+ Model result = instance.parseModel(MediaType.TEXT_PLAIN, body, headers);
+ assertEquals(expResult, result);
+ assertActionsEqual(expResult.getActions(), result.getActions());
+ }
+
+ @Test
+ public void testParseModelPlainActionsFull() throws Exception {
+ String body = TestHelper.readFile(RESOURCE_PATH + "model_plain_actions_full.txt");
+ Headers headers = null;
+ TextParser instance = new TextParser();
+ Model expResult = populateModelWithActions(DataGenerator.getFiveActions(), null);
+ Model result = instance.parseModel(MediaType.TEXT_PLAIN, body, headers);
+ assertEquals(expResult, result);
+ assertActionsEqual(expResult.getActions(), result.getActions());
+ }
+
+ @Test
+ public void testInvalidParseModelPlainAction() {
+ TextParser instance = new TextParser();
+
+ //action with illegal scheme
+ try {
+ String body = "Category: restart;scheme=\"/\\/_)#@564...,p,pkl\";class=\"action\";title=\"Restart Compute instance\";attributes=\"method\"";
+ instance.parseModel(MediaType.TEXT_PLAIN, body, null);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testParseModelPlainAll() throws Exception {
+ String body = TestHelper.readFile(RESOURCE_PATH + "model_plain_all.txt");
+ Headers headers = null;
+ TextParser instance = new TextParser();
+ Model expResult = populateModelWithKinds(DataGenerator.getFiveKinds(), null);
+ expResult = populateModelWithMixins(DataGenerator.getFiveMixins(), expResult);
+ expResult = populateModelWithActions(DataGenerator.getFiveActions(), expResult);
+ Model result = instance.parseModel(MediaType.TEXT_PLAIN, body, headers);
+ assertEquals(expResult, result);
+ assertKindsEqual(expResult.getKinds(), result.getKinds());
+ assertMixinsEqual(expResult.getMixins(), result.getMixins());
+ assertActionsEqual(expResult.getActions(), result.getActions());
+ }
+
+ @Test
+ public void testInvalidParseModelPlain() {
+ TextParser instance = new TextParser();
+
+ try {
+ String body = "nonmatching_line";
+ instance.parseModel(MediaType.TEXT_PLAIN, body, null);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //without term
+ try {
+ String body = "Category: ;scheme=\"http://schemas.ogf.org/occi/core#\";class=\"kind\";title=\"Entity\";location=\"/entity/\";attributes=\"occi.core.id occi.core.title\"";
+ instance.parseModel(MediaType.TEXT_PLAIN, body, null);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //without scheme
+ try {
+ String body = "Category: entity;class=\"kind\";title=\"Entity\";location=\"/entity/\";attributes=\"occi.core.id occi.core.title\"";
+ instance.parseModel(MediaType.TEXT_PLAIN, body, null);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //with empty scheme
+ try {
+ String body = "Category: entity;scheme=\"\";class=\"kind\";title=\"Entity\";location=\"/entity/\";attributes=\"occi.core.id occi.core.title\"";
+ instance.parseModel(MediaType.TEXT_PLAIN, body, null);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //without class
+ try {
+ String body = "Category: entity;scheme=\"http://schemas.ogf.org/occi/core#\";title=\"Entity\";location=\"/entity/\";attributes=\"occi.core.id occi.core.title\"";
+ instance.parseModel(MediaType.TEXT_PLAIN, body, null);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //with empty class
+ try {
+ String body = "Category: entity;scheme=\"http://schemas.ogf.org/occi/core#\";class=\"\";title=\"Entity\";location=\"/entity/\";attributes=\"occi.core.id occi.core.title\"";
+ instance.parseModel(MediaType.TEXT_PLAIN, body, null);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //with unknown class
+ try {
+ String body = "Category: entity;scheme=\"http://schemas.ogf.org/occi/core#\";class=\"nonexisting_class\";title=\"Entity\";location=\"/entity/\";attributes=\"occi.core.id occi.core.title\"";
+ instance.parseModel(MediaType.TEXT_PLAIN, body, null);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ }
+
+ private Headers createDefaultHeaders() {
+ Headers headers = new Headers();
+ headers.add("Status Code", "200 OK");
+ headers.add("Cache-Control", "no-cache");
+ headers.add("Connection", "keep-alive");
+ headers.add("Content-Length", "0");
+ headers.add("Content-Type", "text/occi; charset=utf-8");
+ headers.add("Date", "Thu, 06 Nov 2014 19:11:38 GMT");
+ headers.add("Server", "WEBrick/1.3.1 (Ruby/2.0.0/2014-09-19)");
+ headers.add("Via", "1.1 vegur");
+ headers.add("X-Frame-Options", "SAMEORIGIN");
+ headers.add("X-Request-Id", "3191d404-a8f5-4bda-97d6-1069e71fc418");
+ headers.add("X-Runtime", "0.025947");
+ headers.add("X-XSS-Protection", "1; mode=block");
+ headers.add("x-content-type-options", "nosniff");
+
+ return headers;
+ }
+
+ @Test
+ public void testParseModelOcciKindsMinimal() throws Exception {
+ String categoryHeader = TestHelper.readFile(RESOURCE_PATH + "model_occi_kinds_minimal.txt");
+ String body = null;
+ Headers headers = createDefaultHeaders();
+ headers.add("Category", categoryHeader);
+ TextParser instance = new TextParser();
+ Model expResult = populateModelWithKinds(DataGenerator.getMinimalKind(), null);
+ Model result = instance.parseModel(MediaType.TEXT_OCCI, body, headers);
+ assertEquals(expResult, result);
+ assertKindsEqual(expResult.getKinds(), result.getKinds());
+ }
+
+ @Test
+ public void testParseModelOcciKindsFull() throws Exception {
+ String categoryHeader = TestHelper.readFile(RESOURCE_PATH + "model_occi_kinds_full.txt");
+ String body = null;
+ Headers headers = createDefaultHeaders();
+ headers.add("Category", categoryHeader);
+ TextParser instance = new TextParser();
+ Model expResult = populateModelWithKinds(DataGenerator.getFiveKinds(), null);
+ Model result = instance.parseModel(MediaType.TEXT_OCCI, body, headers);
+ assertEquals(expResult, result);
+ assertKindsEqual(expResult.getKinds(), result.getKinds());
+ }
+
+ @Test
+ public void testInvalidParseModelOcciKind() {
+ TextParser instance = new TextParser();
+ Headers headers = createDefaultHeaders();
+
+ //kind without location
+ try {
+ headers.add("Category", "Category: entity;scheme=\"http://schemas.ogf.org/occi/core#\";class=\"kind\";title=\"Entity\";attributes=\"occi.core.id occi.core.title\"");
+ instance.parseModel(MediaType.TEXT_OCCI, null, headers);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //kind with empty location
+ try {
+ headers.add("Category", "Category: entity;scheme=\"http://schemas.ogf.org/occi/core#\";class=\"kind\";title=\"Entity\";location=\"\";attributes=\"occi.core.id occi.core.title\"");
+ instance.parseModel(MediaType.TEXT_OCCI, null, headers);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //kind with illegal scheme
+ try {
+ headers.add("Category", "Category: entity;scheme=\"/\\/_)#@564...,p,pkl\";class=\"kind\";title=\"Entity\";location=\"/entity/\";attributes=\"occi.core.id occi.core.title\"");
+ instance.parseModel(MediaType.TEXT_OCCI, null, headers);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //kind with illegal location
+ try {
+ headers.add("Category", "Category: entity;scheme=\"http://schemas.ogf.org/occi/core#\";class=\"kind\";title=\"Entity\";location=\"/\\/_)#@564...,p,pkl\";attributes=\"occi.core.id occi.core.title\"");
+ instance.parseModel(MediaType.TEXT_OCCI, null, headers);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testParseModelOcciMixinsMinimal() throws Exception {
+ String categoryHeader = TestHelper.readFile(RESOURCE_PATH + "model_occi_mixins_minimal.txt");
+ String body = null;
+ Headers headers = createDefaultHeaders();
+ headers.add("Category", categoryHeader);
+ TextParser instance = new TextParser();
+ Model expResult = populateModelWithMixins(DataGenerator.getMinimalMixin(), null);
+ Model result = instance.parseModel(MediaType.TEXT_OCCI, body, headers);
+ assertEquals(expResult, result);
+ assertMixinsEqual(expResult.getMixins(), result.getMixins());
+ }
+
+ @Test
+ public void testParseModelOcciMixinsFull() throws Exception {
+ String categoryHeader = TestHelper.readFile(RESOURCE_PATH + "model_occi_mixins_full.txt");
+ String body = null;
+ Headers headers = createDefaultHeaders();
+ headers.add("Category", categoryHeader);
+ TextParser instance = new TextParser();
+ Model expResult = populateModelWithMixins(DataGenerator.getFiveMixins(), null);
+ Model result = instance.parseModel(MediaType.TEXT_OCCI, body, headers);
+ assertEquals(expResult, result);
+ assertMixinsEqual(expResult.getMixins(), result.getMixins());
+ }
+
+ @Test
+ public void testInvalidParseModelOcciMixin() {
+ TextParser instance = new TextParser();
+ Headers headers = createDefaultHeaders();
+
+ //mixin with illegal scheme
+ try {
+ headers.add("Category", "Category: ipnetwork;scheme=\"/\\/_)#@564...,p,pkl\";class=\"mixin\";title=\"IP Network Mixin\";location=\"/mixins/ipnetwork/\";attributes=\"occi.network.address{required} occi.network.gateway occi.network.allocation occi.network.state\"");
+ instance.parseModel(MediaType.TEXT_OCCI, null, headers);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //mixin with illegal location
+ try {
+ headers.add("Category", "Category: ipnetwork;scheme=\"http://schemas.ogf.org/occi/infrastructure/network#\";class=\"mixin\";title=\"IP Network Mixin\";location=\"/\\/_)#@564...,p,pkl\";attributes=\"occi.network.address{required} occi.network.gateway occi.network.allocation occi.network.state\"");
+ instance.parseModel(MediaType.TEXT_OCCI, null, headers);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testParseModelOcciActionsMinimal() throws Exception {
+ String categoryHeader = TestHelper.readFile(RESOURCE_PATH + "model_occi_actions_minimal.txt");
+ String body = null;
+ Headers headers = createDefaultHeaders();
+ headers.add("Category", categoryHeader);
+ TextParser instance = new TextParser();
+ Model expResult = populateModelWithActions(DataGenerator.getMinimalAction(), null);
+ Model result = instance.parseModel(MediaType.TEXT_OCCI, body, headers);
+ assertEquals(expResult, result);
+ assertActionsEqual(expResult.getActions(), result.getActions());
+ }
+
+ @Test
+ public void testParseModelOcciActionsFull() throws Exception {
+ String categoryHeader = TestHelper.readFile(RESOURCE_PATH + "model_occi_actions_full.txt");
+ String body = null;
+ Headers headers = createDefaultHeaders();
+ headers.add("Category", categoryHeader);
+ TextParser instance = new TextParser();
+ Model expResult = populateModelWithActions(DataGenerator.getFiveActions(), null);
+ Model result = instance.parseModel(MediaType.TEXT_OCCI, body, headers);
+ assertEquals(expResult, result);
+ assertActionsEqual(expResult.getActions(), result.getActions());
+ }
+
+ @Test
+ public void testInvalidParseModelOcciAction() {
+ TextParser instance = new TextParser();
+ Headers headers = createDefaultHeaders();
+
+ //action with illegal scheme
+ try {
+ headers.add("Category", "Category: restart;scheme=\"/\\/_)#@564...,p,pkl\";class=\"action\";title=\"Restart Compute instance\";attributes=\"method\"");
+ instance.parseModel(MediaType.TEXT_OCCI, null, headers);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testParseModelOcciAll() throws Exception {
+ String categoryHeader = TestHelper.readFile(RESOURCE_PATH + "model_occi_all.txt");
+ String body = null;
+ Headers headers = createDefaultHeaders();
+ headers.add("Category", categoryHeader);
+ TextParser instance = new TextParser();
+ Model expResult = populateModelWithKinds(DataGenerator.getFiveKinds(), null);
+ expResult = populateModelWithMixins(DataGenerator.getFiveMixins(), expResult);
+ expResult = populateModelWithActions(DataGenerator.getFiveActions(), expResult);
+ Model result = instance.parseModel(MediaType.TEXT_OCCI, body, headers);
+ assertEquals(expResult, result);
+ assertKindsEqual(expResult.getKinds(), result.getKinds());
+ assertMixinsEqual(expResult.getMixins(), result.getMixins());
+ assertActionsEqual(expResult.getActions(), result.getActions());
+ }
+
+ @Test
+ public void testInvalidParseModelOcci() {
+ TextParser instance = new TextParser();
+ Headers headers = createDefaultHeaders();
+
+ //missing category header
+ try {
+ instance.parseModel(MediaType.TEXT_OCCI, null, headers);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ try {
+ headers.add("Category", "nonmatching_line");
+ instance.parseModel(MediaType.TEXT_OCCI, null, headers);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //without term
+ try {
+ headers.add("Category", "Category: ;scheme=\"http://schemas.ogf.org/occi/core#\";class=\"kind\";title=\"Entity\";location=\"/entity/\";attributes=\"occi.core.id occi.core.title\"");
+ instance.parseModel(MediaType.TEXT_OCCI, null, headers);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //without scheme
+ try {
+ headers.add("Category", "Category: entity;class=\"kind\";title=\"Entity\";location=\"/entity/\";attributes=\"occi.core.id occi.core.title\"");
+ instance.parseModel(MediaType.TEXT_OCCI, null, headers);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //with empty scheme
+ try {
+ headers.add("Category", "Category: entity;scheme=\"\";class=\"kind\";title=\"Entity\";location=\"/entity/\";attributes=\"occi.core.id occi.core.title\"");
+ instance.parseModel(MediaType.TEXT_OCCI, null, headers);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //without class
+ try {
+ headers.add("Category", "Category: entity;scheme=\"http://schemas.ogf.org/occi/core#\";title=\"Entity\";location=\"/entity/\";attributes=\"occi.core.id occi.core.title\"");
+ instance.parseModel(MediaType.TEXT_OCCI, null, headers);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //with empty class
+ try {
+ headers.add("Category", "Category: entity;scheme=\"http://schemas.ogf.org/occi/core#\";class=\"\";title=\"Entity\";location=\"/entity/\";attributes=\"occi.core.id occi.core.title\"");
+ instance.parseModel(MediaType.TEXT_OCCI, null, headers);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //with unknown class
+ try {
+ headers.add("Category", "Category: entity;scheme=\"http://schemas.ogf.org/occi/core#\";class=\"nonexisting_class\";title=\"Entity\";location=\"/entity/\";attributes=\"occi.core.id occi.core.title\"");
+ instance.parseModel(MediaType.TEXT_OCCI, null, headers);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ }
+
+ @Test
+ public void testParseLocationsPlain() throws Exception {
+ String body = TestHelper.readFile(RESOURCE_PATH + "locations_plain.txt");
+ Headers headers = null;
+ TextParser instance = new TextParser();
+ List<URI> expResult = DataGenerator.getLocations();
+ List<URI> result = instance.parseLocations(MediaType.TEXT_PLAIN, body, headers);
+ assertEquals(expResult, result);
+ }
+
+ @Test
+ public void testInvalidParseLocationsPlain() {
+ TextParser instance = new TextParser();
+ String body = "X-OCCI-Location: http://rocci-server-1-1-x.herokuapp.com:80/compute/87f3bfc3-42d4-4474-b45c-757e55e093e9\n"
+ + "!@#$%^&||}?:{}|\n"
+ + "X-OCCI-Location: http://rocci-server-1-1-x.herokuapp.com:80/compute/17679ebd-975f-4ea0-b42b-47405178c360";
+
+ try {
+ instance.parseLocations(MediaType.TEXT_PLAIN, body, null);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testParseLocationsUriList() throws Exception {
+ String body = TestHelper.readFile(RESOURCE_PATH + "locations_uri-list.txt");
+ Headers headers = null;
+ TextParser instance = new TextParser();
+ List<URI> expResult = DataGenerator.getLocations();
+ List<URI> result = instance.parseLocations(MediaType.TEXT_URI_LIST, body, headers);
+ assertEquals(expResult, result);
+ }
+
+ @Test
+ public void testInvalidParseLocationsUriList() {
+ TextParser instance = new TextParser();
+ String body = "http://rocci-server-1-1-x.herokuapp.com:80/compute/87f3bfc3-42d4-4474-b45c-757e55e093e9\n"
+ + "!@#$%^&||}?:{}|\n"
+ + "http://rocci-server-1-1-x.herokuapp.com:80/compute/17679ebd-975f-4ea0-b42b-47405178c360";
+
+ try {
+ instance.parseLocations(MediaType.TEXT_URI_LIST, body, null);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testParseLocationsOcci() throws Exception {
+ String body = null;
+ Headers headers = createDefaultHeaders();
+ headers.add("Location", "http://rocci-server-1-1-x.herokuapp.com:80/compute/87f3bfc3-42d4-4474-b45c-757e55e093e9,http://rocci-server-1-1-x.herokuapp.com:80/compute/17679ebd-975f-4ea0-b42b-47405178c360,http://rocci-server-1-1-x.herokuapp.com:80/compute/509afbd3-abff-427c-9b25-7913d17e5102");
+ TextParser instance = new TextParser();
+ List<URI> expResult = DataGenerator.getLocations();
+ List<URI> result = instance.parseLocations(MediaType.TEXT_OCCI, body, headers);
+ assertEquals(expResult, result);
+ }
+
+ @Test
+ public void testInvalidParseLocationsOcci() {
+ TextParser instance = new TextParser();
+ Headers headers = createDefaultHeaders();
+
+ try {
+ instance.parseLocations(MediaType.TEXT_OCCI, null, headers);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ try {
+ headers.add("Location", "http://rocci-server-1-1-x.herokuapp.com:80/compute/87f3bfc3-42d4-4474-b45c-757e55e093e9,!@#$%^&||}?:{}|,http://rocci-server-1-1-x.herokuapp.com:80/compute/509afbd3-abff-427c-9b25-7913d17e5102");
+ instance.parseLocations(MediaType.TEXT_OCCI, null, headers);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testParseCollectionPlainResource() throws Exception {
+ String body = TestHelper.readFile(RESOURCE_PATH + "collection_plain_resource.txt");
+ Headers headers = null;
+ TextParser instance = new TextParser();
+
+ Collection expResult = new Collection();
+ expResult.addResource(DataGenerator.getResource());
+ Collection result = instance.parseCollection(MediaType.TEXT_PLAIN, body, headers, CollectionType.RESOURCE);
+ assertEquals(expResult, result);
+ assertResourcesEqual(expResult.getResources(), result.getResources());
+ }
+
+ @Test
+ public void testInvalidParseCollectionPlainRersource() {
+ TextParser instance = new TextParser();
+ String body;
+
+ try {
+ body = "no kind specification on the first line";
+ instance.parseCollection(MediaType.TEXT_PLAIN, body, null, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //unknown class
+ try {
+ body = "Category: compute;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"unknown_class\";location=\"/compute/\";title=\"compute resource\"";
+ instance.parseCollection(MediaType.TEXT_PLAIN, body, null, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //invalid kind scheme
+ try {
+ body = "Category: compute;scheme=\"!@#$%^&||}?:{}|\";class=\"kind\";location=\"/compute/\";title=\"compute resource\"";
+ instance.parseCollection(MediaType.TEXT_PLAIN, body, null, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //invalid kind location
+ try {
+ body = "Category: compute;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";location=\"!@#$%^&||}?:{}|\";title=\"compute resource\"";
+ instance.parseCollection(MediaType.TEXT_PLAIN, body, null, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //unknown class
+ try {
+ body = "Category: compute;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";location=\"/compute/\";title=\"compute resource\"\n"
+ + "Category: os_tpl;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"unknown_class\";title=\"Operating System Template\";location=\"/mixins/os_tpl/\"";
+ instance.parseCollection(MediaType.TEXT_PLAIN, body, null, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //invalid mixin scheme
+ try {
+ body = "Category: compute;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";location=\"/compute/\";title=\"compute resource\"\n"
+ + "Category: os_tpl;scheme=\"!@#$%^&||}?:{}|\";class=\"mixin\";title=\"Operating System Template\";location=\"/mixins/os_tpl/\"";
+ instance.parseCollection(MediaType.TEXT_PLAIN, body, null, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //invalid mixin location
+ try {
+ body = "Category: compute;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";location=\"/compute/\";title=\"compute resource\"\n"
+ + "Category: os_tpl;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"mixin\";title=\"Operating System Template\";location=\"!@#$%^&||}?:{}|\"";
+ instance.parseCollection(MediaType.TEXT_PLAIN, body, null, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //missing action link rel
+ try {
+ body = "Category: compute;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";location=\"/compute/\";title=\"compute resource\"\n"
+ + "Link: </compute/123?action=start>";
+ instance.parseCollection(MediaType.TEXT_PLAIN, body, null, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //invalid action link relation
+ try {
+ body = "Category: compute;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";location=\"/compute/\";title=\"compute resource\"\n"
+ + "Link: </compute/123?action=start>;rel=\"!@$%^&||}?:{}|\"";
+ instance.parseCollection(MediaType.TEXT_PLAIN, body, null, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //invalid link category
+ try {
+ body = "Category: compute;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";location=\"/compute/\";title=\"compute resource\"\n"
+ + "Link: </network/123>;rel=\"http://schemas.ogf.org/occi/infrastructure#network\";self=\"/link/networkinterface/456\";category=\"!@$%^&||}?:{}|\";occi.networkinterface.interface=\"eth0\";occi.networkinterface.mac=\"00:11:22:33:44:55\";occi.networkinterface.state=\"active\";";
+ instance.parseCollection(MediaType.TEXT_PLAIN, body, null, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //invalid link location
+ try {
+ body = "Category: compute;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";location=\"/compute/\";title=\"compute resource\"\n"
+ + "Link: </network/123>;rel=\"http://schemas.ogf.org/occi/infrastructure#network\";self=\"!@$%^&||}?:{}|\";category=\"http://schemas.ogf.org/occi/infrastructure#networkinterface\";occi.networkinterface.interface=\"eth0\";occi.networkinterface.mac=\"00:11:22:33:44:55\";occi.networkinterface.state=\"active\";";
+ instance.parseCollection(MediaType.TEXT_PLAIN, body, null, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //missing id attribute
+ try {
+ body = "Category: compute;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";location=\"/compute/\";title=\"compute resource\"\n"
+ + "X-OCCI-Attribute: occi.core.title=\"compute1\"";
+ instance.parseCollection(MediaType.TEXT_PLAIN, body, null, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testParseCollectionPlainLink() throws Exception {
+ String body = TestHelper.readFile(RESOURCE_PATH + "collection_plain_link.txt");
+ Headers headers = null;
+ TextParser instance = new TextParser();
+
+ Collection expResult = new Collection();
+ expResult.addLink(DataGenerator.getLink());
+ Collection result = instance.parseCollection(MediaType.TEXT_PLAIN, body, headers, CollectionType.LINK);
+ assertEquals(expResult, result);
+ assertLinksEqual(expResult.getLinks(), result.getLinks());
+ }
+
+ @Test
+ public void testInvalidParseCollectionPlainLink() {
+ TextParser instance = new TextParser();
+ String body;
+
+ try {
+ body = "no kind specification on the first line";
+ instance.parseCollection(MediaType.TEXT_PLAIN, body, null, CollectionType.LINK);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //unknown class
+ try {
+ body = "Category: networkinterface;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"unknown_class\";";
+ instance.parseCollection(MediaType.TEXT_PLAIN, body, null, CollectionType.LINK);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //invalid kind scheme
+ try {
+ body = "Category: networkinterface;scheme=\"!@$%^&||}?:{}|\";class=\"kind\";";
+ instance.parseCollection(MediaType.TEXT_PLAIN, body, null, CollectionType.LINK);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //unknown class
+ try {
+ body = "Category: networkinterface;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";\n"
+ + "Category: os_tpl;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"unknown_class\";title=\"Operating System Template\";location=\"/mixins/os_tpl/\"";
+ instance.parseCollection(MediaType.TEXT_PLAIN, body, null, CollectionType.LINK);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //invalid mixin scheme
+ try {
+ body = "Category: networkinterface;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";\n"
+ + "Category: os_tpl;scheme=\"!@#$%^&||}?:{}|\";class=\"mixin\";title=\"Operating System Template\";location=\"/mixins/os_tpl/\"";
+ instance.parseCollection(MediaType.TEXT_PLAIN, body, null, CollectionType.LINK);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //invalid mixin location
+ try {
+ body = "Category: networkinterface;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";\n"
+ + "Category: os_tpl;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"mixin\";title=\"Operating System Template\";location=\"!@#$%^&||}?:{}|\"";
+ instance.parseCollection(MediaType.TEXT_PLAIN, body, null, CollectionType.LINK);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //missing id attribute
+ try {
+ body = "Category: compute;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";location=\"/compute/\";title=\"compute resource\"\n"
+ + "X-OCCI-Attribute: occi.networkinterface.interface=\"eth0\";";
+ instance.parseCollection(MediaType.TEXT_PLAIN, body, null, CollectionType.LINK);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testParseCollectionPlainAction() throws Exception {
+ String body = TestHelper.readFile(RESOURCE_PATH + "collection_plain_action.txt");
+ Headers headers = null;
+ TextParser instance = new TextParser();
+
+ Collection expResult = new Collection();
+ expResult.addAction(DataGenerator.getAction());
+ Collection result = instance.parseCollection(MediaType.TEXT_PLAIN, body, headers, CollectionType.ACTION);
+ assertEquals(expResult, result);
+ assertActionInstancesEqual(expResult.getActions(), result.getActions());
+ }
+
+ @Test
+ public void testInvalidParseCollectionPlainAction() {
+ TextParser instance = new TextParser();
+ String body;
+
+ try {
+ body = "no action specification on the first line";
+ instance.parseCollection(MediaType.TEXT_PLAIN, body, null, CollectionType.ACTION);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //unknown class
+ try {
+ body = "Category: backup;scheme=\"http://schemas.ogf.org/occi/infrastructure/storage/action#\";class=\"unknown_class\";title=\"Backup Storage\"";
+ instance.parseCollection(MediaType.TEXT_PLAIN, body, null, CollectionType.ACTION);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //invalid action scheme
+ try {
+ body = "Category: backup;scheme=\"!@#$%^&||}?:{}|\";class=\"action\";title=\"Backup Storage\"";
+ instance.parseCollection(MediaType.TEXT_PLAIN, body, null, CollectionType.ACTION);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testParseCollectionOcciResource() throws Exception {
+ String categoryHeader = TestHelper.readFile(RESOURCE_PATH + "collection_occi_resource_category.txt");
+ String attributeHeader = TestHelper.readFile(RESOURCE_PATH + "collection_occi_resource_attribute.txt");
+ String linkHeader = TestHelper.readFile(RESOURCE_PATH + "collection_occi_resource_link.txt");
+ String body = null;
+ Headers headers = createDefaultHeaders();
+ headers.add("Category", categoryHeader);
+ headers.add("X-Occi-Attribute", attributeHeader);
+ headers.add("Link", linkHeader);
+ TextParser instance = new TextParser();
+ Collection expResult = new Collection();
+ expResult.addResource(DataGenerator.getResource());
+ Collection result = instance.parseCollection(MediaType.TEXT_OCCI, body, headers, CollectionType.RESOURCE);
+ assertEquals(expResult, result);
+ assertResourcesEqual(expResult.getResources(), result.getResources());
+ }
+
+ @Test
+ public void testInvalidParseCollectionOcciResource() {
+ TextParser instance = new TextParser();
+ Headers headers = new Headers();
+
+ try {
+ headers.add("Category", "no kind specification on the first line");
+ instance.parseCollection(MediaType.TEXT_OCCI, null, headers, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //unknown class
+ try {
+ headers.add("Category", "compute;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"unknown_class\";location=\"/compute/\";title=\"compute resource\"");
+ instance.parseCollection(MediaType.TEXT_OCCI, null, headers, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //invalid kind scheme
+ try {
+ headers.add("Category", "compute;scheme=\"!@#$%^&||}?:{}|\";class=\"kind\";location=\"/compute/\";title=\"compute resource\"");
+ instance.parseCollection(MediaType.TEXT_OCCI, null, headers, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //invalid kind location
+ try {
+ headers.add("Category", "compute;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";location=\"!@#$%^&||}?:{}|\";title=\"compute resource\"");
+ instance.parseCollection(MediaType.TEXT_OCCI, null, headers, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //unknown class
+ try {
+ headers.add("Category", "compute;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";location=\"/compute/\";title=\"compute resource\"\n"
+ + "os_tpl;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"unknown_class\";title=\"Operating System Template\";location=\"/mixins/os_tpl/\"");
+ instance.parseCollection(MediaType.TEXT_OCCI, null, headers, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //invalid mixin scheme
+ try {
+ headers.add("Category", "compute;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";location=\"/compute/\";title=\"compute resource\"\n"
+ + "os_tpl;scheme=\"!@#$%^&||}?:{}|\";class=\"mixin\";title=\"Operating System Template\";location=\"/mixins/os_tpl/\"");
+ instance.parseCollection(MediaType.TEXT_OCCI, null, headers, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //invalid mixin location
+ try {
+ headers.add("Category", "compute;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";location=\"/compute/\";title=\"compute resource\""
+ + "os_tpl;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"mixin\";title=\"Operating System Template\";location=\"!@#$%^&||}?:{}|\"");
+ instance.parseCollection(MediaType.TEXT_OCCI, null, headers, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //missing action link rel
+ try {
+ headers.add("Category", "compute;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";location=\"/compute/\";title=\"compute resource\"");
+ headers.add("Link", "</compute/123?action=start>");
+ instance.parseCollection(MediaType.TEXT_OCCI, null, headers, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //invalid action link relation
+ try {
+ headers.add("Category", "compute;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";location=\"/compute/\";title=\"compute resource\"");
+ headers.add("Link", "</compute/123?action=start>;rel=\"!@$%^&||}?:{}|\"");
+ instance.parseCollection(MediaType.TEXT_OCCI, null, headers, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //invalid link category
+ try {
+ headers.add("Category", "compute;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";location=\"/compute/\";title=\"compute resource\"");
+ headers.add("Link", "</network/123>;rel=\"http://schemas.ogf.org/occi/infrastructure#network\";self=\"/link/networkinterface/456\";category=\"!@$%^&||}?:{}|\";occi.networkinterface.interface=\"eth0\";occi.networkinterface.mac=\"00:11:22:33:44:55\";occi.networkinterface.state=\"active\";");
+ instance.parseCollection(MediaType.TEXT_OCCI, null, headers, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //invalid link location
+ try {
+ headers.add("Category", "compute;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";location=\"/compute/\";title=\"compute resource\"");
+ headers.add("Link", "</network/123>;rel=\"http://schemas.ogf.org/occi/infrastructure#network\";self=\"!@$%^&||}?:{}|\";category=\"http://schemas.ogf.org/occi/infrastructure#networkinterface\";occi.networkinterface.interface=\"eth0\";occi.networkinterface.mac=\"00:11:22:33:44:55\";occi.networkinterface.state=\"active\";");
+ instance.parseCollection(MediaType.TEXT_OCCI, null, headers, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //missing id attribute
+ try {
+ headers.add("Category", "compute;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";location=\"/compute/\";title=\"compute resource\"");
+ headers.add("X-Occi-Attribute", "occi.core.title=\"compute1\"");
+ instance.parseCollection(MediaType.TEXT_OCCI, null, headers, CollectionType.RESOURCE);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testParseCollectionOcciLink() throws Exception {
+ String categoryHeader = TestHelper.readFile(RESOURCE_PATH + "collection_occi_link_category.txt");
+ String attributeHeader = TestHelper.readFile(RESOURCE_PATH + "collection_occi_link_attribute.txt");
+ String body = null;
+ Headers headers = createDefaultHeaders();
+ headers.add("Category", categoryHeader);
+ headers.add("X-Occi-Attribute", attributeHeader);
+ TextParser instance = new TextParser();
+ Collection expResult = new Collection();
+ expResult.addLink(DataGenerator.getLink());
+ Collection result = instance.parseCollection(MediaType.TEXT_OCCI, body, headers, CollectionType.LINK);
+ assertEquals(expResult, result);
+ assertLinksEqual(expResult.getLinks(), result.getLinks());
+ }
+
+ @Test
+ public void testInvalidParseCollectionOcciLink() {
+ TextParser instance = new TextParser();
+ Headers headers = new Headers();
+
+ try {
+ headers.add("Category", "no kind specification on the first line");
+ instance.parseCollection(MediaType.TEXT_OCCI, null, headers, CollectionType.LINK);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //unknown class
+ try {
+ headers.add("Category", "networkinterface;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"unknown_class\";");
+ instance.parseCollection(MediaType.TEXT_OCCI, null, headers, CollectionType.LINK);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //invalid kind scheme
+ try {
+ headers.add("Category", "networkinterface;scheme=\"!@$%^&||}?:{}|\";class=\"kind\";");
+ instance.parseCollection(MediaType.TEXT_OCCI, null, headers, CollectionType.LINK);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //unknown class
+ try {
+ headers.add("Category", "networkinterface;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";\n"
+ + "os_tpl;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"unknown_class\";title=\"Operating System Template\";location=\"/mixins/os_tpl/\"");
+ instance.parseCollection(MediaType.TEXT_OCCI, null, headers, CollectionType.LINK);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //invalid mixin scheme
+ try {
+ headers.add("Category", "networkinterface;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";\n"
+ + "os_tpl;scheme=\"!@#$%^&||}?:{}|\";class=\"mixin\";title=\"Operating System Template\";location=\"/mixins/os_tpl/\"");
+ instance.parseCollection(MediaType.TEXT_OCCI, null, headers, CollectionType.LINK);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //invalid mixin location
+ try {
+ headers.add("Category", "networkinterface;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";\n"
+ + "os_tpl;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"mixin\";title=\"Operating System Template\";location=\"!@#$%^&||}?:{}|\"");
+ instance.parseCollection(MediaType.TEXT_OCCI, null, headers, CollectionType.LINK);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //missing id attribute
+ try {
+ headers.add("Category", "compute;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";location=\"/compute/\";title=\"compute resource\"");
+ headers.add("X-Occi-Attribute", "occi.networkinterface.interface=\"eth0\";");
+ instance.parseCollection(MediaType.TEXT_OCCI, null, headers, CollectionType.LINK);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+ }
+
+ @Test
+ public void testParseCollectionOcciAction() throws Exception {
+ String categoryHeader = TestHelper.readFile(RESOURCE_PATH + "collection_occi_action_category.txt");
+ String attributeHeader = TestHelper.readFile(RESOURCE_PATH + "collection_occi_action_attribute.txt");
+ String body = null;
+ Headers headers = createDefaultHeaders();
+ headers.add("Category", categoryHeader);
+ headers.add("X-Occi-Attribute", attributeHeader);
+ TextParser instance = new TextParser();
+ Collection expResult = new Collection();
+ expResult.addAction(DataGenerator.getAction());
+ Collection result = instance.parseCollection(MediaType.TEXT_OCCI, body, headers, CollectionType.ACTION);
+ assertEquals(expResult, result);
+ assertActionInstancesEqual(expResult.getActions(), result.getActions());
+ }
+
+ @Test
+ public void testInvalidParseCollectionOcciAction() {
+ TextParser instance = new TextParser();
+ Headers headers = new Headers();
+
+ try {
+ headers.add("Category", "no action specification on the first line");
+ instance.parseCollection(MediaType.TEXT_OCCI, null, headers, CollectionType.ACTION);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //unknown class
+ try {
+ headers.add("Category", "backup;scheme=\"http://schemas.ogf.org/occi/infrastructure/storage/action#\";class=\"unknown_class\";title=\"Backup Storage\"");
+ instance.parseCollection(MediaType.TEXT_OCCI, null, headers, CollectionType.ACTION);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+
+ //invalid action scheme
+ try {
+ headers.add("Category", "backup;scheme=\"!@#$%^&||}?:{}|\";class=\"action\";title=\"Backup Storage\"");
+ instance.parseCollection(MediaType.TEXT_OCCI, null, headers, CollectionType.ACTION);
+ fail();
+ } catch (ParsingException ex) {
+ //cool
+ }
+ }
+
+ private void assertKindsEqual(Set<Kind> expected, Set<Kind> result) {
+ assertEquals(expected.size(), result.size());
+
+ List<Kind> expectedList = new ArrayList<>();
+ expectedList.addAll(expected);
+ Collections.sort(expectedList);
+ List<Kind> resultList = new ArrayList<>();
+ resultList.addAll(result);
+ Collections.sort(resultList);
+ for (int i = 0; i < expectedList.size(); i++) {
+ assertKindDeepEquals(expectedList.get(i), resultList.get(i));
+ }
+ }
+
+ private void assertKindDeepEquals(Kind expected, Kind result) {
+ System.out.println("comparing " + expected + " with " + result);
+ assertEquals(expected, result);
+
+ assertEquals(expected.getTitle(), result.getTitle());
+ assertEquals(expected.getLocation(), result.getLocation());
+ assertEquals(expected.getRelations(), result.getRelations());
+ assertAttributesEqual(expected.getAttributes(), result.getAttributes());
+ }
+
+ private void assertMixinsEqual(Set<Mixin> expected, Set<Mixin> result) {
+ assertEquals(expected.size(), result.size());
+
+ List<Mixin> expectedList = new ArrayList<>();
+ expectedList.addAll(expected);
+ Collections.sort(expectedList);
+ List<Mixin> resultList = new ArrayList<>();
+ resultList.addAll(result);
+ Collections.sort(resultList);
+ for (int i = 0; i < expectedList.size(); i++) {
+ assertMixinDeepEquals(expectedList.get(i), resultList.get(i));
+ }
+ }
+
+ private void assertMixinDeepEquals(Mixin expected, Mixin result) {
+ System.out.println("comparing " + expected + " with " + result);
+ assertEquals(expected, result);
+
+ assertEquals(expected.getTitle(), result.getTitle());
+ assertEquals(expected.getLocation(), result.getLocation());
+ assertEquals(expected.getRelations(), result.getRelations());
+ assertAttributesEqual(expected.getAttributes(), result.getAttributes());
+ }
+
+ private void assertActionsEqual(Set<Action> expected, Set<Action> result) {
+ assertEquals(expected.size(), result.size());
+
+ List<Action> expectedList = new ArrayList<>();
+ expectedList.addAll(expected);
+ Collections.sort(expectedList);
+ List<Action> resultList = new ArrayList<>();
+ resultList.addAll(result);
+ Collections.sort(resultList);
+ for (int i = 0; i < expectedList.size(); i++) {
+ assertActionDeepEquals(expectedList.get(i), resultList.get(i));
+ }
+ }
+
+ private void assertActionDeepEquals(Action expected, Action result) {
+ System.out.println("comparing " + expected + " with " + result);
+ assertEquals(expected, result);
+
+ assertEquals(expected.getTitle(), result.getTitle());
+ assertAttributesEqual(expected.getAttributes(), result.getAttributes());
+ }
+
+ private void assertActionInstancesEqual(Set<ActionInstance> expected, Set<ActionInstance> result) {
+ assertEquals(expected.size(), result.size());
+
+ List<ActionInstance> expectedList = new ArrayList<>();
+ expectedList.addAll(expected);
+ Collections.sort(expectedList);
+ List<ActionInstance> resultList = new ArrayList<>();
+ resultList.addAll(result);
+ Collections.sort(resultList);
+ for (int i = 0; i < expectedList.size(); i++) {
+ assertActionInstanceDeepEquals(expectedList.get(i), resultList.get(i));
+ }
+ }
+
+ private void assertActionInstanceDeepEquals(ActionInstance expected, ActionInstance result) {
+ System.out.println("comparing " + expected + " with " + result);
+ assertEquals(expected, result);
+
+ assertActionDeepEquals(expected.getAction(), result.getAction());
+ for (Attribute expAttr : expected.getAttributes().keySet()) {
+ if (!result.getAttributes().containsKey(expAttr)) {
+ fail();
+ }
+ assertEquals(expected.getAttributes().get(expAttr), result.getAttributes().get(expAttr));
+ }
+ assertEquals(expected.getAttributes(), result.getAttributes());
+ }
+
+ private void assertLinksEqual(Set<Link> expected, Set<Link> result) {
+ assertEquals(expected.size(), result.size());
+
+ List<Link> expectedList = new ArrayList<>();
+ expectedList.addAll(expected);
+ Collections.sort(expectedList);
+ System.out.println("expected links: " + expectedList);
+ List<Link> resultList = new ArrayList<>();
+ resultList.addAll(result);
+ Collections.sort(resultList);
+ System.out.println("result links: " + resultList);
+ for (int i = 0; i < expectedList.size(); i++) {
+ assertLinkDeepEquals(expectedList.get(i), resultList.get(i));
+ }
+ }
+
+ private void assertLinkDeepEquals(Link expected, Link result) {
+ System.out.println("comparing " + expected + " with " + result);
+ assertEquals(expected, result);
+
+ assertEquals(expected.getTitle(), result.getTitle());
+ assertEquals(expected.getRelation(), result.getRelation());
+ assertEquals(expected.getMixins(), result.getMixins());
+ assertEquals(expected.getAttributes(), result.getAttributes());
+ }
+
+ private void assertResourcesEqual(Set<Resource> expected, Set<Resource> result) {
+ assertEquals(expected.size(), result.size());
+
+ List<Resource> expectedList = new ArrayList<>();
+ expectedList.addAll(expected);
+ Collections.sort(expectedList);
+ List<Resource> resultList = new ArrayList<>();
+ resultList.addAll(result);
+ Collections.sort(resultList);
+ for (int i = 0; i < expectedList.size(); i++) {
+ assertResourceDeepEquals(expectedList.get(i), resultList.get(i));
+ }
+ }
+
+ private void assertResourceDeepEquals(Resource expected, Resource result) {
+ System.out.println("comparing " + expected + " with " + result);
+ assertEquals(expected, result);
+
+ assertEquals(expected.getTitle(), result.getTitle());
+ assertEquals(expected.getMixins(), result.getMixins());
+ assertEquals(expected.getAttributes(), result.getAttributes());
+ assertEquals(expected.getActions(), result.getActions());
+ assertLinksEqual(expected.getLinks(), result.getLinks());
+ }
+
+ private void assertAttributesEqual(Set<Attribute> expected, Set<Attribute> result) {
+ assertEquals(expected.size(), result.size());
+
+ List<Attribute> expectedList = new ArrayList<>();
+ expectedList.addAll(expected);
+ Collections.sort(expectedList);
+ List<Attribute> resultList = new ArrayList<>();
+ resultList.addAll(result);
+ Collections.sort(resultList);
+ for (int i = 0; i < expectedList.size(); i++) {
+ assertAttributeDeepEquals(expectedList.get(i), resultList.get(i));
+ }
+ }
+
+ private void assertAttributeDeepEquals(Attribute expected, Attribute result) {
+ assertEquals(expected, result);
+
+ assertEquals(expected.isRequired(), result.isRequired());
+ assertEquals(expected.isImmutable(), result.isImmutable());
+ assertEquals(expected.getType(), result.getType());
+ assertEquals(expected.getPattern(), result.getPattern());
+ assertEquals(expected.getDefaultValue(), result.getDefaultValue());
+ assertEquals(expected.getDescription(), result.getDescription());
+ }
+}
--- /dev/null
+# Root logger option
+log4j.rootLogger=DEBUG, stdout
+
+# Redirect log messages to console
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
\ No newline at end of file
--- /dev/null
+occi.core.id="87f3bfc3-42d4-4474-b45c-757e55e093e9",occi.networkinterface.interface="eth0";,occi.networkinterface.mac="00:11:22:33:44:55";,occi.networkinterface.state="active";,occi.core.source="/vms/foo/vm1",occi.core.target="/network/123"
\ No newline at end of file
--- /dev/null
+backup;scheme="http://schemas.ogf.org/occi/infrastructure/storage/action#";class="action";title="Backup Storage"
\ No newline at end of file
--- /dev/null
+occi.core.id="87f3bfc3-42d4-4474-b45c-757e55e093e9",occi.networkinterface.interface="eth0",occi.networkinterface.mac="00:11:22:33:44:55",occi.networkinterface.state="active",occi.core.source="/vms/foo/vm1",occi.core.target="/network/123"
\ No newline at end of file
--- /dev/null
+networkinterface;scheme="http://schemas.ogf.org/occi/infrastructure#";class="kind",os_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin";title="Operating System Template";location="/mixins/os_tpl/",ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin";title="IP Network Mixin";location="/mixins/ipnetwork/";attributes="occi.network.address{required} occi.network.gateway occi.network.allocation occi.network.state",resource_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin";title="Resource Template";location="/mixins/resource_tpl/",larger;scheme="https://occi.localhost/occi/infrastructure/resource_tpl#";class="mixin";title="Larger Instance - 4 cores and 10 GB of RAM";rel="http://schemas.ogf.org/occi/infrastructure#resource_tpl";location="/mixins/larger/";attributes="occi.compute.architecture occi.compute.cores{immutable required} occi.compute.speed occi.compute.memory{immutable}",debianvm;scheme="https://occi.localhost/occi/infrastructure/os_tpl#";class="mixin";title="debianvm";rel="http://schemas.ogf.org/occi/infrastructure#os_tpl";location="/mixins/debianvm/"
\ No newline at end of file
--- /dev/null
+occi.core.id="87f3bfc3-42d4-4474-b45c-757e55e093e9",occi.core.title="compute1",occi.compute.architecture="x86",occi.compute.hostname="compute1.example.org",occi.compute.memory=1.7,occi.compute.speed=1.0,occi.compute.state="active"
\ No newline at end of file
--- /dev/null
+compute;scheme="http://schemas.ogf.org/occi/infrastructure#";class="kind";location="/compute/";title="compute resource",os_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin";title="Operating System Template";location="/mixins/os_tpl/",ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin";title="IP Network Mixin";location="/mixins/ipnetwork/";attributes="occi.network.address{required} occi.network.gateway occi.network.allocation occi.network.state",resource_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin";title="Resource Template";location="/mixins/resource_tpl/",larger;scheme="https://occi.localhost/occi/infrastructure/resource_tpl#";class="mixin";title="Larger Instance - 4 cores and 10 GB of RAM";rel="http://schemas.ogf.org/occi/infrastructure#resource_tpl";location="/mixins/larger/";attributes="occi.compute.architecture occi.compute.cores{immutable required} occi.compute.speed occi.compute.memory{immutable}",debianvm;scheme="https://occi.localhost/occi/infrastructure/os_tpl#";class="mixin";title="debianvm";rel="http://schemas.ogf.org/occi/infrastructure#os_tpl";location="/mixins/debianvm/"
\ No newline at end of file
--- /dev/null
+</network/123>;rel="http://schemas.ogf.org/occi/infrastructure#network";self="/link/networkinterface/456";category="http://schemas.ogf.org/occi/infrastructure#networkinterface";occi.networkinterface.interface="eth0";occi.networkinterface.mac="00:11:22:33:44:55";occi.networkinterface.state="active",</storage/852>;rel="http://schemas.ogf.org/occi/infrastructure#storage";self="/link/storagelink/789";category="http://schemas.ogf.org/occi/infrastructure#storagelink http://opennebula.org/occi/infrastructure#storagelink";occi.storagelink.deviceid="1234qwerty"; occi.storagelink.mountpoint="/mnt/somewhere/"; occi.storagelink.state="active",</compute/123?action=start>;rel="http://schemas.ogf.org/occi/infrastructure/compute/action#start",</compute/123?action=stop>;rel="http://schemas.ogf.org/occi/infrastructure/compute/action#stop";
\ No newline at end of file
--- /dev/null
+CATEGORY: backup;scheme="http://schemas.ogf.org/occi/infrastructure/storage/action#";class="action";title="Backup Storage"
+X-occi-Attribute: occi.core.id="87f3bfc3-42d4-4474-b45c-757e55e093e9"
+X-OCCI-Attribute: occi.networkinterface.interface="eth0";
+X-oCcI-AtTriBute: occi.networkinterface.mac="00:11:22:33:44:55";
+X-OCCI-Attribute: occi.networkinterface.state="active";
+x-occi-attribute: occi.core.source="/vms/foo/vm1"
+X-OCCI-Attribute: occi.core.target="/network/123"
\ No newline at end of file
--- /dev/null
+Category: networkinterface;scheme="http://schemas.ogf.org/occi/infrastructure#";class="kind";
+Category: os_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin";title="Operating System Template";location="/mixins/os_tpl/"
+Category: ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin";title="IP Network Mixin";location="/mixins/ipnetwork/";attributes="occi.network.address{required} occi.network.gateway occi.network.allocation occi.network.state"
+Category: resource_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin";title="Resource Template";location="/mixins/resource_tpl/"
+Category: larger;scheme="https://occi.localhost/occi/infrastructure/resource_tpl#";class="mixin";title="Larger Instance - 4 cores and 10 GB of RAM";rel="http://schemas.ogf.org/occi/infrastructure#resource_tpl";location="/mixins/larger/";attributes="occi.compute.architecture occi.compute.cores{immutable required} occi.compute.speed occi.compute.memory{immutable}"
+Category: debianvm;scheme="https://occi.localhost/occi/infrastructure/os_tpl#";class="mixin";title="debianvm";rel="http://schemas.ogf.org/occi/infrastructure#os_tpl";location="/mixins/debianvm/"
+X-OCCI-Attribute: occi.core.id="87f3bfc3-42d4-4474-b45c-757e55e093e9"
+X-OCCI-Attribute: occi.networkinterface.interface="eth0";
+X-OCCI-Attribute: occi.networkinterface.mac="00:11:22:33:44:55";
+X-OCCI-Attribute: occi.networkinterface.state="active";
+X-OCCI-Attribute: occi.core.source="/vms/foo/vm1"
+X-OCCI-Attribute: occi.core.target="/network/123"
--- /dev/null
+Category: compute;scheme="http://schemas.ogf.org/occi/infrastructure#";class="kind";location="/compute/";title="compute resource"
+Category: os_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin";title="Operating System Template";location="/mixins/os_tpl/"
+Category: ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin";title="IP Network Mixin";location="/mixins/ipnetwork/";attributes="occi.network.address{required} occi.network.gateway occi.network.allocation occi.network.state"
+CATEGORY: resource_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin";title="Resource Template";location="/mixins/resource_tpl/"
+category: larger;scheme="https://occi.localhost/occi/infrastructure/resource_tpl#";class="mixin";title="Larger Instance - 4 cores and 10 GB of RAM";rel="http://schemas.ogf.org/occi/infrastructure#resource_tpl";location="/mixins/larger/";attributes="occi.compute.architecture occi.compute.cores{immutable required} occi.compute.speed occi.compute.memory{immutable}"
+Category: debianvm;scheme="https://occi.localhost/occi/infrastructure/os_tpl#";class="mixin";title="debianvm";rel="http://schemas.ogf.org/occi/infrastructure#os_tpl";location="/mixins/debianvm/"
+X-OCCI-Attribute: occi.core.id="87f3bfc3-42d4-4474-b45c-757e55e093e9"
+X-OCCI-Attribute: occi.core.title="compute1"
+X-OCCI-Attribute: occi.compute.architecture="x86"
+X-OCCI-Attribute: occi.compute.hostname="compute1.example.org"
+X-OCCI-Attribute: occi.compute.memory=1.7
+X-OCCI-Attribute: occi.compute.speed=1.0
+X-OCCI-Attribute: occi.compute.state="active"
+LINK: </network/123>;rel="http://schemas.ogf.org/occi/infrastructure#network";self="/link/networkinterface/456";category="http://schemas.ogf.org/occi/infrastructure#networkinterface";occi.networkinterface.interface="eth0";occi.networkinterface.mac="00:11:22:33:44:55";occi.networkinterface.state="active";
+link: </storage/852>;rel="http://schemas.ogf.org/occi/infrastructure#storage";self="/link/storagelink/789";category="http://schemas.ogf.org/occi/infrastructure#storagelink http://opennebula.org/occi/infrastructure#storagelink";occi.storagelink.deviceid="1234qwerty"; occi.storagelink.mountpoint="/mnt/somewhere/"; occi.storagelink.state="active";
+Link: </compute/123?action=start>;rel="http://schemas.ogf.org/occi/infrastructure/compute/action#start"
+Link: </compute/123?action=stop>;rel="http://schemas.ogf.org/occi/infrastructure/compute/action#stop"
\ No newline at end of file
--- /dev/null
+X-OCCI-Location: http://rocci-server-1-1-x.herokuapp.com:80/compute/87f3bfc3-42d4-4474-b45c-757e55e093e9
+X-OCCI-Location: http://rocci-server-1-1-x.herokuapp.com:80/compute/17679ebd-975f-4ea0-b42b-47405178c360
+X-OCCI-Location: http://rocci-server-1-1-x.herokuapp.com:80/compute/509afbd3-abff-427c-9b25-7913d17e5102
\ No newline at end of file
--- /dev/null
+http://rocci-server-1-1-x.herokuapp.com:80/compute/87f3bfc3-42d4-4474-b45c-757e55e093e9
+http://rocci-server-1-1-x.herokuapp.com:80/compute/17679ebd-975f-4ea0-b42b-47405178c360
+http://rocci-server-1-1-x.herokuapp.com:80/compute/509afbd3-abff-427c-9b25-7913d17e5102
\ No newline at end of file
--- /dev/null
+restart;scheme="http://schemas.ogf.org/occi/infrastructure/compute/action#";class="action";title="Restart Compute instance";attributes="method",suspend;scheme="http://schemas.ogf.org/occi/infrastructure/compute/action#";class="action";title="Suspend Compute instance";attributes="method",up;scheme="http://schemas.ogf.org/occi/infrastructure/network/action#";class="action";title="Activate network",down;scheme="http://schemas.ogf.org/occi/infrastructure/network/action#up";class="action";title="Deactivate network",backup;scheme="http://schemas.ogf.org/occi/infrastructure/storage/action#";class="action";title="Backup Storage"
\ No newline at end of file
--- /dev/null
+up;scheme="http://schemas.ogf.org/occi/infrastructure/network/action#";class="action"
\ No newline at end of file
--- /dev/null
+entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Entity";location="/entity/";attributes="occi.core.id occi.core.title",resource;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Resource";rel="http://schemas.ogf.org/occi/core#entity";location="/resource/";attributes="occi.core.summary",link;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Link";rel="http://schemas.ogf.org/occi/core#entity";location="/link/";attributes="occi.core.target occi.core.source",compute;scheme="http://schemas.ogf.org/occi/infrastructure#";class="kind";title="Compute Resource";rel="http://schemas.ogf.org/occi/core#resource";location="/compute/";attributes="occi.compute.architecture{immutable} occi.compute.cores occi.compute.hostname occi.compute.speed occi.compute.memory occi.compute.state";actions="http://schemas.ogf.org/occi/infrastructure/compute/action#start http://schemas.ogf.org/occi/infrastructure/compute/action#stop http://schemas.ogf.org/occi/infrastructure/compute/action#restart http://schemas.ogf.org/occi/infrastructure/compute/action#suspend",storagelink;scheme="http://schemas.ogf.org/occi/infrastructure#";class="kind";title="Storage Link";rel="http://schemas.ogf.org/occi/core#link";location="/storagelink/";attributes="occi.storagelink.deviceid{required} occi.storagelink.mountpoint occi.storagelink.state{required immutable}",os_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin";title="Operating System Template";location="/mixins/os_tpl/",ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin";title="IP Network Mixin";location="/mixins/ipnetwork/";attributes="occi.network.address{required} occi.network.gateway occi.network.allocation occi.network.state",resource_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin";title="Resource Template";location="/mixins/resource_tpl/",larger;scheme="https://occi.localhost/occi/infrastructure/resource_tpl#";class="mixin";title="Larger Instance - 4 cores and 10 GB of RAM";rel="http://schemas.ogf.org/occi/infrastructure#resource_tpl";location="/mixins/larger/";attributes="occi.compute.architecture occi.compute.cores{immutable required} occi.compute.speed occi.compute.memory{immutable}",debianvm;scheme="https://occi.localhost/occi/infrastructure/os_tpl#";class="mixin";title="debianvm";rel="http://schemas.ogf.org/occi/infrastructure#os_tpl";location="/mixins/debianvm/",restart;scheme="http://schemas.ogf.org/occi/infrastructure/compute/action#";class="action";title="Restart Compute instance";attributes="method",suspend;scheme="http://schemas.ogf.org/occi/infrastructure/compute/action#";class="action";title="Suspend Compute instance";attributes="method",up;scheme="http://schemas.ogf.org/occi/infrastructure/network/action#";class="action";title="Activate network",down;scheme="http://schemas.ogf.org/occi/infrastructure/network/action#up";class="action";title="Deactivate network",backup;scheme="http://schemas.ogf.org/occi/infrastructure/storage/action#";class="action";title="Backup Storage"
\ No newline at end of file
--- /dev/null
+entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Entity";location="/entity/";attributes="occi.core.id occi.core.title",resource;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Resource";rel="http://schemas.ogf.org/occi/core#entity";location="/resource/";attributes="occi.core.summary",link;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Link";rel="http://schemas.ogf.org/occi/core#entity";location="/link/";attributes="occi.core.target occi.core.source",compute;scheme="http://schemas.ogf.org/occi/infrastructure#";class="kind";title="Compute Resource";rel="http://schemas.ogf.org/occi/core#resource";location="/compute/";attributes="occi.compute.architecture{immutable} occi.compute.cores occi.compute.hostname occi.compute.speed occi.compute.memory occi.compute.state";actions="http://schemas.ogf.org/occi/infrastructure/compute/action#start http://schemas.ogf.org/occi/infrastructure/compute/action#stop http://schemas.ogf.org/occi/infrastructure/compute/action#restart http://schemas.ogf.org/occi/infrastructure/compute/action#suspend",storagelink;scheme="http://schemas.ogf.org/occi/infrastructure#";class="kind";title="Storage Link";rel="http://schemas.ogf.org/occi/core#link";location="/storagelink/";attributes="occi.storagelink.deviceid{required} occi.storagelink.mountpoint occi.storagelink.state{required immutable}"
\ No newline at end of file
--- /dev/null
+entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";location="/entity/"
\ No newline at end of file
--- /dev/null
+os_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin";title="Operating System Template";location="/mixins/os_tpl/",ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin";title="IP Network Mixin";location="/mixins/ipnetwork/";attributes="occi.network.address{required} occi.network.gateway occi.network.allocation occi.network.state",resource_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin";title="Resource Template";location="/mixins/resource_tpl/",larger;scheme="https://occi.localhost/occi/infrastructure/resource_tpl#";class="mixin";title="Larger Instance - 4 cores and 10 GB of RAM";rel="http://schemas.ogf.org/occi/infrastructure#resource_tpl";location="/mixins/larger/";attributes="occi.compute.architecture occi.compute.cores{immutable required} occi.compute.speed occi.compute.memory{immutable}",debianvm;scheme="https://occi.localhost/occi/infrastructure/os_tpl#";class="mixin";title="debianvm";rel="http://schemas.ogf.org/occi/infrastructure#os_tpl";location="/mixins/debianvm/"
\ No newline at end of file
--- /dev/null
+os_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin";location="/mixins/os_tpl/"
\ No newline at end of file
--- /dev/null
+Category: restart;scheme="http://schemas.ogf.org/occi/infrastructure/compute/action#";class="action";title="Restart Compute instance";attributes="method"
+Category: suspend;scheme="http://schemas.ogf.org/occi/infrastructure/compute/action#";class="action";title="Suspend Compute instance";attributes="method"
+Category: up;scheme="http://schemas.ogf.org/occi/infrastructure/network/action#";class="action";title="Activate network"
+Category: down;scheme="http://schemas.ogf.org/occi/infrastructure/network/action#up";class="action";title="Deactivate network"
+Category: backup;scheme="http://schemas.ogf.org/occi/infrastructure/storage/action#";class="action";title="Backup Storage"
\ No newline at end of file
--- /dev/null
+category: up;scheme="http://schemas.ogf.org/occi/infrastructure/network/action#";class="action"
\ No newline at end of file
--- /dev/null
+Category: entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Entity";location="/entity/";attributes="occi.core.id occi.core.title"
+Category: resource;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Resource";rel="http://schemas.ogf.org/occi/core#entity";location="/resource/";attributes="occi.core.summary"
+Category: link;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Link";rel="http://schemas.ogf.org/occi/core#entity";location="/link/";attributes="occi.core.target occi.core.source"
+Category: compute;scheme="http://schemas.ogf.org/occi/infrastructure#";class="kind";title="Compute Resource";rel="http://schemas.ogf.org/occi/core#resource";location="/compute/";attributes="occi.compute.architecture{immutable} occi.compute.cores occi.compute.hostname occi.compute.speed occi.compute.memory occi.compute.state";actions="http://schemas.ogf.org/occi/infrastructure/compute/action#start http://schemas.ogf.org/occi/infrastructure/compute/action#stop http://schemas.ogf.org/occi/infrastructure/compute/action#restart http://schemas.ogf.org/occi/infrastructure/compute/action#suspend"
+category: storagelink;scheme="http://schemas.ogf.org/occi/infrastructure#";class="kind";title="Storage Link";rel="http://schemas.ogf.org/occi/core#link";location="/storagelink/";attributes="occi.storagelink.deviceid{required} occi.storagelink.mountpoint occi.storagelink.state{required immutable}"
+Category: os_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin";title="Operating System Template";location="/mixins/os_tpl/"
+Category: ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin";title="IP Network Mixin";location="/mixins/ipnetwork/";attributes="occi.network.address{required} occi.network.gateway occi.network.allocation occi.network.state"
+Category: resource_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin";title="Resource Template";location="/mixins/resource_tpl/"
+Category: larger;scheme="https://occi.localhost/occi/infrastructure/resource_tpl#";class="mixin";title="Larger Instance - 4 cores and 10 GB of RAM";rel="http://schemas.ogf.org/occi/infrastructure#resource_tpl";location="/mixins/larger/";attributes="occi.compute.architecture occi.compute.cores{immutable required} occi.compute.speed occi.compute.memory{immutable}"
+cAtEgOrY: debianvm;scheme="https://occi.localhost/occi/infrastructure/os_tpl#";class="mixin";title="debianvm";rel="http://schemas.ogf.org/occi/infrastructure#os_tpl";location="/mixins/debianvm/"
+Category: restart;scheme="http://schemas.ogf.org/occi/infrastructure/compute/action#";class="action";title="Restart Compute instance";attributes="method"
+Category: suspend;scheme="http://schemas.ogf.org/occi/infrastructure/compute/action#";class="action";title="Suspend Compute instance";attributes="method"
+Category: up;scheme="http://schemas.ogf.org/occi/infrastructure/network/action#";class="action";title="Activate network"
+Category: down;scheme="http://schemas.ogf.org/occi/infrastructure/network/action#up";class="action";title="Deactivate network"
+Category: backup;scheme="http://schemas.ogf.org/occi/infrastructure/storage/action#";class="action";title="Backup Storage"
\ No newline at end of file
--- /dev/null
+Category: entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Entity";location="/entity/";attributes="occi.core.id occi.core.title"
+Category: resource;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Resource";rel="http://schemas.ogf.org/occi/core#entity";location="/resource/";attributes="occi.core.summary"
+Category: link;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Link";rel="http://schemas.ogf.org/occi/core#entity";location="/link/";attributes="occi.core.target occi.core.source"
+Category: compute;scheme="http://schemas.ogf.org/occi/infrastructure#";class="kind";title="Compute Resource";rel="http://schemas.ogf.org/occi/core#resource";location="/compute/";attributes="occi.compute.architecture{immutable} occi.compute.cores occi.compute.hostname occi.compute.speed occi.compute.memory occi.compute.state";actions="http://schemas.ogf.org/occi/infrastructure/compute/action#start http://schemas.ogf.org/occi/infrastructure/compute/action#stop http://schemas.ogf.org/occi/infrastructure/compute/action#restart http://schemas.ogf.org/occi/infrastructure/compute/action#suspend"
+Category: storagelink;scheme="http://schemas.ogf.org/occi/infrastructure#";class="kind";title="Storage Link";rel="http://schemas.ogf.org/occi/core#link";location="/storagelink/";attributes="occi.storagelink.deviceid{required} occi.storagelink.mountpoint occi.storagelink.state{required immutable}"
\ No newline at end of file
--- /dev/null
+Category: entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";location="/entity/"
\ No newline at end of file
--- /dev/null
+Category: os_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin";title="Operating System Template";location="/mixins/os_tpl/"
+Category: ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin";title="IP Network Mixin";location="/mixins/ipnetwork/";attributes="occi.network.address{required} occi.network.gateway occi.network.allocation occi.network.state"
+Category: resource_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin";title="Resource Template";location="/mixins/resource_tpl/"
+Category: larger;scheme="https://occi.localhost/occi/infrastructure/resource_tpl#";class="mixin";title="Larger Instance - 4 cores and 10 GB of RAM";rel="http://schemas.ogf.org/occi/infrastructure#resource_tpl";location="/mixins/larger/";attributes="occi.compute.architecture occi.compute.cores{immutable required} occi.compute.speed occi.compute.memory{immutable}"
+Category: debianvm;scheme="https://occi.localhost/occi/infrastructure/os_tpl#";class="mixin";title="debianvm";rel="http://schemas.ogf.org/occi/infrastructure#os_tpl";location="/mixins/debianvm/"
\ No newline at end of file
--- /dev/null
+Category: os_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin";location="/mixins/os_tpl/"
\ No newline at end of file
--- /dev/null
+occi.core.id="87f3bfc3-42d4-4474-b45c-757e55e093e9"
+occi.core.source="/vms/foo/vm1"
+occi.core.target="/network/123"
+occi.networkinterface.interface="eth0"
+occi.networkinterface.mac="00:11:22:33:44:55"
+occi.networkinterface.state="active"
\ No newline at end of file
--- /dev/null
+backup;scheme="http://schemas.ogf.org/occi/infrastructure/storage/action#";class="action";title="Backup Storage";
\ No newline at end of file
--- /dev/null
+Category: backup;scheme="http://schemas.ogf.org/occi/infrastructure/storage/action#";class="action";title="Backup Storage";
+X-OCCI-Attribute: occi.core.id="87f3bfc3-42d4-4474-b45c-757e55e093e9"
+X-OCCI-Attribute: occi.core.source="/vms/foo/vm1"
+X-OCCI-Attribute: occi.core.target="/network/123"
+X-OCCI-Attribute: occi.networkinterface.interface="eth0"
+X-OCCI-Attribute: occi.networkinterface.mac="00:11:22:33:44:55"
+X-OCCI-Attribute: occi.networkinterface.state="active"
\ No newline at end of file
--- /dev/null
+</network/123>;rel="http://schemas.ogf.org/occi/infrastructure#network";category="http://schemas.ogf.org/occi/infrastructure#networkinterface";occi.core.id=456;occi.core.target="/network/123";
+</network/123>;rel="http://schemas.ogf.org/occi/infrastructure#network";self="/link/networkinterface/456";category="http://schemas.ogf.org/occi/infrastructure#networkinterface";occi.core.id=456;occi.core.target="/network/123";
+</network/123>;rel="http://schemas.ogf.org/occi/infrastructure#network";category="http://schemas.ogf.org/occi/infrastructure#networkinterface";occi.core.id=456;occi.core.target="/network/123";occi.networkinterface.interface="eth0";occi.networkinterface.mac="00:11:22:33:44:55";occi.networkinterface.state="active";
+</network/123>;rel="http://schemas.ogf.org/occi/infrastructure#network";self="/link/networkinterface/456";category="http://schemas.ogf.org/occi/infrastructure#networkinterface";occi.core.id=456;occi.core.target="/network/123";occi.networkinterface.interface="eth0";occi.networkinterface.mac="00:11:22:33:44:55";occi.networkinterface.state="active";
--- /dev/null
+Link: </network/123>;rel="http://schemas.ogf.org/occi/infrastructure#network";category="http://schemas.ogf.org/occi/infrastructure#networkinterface";occi.core.id=456;occi.core.target="/network/123";
+Link: </network/123>;rel="http://schemas.ogf.org/occi/infrastructure#network";self="/link/networkinterface/456";category="http://schemas.ogf.org/occi/infrastructure#networkinterface";occi.core.id=456;occi.core.target="/network/123";
+Link: </network/123>;rel="http://schemas.ogf.org/occi/infrastructure#network";category="http://schemas.ogf.org/occi/infrastructure#networkinterface";occi.core.id=456;occi.core.target="/network/123";occi.networkinterface.interface="eth0";occi.networkinterface.mac="00:11:22:33:44:55";occi.networkinterface.state="active";
+Link: </network/123>;rel="http://schemas.ogf.org/occi/infrastructure#network";self="/link/networkinterface/456";category="http://schemas.ogf.org/occi/infrastructure#networkinterface";occi.core.id=456;occi.core.target="/network/123";occi.networkinterface.interface="eth0";occi.networkinterface.mac="00:11:22:33:44:55";occi.networkinterface.state="active";
--- /dev/null
+entity;scheme="http://schemas.ogf.org/occi/core#";class="kind"
+entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Entity"
+entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";location="/entity/"
+entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";attributes="occi.core.id occi.core.title"
+entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";actions="http://schemas.ogf.org/occi/infrastructure/compute/action#start http://schemas.ogf.org/occi/infrastructure/compute/action#stop"
+entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Entity";location="/entity/";attributes="occi.core.id occi.core.title";actions="http://schemas.ogf.org/occi/infrastructure/compute/action#start http://schemas.ogf.org/occi/infrastructure/compute/action#stop"
+entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Entity";location="/entity/";attributes="occi.core.id{required} occi.core.title";actions="http://schemas.ogf.org/occi/infrastructure/compute/action#start http://schemas.ogf.org/occi/infrastructure/compute/action#stop"
+entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Entity";location="/entity/";attributes="occi.core.id{required immutable} occi.core.title";actions="http://schemas.ogf.org/occi/infrastructure/compute/action#start http://schemas.ogf.org/occi/infrastructure/compute/action#stop"
+entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Entity";location="/entity/";attributes="occi.core.id{required immutable} occi.core.title{immutable}";actions="http://schemas.ogf.org/occi/infrastructure/compute/action#start http://schemas.ogf.org/occi/infrastructure/compute/action#stop"
\ No newline at end of file
--- /dev/null
+Category: entity;scheme="http://schemas.ogf.org/occi/core#";class="kind"
+Category: entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Entity"
+Category: entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";location="/entity/"
+Category: entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";attributes="occi.core.id occi.core.title"
+Category: entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";actions="http://schemas.ogf.org/occi/infrastructure/compute/action#start http://schemas.ogf.org/occi/infrastructure/compute/action#stop"
+Category: entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Entity";location="/entity/";attributes="occi.core.id occi.core.title";actions="http://schemas.ogf.org/occi/infrastructure/compute/action#start http://schemas.ogf.org/occi/infrastructure/compute/action#stop"
+Category: entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Entity";location="/entity/";attributes="occi.core.id{required} occi.core.title";actions="http://schemas.ogf.org/occi/infrastructure/compute/action#start http://schemas.ogf.org/occi/infrastructure/compute/action#stop"
+Category: entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Entity";location="/entity/";attributes="occi.core.id{required immutable} occi.core.title";actions="http://schemas.ogf.org/occi/infrastructure/compute/action#start http://schemas.ogf.org/occi/infrastructure/compute/action#stop"
+Category: entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Entity";location="/entity/";attributes="occi.core.id{required immutable} occi.core.title{immutable}";actions="http://schemas.ogf.org/occi/infrastructure/compute/action#start http://schemas.ogf.org/occi/infrastructure/compute/action#stop"
\ No newline at end of file
--- /dev/null
+occi.compute.architecture="x86"
+occi.compute.hostname="compute1.example.org"
+occi.compute.memory=1.7
+occi.compute.speed=1.0
+occi.compute.state="active"
+occi.core.id="87f3bfc3-42d4-4474-b45c-757e55e093e9"
+occi.core.title="compute1"
\ No newline at end of file
--- /dev/null
+console;scheme="http://schemas.ogf.org/occi/infrastructure/compute#";class="kind"
+os_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin"
+resource_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin"
+ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin"
\ No newline at end of file
--- /dev/null
+Category: console;scheme="http://schemas.ogf.org/occi/infrastructure/compute#";class="kind"
+Category: os_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin"
+Category: resource_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin"
+Category: ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin"
+X-OCCI-Attribute: occi.compute.architecture="x86"
+X-OCCI-Attribute: occi.compute.hostname="compute1.example.org"
+X-OCCI-Attribute: occi.compute.memory=1.7
+X-OCCI-Attribute: occi.compute.speed=1.0
+X-OCCI-Attribute: occi.compute.state="active"
+X-OCCI-Attribute: occi.core.id="87f3bfc3-42d4-4474-b45c-757e55e093e9"
+X-OCCI-Attribute: occi.core.title="compute1"
\ No newline at end of file
--- /dev/null
+ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin"
+ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin";title="IP Network Mixin"
+ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin";location="/mixins/ipnetwork/"
+ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin";attributes="occi.network.address occi.network.allocation occi.network.gateway occi.network.state"
+ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin";actions="http://schemas.ogf.org/occi/infrastructure/compute/action#start http://schemas.ogf.org/occi/infrastructure/compute/action#stop"
+ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin";title="IP Network Mixin";location="/mixins/ipnetwork/";attributes="occi.network.address{required} occi.network.allocation{required immutable} occi.network.gateway{immutable} occi.network.state";actions="http://schemas.ogf.org/occi/infrastructure/compute/action#start http://schemas.ogf.org/occi/infrastructure/compute/action#stop"
\ No newline at end of file
--- /dev/null
+Category: ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin"
+Category: ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin";title="IP Network Mixin"
+Category: ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin";location="/mixins/ipnetwork/"
+Category: ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin";attributes="occi.network.address occi.network.allocation occi.network.gateway occi.network.state"
+Category: ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin";actions="http://schemas.ogf.org/occi/infrastructure/compute/action#start http://schemas.ogf.org/occi/infrastructure/compute/action#stop"
+Category: ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin";title="IP Network Mixin";location="/mixins/ipnetwork/";attributes="occi.network.address{required} occi.network.allocation{required immutable} occi.network.gateway{immutable} occi.network.state";actions="http://schemas.ogf.org/occi/infrastructure/compute/action#start http://schemas.ogf.org/occi/infrastructure/compute/action#stop"
\ No newline at end of file
--- /dev/null
+occi.compute.architecture="x86"
+occi.compute.hostname="compute1.example.org"
+occi.compute.memory=1.7
+occi.compute.speed=1.0
+occi.compute.state="active"
+occi.core.id="87f3bfc3-42d4-4474-b45c-757e55e093e9"
+occi.core.title="compute1"
\ No newline at end of file
--- /dev/null
+compute;scheme="http://schemas.ogf.org/occi/infrastructure#";class="kind"
+os_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin"
+resource_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin"
+ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin"
+debianvm;scheme="https://occi.localhost/occi/infrastructure/os_tpl#";class="mixin"
+larger;scheme="https://occi.localhost/occi/infrastructure/resource_tpl#";class="mixin"
\ No newline at end of file
--- /dev/null
+</network/123>;rel="http://schemas.ogf.org/occi/infrastructure#network";self="/link/networkinterface/456";category="http://schemas.ogf.org/occi/infrastructure#networkinterface";occi.core.id=456;occi.core.source="/compute/87f3bfc3-42d4-4474-b45c-757e55e093e9";occi.core.target="/network/123";occi.networkinterface.interface="eth0";occi.networkinterface.mac="00:11:22:33:44:55";occi.networkinterface.state="active";
+</storage/852>;rel="http://schemas.ogf.org/occi/infrastructure#storage";self="/link/storagelink/789";category="http://schemas.ogf.org/occi/infrastructure#storagelink http://opennebula.org/occi/infrastructure#storagelink";occi.core.id=789;occi.core.source="/compute/87f3bfc3-42d4-4474-b45c-757e55e093e9";occi.core.target="/storage/852";occi.storagelink.deviceid="1234qwerty";occi.storagelink.mountpoint="/mnt/somewhere/";occi.storagelink.state="active";
+</compute/87f3bfc3-42d4-4474-b45c-757e55e093e9?action=start>;rel="http://schemas.ogf.org/occi/infrastructure/compute/action#start";
+</compute/87f3bfc3-42d4-4474-b45c-757e55e093e9?action=stop>;rel="http://schemas.ogf.org/occi/infrastructure/compute/action#stop";
\ No newline at end of file
--- /dev/null
+Category: compute;scheme="http://schemas.ogf.org/occi/infrastructure#";class="kind"
+Category: os_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin"
+Category: resource_tpl;scheme="http://schemas.ogf.org/occi/infrastructure#";class="mixin"
+Category: ipnetwork;scheme="http://schemas.ogf.org/occi/infrastructure/network#";class="mixin"
+Category: debianvm;scheme="https://occi.localhost/occi/infrastructure/os_tpl#";class="mixin"
+Category: larger;scheme="https://occi.localhost/occi/infrastructure/resource_tpl#";class="mixin"
+X-OCCI-Attribute: occi.compute.architecture="x86"
+X-OCCI-Attribute: occi.compute.hostname="compute1.example.org"
+X-OCCI-Attribute: occi.compute.memory=1.7
+X-OCCI-Attribute: occi.compute.speed=1.0
+X-OCCI-Attribute: occi.compute.state="active"
+X-OCCI-Attribute: occi.core.id="87f3bfc3-42d4-4474-b45c-757e55e093e9"
+X-OCCI-Attribute: occi.core.title="compute1"
+Link: </network/123>;rel="http://schemas.ogf.org/occi/infrastructure#network";self="/link/networkinterface/456";category="http://schemas.ogf.org/occi/infrastructure#networkinterface";occi.core.id=456;occi.core.source="/compute/87f3bfc3-42d4-4474-b45c-757e55e093e9";occi.core.target="/network/123";occi.networkinterface.interface="eth0";occi.networkinterface.mac="00:11:22:33:44:55";occi.networkinterface.state="active";
+Link: </storage/852>;rel="http://schemas.ogf.org/occi/infrastructure#storage";self="/link/storagelink/789";category="http://schemas.ogf.org/occi/infrastructure#storagelink http://opennebula.org/occi/infrastructure#storagelink";occi.core.id=789;occi.core.source="/compute/87f3bfc3-42d4-4474-b45c-757e55e093e9";occi.core.target="/storage/852";occi.storagelink.deviceid="1234qwerty";occi.storagelink.mountpoint="/mnt/somewhere/";occi.storagelink.state="active";
+Link: </compute/87f3bfc3-42d4-4474-b45c-757e55e093e9?action=start>;rel="http://schemas.ogf.org/occi/infrastructure/compute/action#start";
+Link: </compute/87f3bfc3-42d4-4474-b45c-757e55e093e9?action=stop>;rel="http://schemas.ogf.org/occi/infrastructure/compute/action#stop";
\ No newline at end of file