Back to git
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5d29018
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+target/
+.svn
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/NOTICE.txt b/NOTICE.txt
new file mode 100644
index 0000000..66a6d0f
--- /dev/null
+++ b/NOTICE.txt
@@ -0,0 +1,8 @@
+Apache Commons RDF
+Copyright 2001-2014 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+This product includes software developed at
+https://github.com/commons-rdf/commons-rdf.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5e05c3d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,72 @@
+## Building
+
+Build using Apache Maven with
+
+ mvn install
+
+## Documentation
+
+You can build the documentation with:
+
+ mvn site
+
+## FAQ
+
+Some more advanced questions focused on showing the differences to other proposed APIs.
+
+### Can I add RdfTerms from one implementation to another?
+
+Yes, any compliant implementation of BlankNode, Iri or Literal as well as Triple
+can be added to any implemenation of Graph, as long the Graph supports adding triples. Implementation
+may not require the nodes to be of a particular implementation of having been
+created with a specific factory.
+
+### How does it work?
+
+Implementation might need to map instances of BlankNode to their internal
+implementation. This should be done in a way that when there is no more reference
+to the BlankNode object (i.e. when the object can be garbage collected) the mapping
+to the internal implementation is removed from memory to. This can be achieved
+by using a java.util.WeakHashMap
+
+### Do I get back the same object that I added?
+
+For instances of Iri or Literals you get back an object that result equal to the
+originally added object, i.e. an object with the same HashCode and of which the
+equals method return true when compared with the originally added object. Ther
+is no guarantee that the same instance will be returned.
+For instances of BlankNode the above in only guaranteed as long as the original
+object is referenced. When the original object becomes eligible for garbage
+collection the implementation may start returning a different (an not equal)
+object. In practice this means BlankNode objects cannot safely be serialized
+(using Java serialization) or passed around via RMI.
+
+### Can an implementation remove redundant information from a Graph?
+
+Yes, as long as this doesn't affect any BlankNode instance that is currently
+reachable (i.e. the Java object is in memory and is not eligible for garbage
+collection).
+
+For example given the non-lean graph:
+
+ ex:a ex:p _:x .
+ _:y ex:p _:x .
+
+As long as there is no BlankNode instance referencing _:y the implementation can
+reduce the graph to:
+
+ ex:a ex:p _:x .
+
+removing the redundancy. If however there is a reachable BlankNode instance for
+_:y the implementation must not remove the redundancy as the code which has
+access to the object can go on adding a triple:
+
+ _:y ex:p2 ex:b .
+
+Thus creating a graph that doesn't contain any internal redundancy, namely:
+
+ ex:a ex:p _:x .
+ _:y ex:p _:x .
+ _:y ex:p2 ex:b .
+
+
diff --git a/alerts.txt b/alerts.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/alerts.txt
diff --git a/api/pom.xml b/api/pom.xml
new file mode 100644
index 0000000..7994cd2
--- /dev/null
+++ b/api/pom.xml
@@ -0,0 +1,387 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+
+-->
+
+<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/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-parent</artifactId>
+ <version>37</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>commons-rdf</groupId>
+ <artifactId>commons-rdf-api</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ <name>Apache Commons RDF API</name>
+ <description>
+ Apache Commons RDF provides an API modelling the RDF data model as defined by
+ http://www.w3.org/TR/rdf11-concepts/
+ </description>
+ <url>http://commons.apache.org/sandbox/commons-rdf/</url>
+ <!-- TBD
+ <issueManagement>
+ <system>jira</system>
+ <url>http://issues.apache.org/jira/browse/RDF</url>
+ </issueManagement>
+ -->
+ <inceptionYear>2014</inceptionYear>
+ <scm>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/rdf/trunk</connection>
+ <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/rdf/trunk</developerConnection>
+ <url>http://svn.apache.org/viewvc/commons/proper/rdf/trunk</url>
+ </scm>
+
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <distributionManagement>
+ <site>
+ <id>apache.website</id>
+ <name>Apache Commons Site</name>
+ <url>${commons.deployment.protocol}://people.apache.org/www/commons.apache.org/${commons.componentid}</url>
+ </site>
+ </distributionManagement>
+
+ <properties>
+ <maven.compiler.source>1.7</maven.compiler.source>
+ <maven.compiler.target>1.7</maven.compiler.target>
+ <commons.javadoc.java.link>http://docs.oracle.com/javase/7/docs/api/</commons.javadoc.java.link>
+ <commons.componentid>rdf</commons.componentid>
+ <commons.release.version>${project.version}</commons.release.version>
+ <commons.encoding>UTF-8</commons.encoding>
+<!-- <commons.rc.version>RC1</commons.rc.version>
+ <commons.release.desc>(Requires Java ${maven.compiler.target} or later)</commons.release.desc>
+ <commons.release.2.version>1.4.1</commons.release.2.version>
+ <commons.release.2.binary.suffix />
+ <commons.release.2.desc>(Requires Java 1.3 or later)</commons.release.2.desc> -->
+ <!-- TBD <commons.jira.id>RDF</commons.jira.id>
+ <commons.jira.pid></commons.jira.pid> -->
+ </properties>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>${commons.compiler.version}</version>
+ <configuration>
+ <!-- Fix incremental compiler bug, see https://jira.codehaus.org/browse/MCOMPILER-205 etc. -->
+ <excludes>
+ <exclude>**/package-info.java</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ <plugins>
+
+ <!-- Exclude examples from binary jar -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <excludes>
+ <exclude>examples/**</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+
+ <!-- Exclude examples from source jar -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-source-plugin</artifactId>
+ <configuration>
+ <excludes>
+ <exclude>examples/**</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <excludes>
+ <exclude>**/*FunctionalTest.java</exclude>
+ <exclude>**/POP3*Test.java</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <configuration>
+ <descriptors>
+ <descriptor>src/main/assembly/bin.xml</descriptor>
+ <descriptor>src/main/assembly/src.xml</descriptor>
+ </descriptors>
+ <tarLongFileMode>gnu</tarLongFileMode>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <configuration>
+ <target>
+ <jar destfile="target/commons-net-ftp-${project.version}.jar">
+ <metainf dir="${basedir}" includes="NOTICE.txt,LICENSE.txt" />
+ <manifest>
+ <attribute name="Extension-Name" value="org.apache.commons.net" />
+ <attribute name="Specification-Title" value="${project.name}" />
+ <attribute name="Implementation-Title" value="${project.name}" />
+ <attribute name="Implementation-Vendor" value="${project.organization.name}" />
+ <attribute name="Implementation-Version" value="${project.version}" />
+ <attribute name="Implementation-Vendor-Id" value="org.apache" />
+ <attribute name="Implementation-Build" value="${implementation.build}"/>
+ <attribute name="X-Compile-Source-JDK" value="${maven.compiler.source}" />
+ <attribute name="X-Compile-Target-JDK" value="${maven.compiler.target}" />
+ </manifest>
+ <fileset dir="target/classes" includes="org/apache/commons/net/ftp/**,org/apache/commons/net/*,org/apache/commons/net/io/*,org/apache/commons/net/util/*" />
+ </jar>
+ <!--
+ Create the binary examples jar, which will be added to the binary zip/tgz,
+ but not deployed independently to Maven
+ -->
+ <jar destfile="target/commons-net-examples-${project.version}.jar">
+ <metainf dir="${basedir}" includes="NOTICE.txt,LICENSE.txt" />
+ <manifest>
+ <attribute name="Extension-Name" value="org.apache.commons.net" />
+ <attribute name="Specification-Title" value="${project.name}" />
+ <attribute name="Implementation-Title" value="${project.name}" />
+ <attribute name="Implementation-Vendor" value="${project.organization.name}" />
+ <attribute name="Implementation-Version" value="${project.version}" />
+ <attribute name="Implementation-Vendor-Id" value="org.apache" />
+ <attribute name="Implementation-Build" value="${implementation.build}"/>
+ <attribute name="X-Compile-Source-JDK" value="${maven.compiler.source}" />
+ <attribute name="X-Compile-Target-JDK" value="${maven.compiler.target}" />
+ <!-- Helper application -->
+ <attribute name="Main-Class" value="examples/Main" />
+ <!-- Allow java -jar examples.jar to work -->
+ <attribute name="Class-Path" value="commons-net-${project.version}.jar" />
+ </manifest>
+ <fileset dir="target/classes" includes="examples/**" />
+ </jar>
+ </target>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <!-- Attaches the commons-net-ftp and examples JARs to the Maven lifecycle
+ to ensure they will be signed and deployed as normal -->
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.8</version>
+ <executions>
+ <execution>
+ <id>attach-artifacts</id>
+ <phase>package</phase>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>target/commons-net-ftp-${project.version}.jar</file>
+ <type>jar</type>
+ <classifier>ftp</classifier>
+ </artifact>
+ <artifact>
+ <file>target/commons-net-examples-${project.version}.jar</file>
+ <type>jar</type>
+ <classifier>examples</classifier>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- Exclude examples from Javadoc jar -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <excludePackageNames>examples.*</excludePackageNames>
+ </configuration>
+ </plugin>
+
+ <!-- Copy the examples sources -->
+ <plugin>
+ <artifactId>maven-resources-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>copy-resources</id>
+ <phase>pre-site</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${basedir}/target/site/examples</outputDirectory>
+ <resources>
+ <resource>
+ <directory>src/main/java/examples</directory>
+ <excludes>
+ <exclude>**/Main.java</exclude>
+ </excludes>
+ <filtering>false</filtering>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-scm-publish-plugin</artifactId>
+ <configuration>
+ <ignorePathsToDelete>
+ <ignorePathToDelete>javadocs</ignorePathToDelete>
+ </ignorePathsToDelete>
+ </configuration>
+ </plugin>
+
+ </plugins>
+
+ </build>
+
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-changes-plugin</artifactId>
+ <version>${commons.changes.version}</version>
+ <configuration>
+ <issueLinkTemplatePerSystem>
+ <default>%URL%/%ISSUE%</default>
+ </issueLinkTemplatePerSystem>
+ <template>release-notes.vm</template>
+ <templateDirectory>src/changes</templateDirectory>
+ <!-- Add sample JIRA report - 'mvn changes:jira-report' or 'mvn site' -->
+ <onlyCurrentVersion>false</onlyCurrentVersion>
+ <columnNames>Fix Version,Key,Component,Summary,Type,Resolution,Status</columnNames>
+ <!-- Sort cols have to be reversed in JIRA 4 -->
+ <sortColumnNames>Key DESC,Type,Fix Version DESC</sortColumnNames>
+ <resolutionIds>Fixed</resolutionIds>
+ <statusIds>Resolved,Closed</statusIds>
+ <!-- Don't include sub-task -->
+ <typeIds>Bug,New Feature,Task,Improvement,Wish,Test</typeIds>
+ <fixVersionIds>${commons.release.version}</fixVersionIds>
+ <!-- The default is 100 -->
+ <maxEntries>100</maxEntries>
+ </configuration>
+ <reportSets>
+ <reportSet>
+ <reports>
+ <report>changes-report</report>
+ <report>jira-report</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ </plugin>
+
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>findbugs-maven-plugin</artifactId>
+ <version>2.5.5</version>
+ <configuration>
+ <excludeFilterFile>findbugs-exclude-filter.xml</excludeFilterFile>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>clirr-maven-plugin</artifactId>
+ <configuration>
+ <excludes>
+ <exclude>examples/**</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <excludePackageNames>examples.*</excludePackageNames>
+ </configuration>
+ <reportSets>
+ <reportSet>
+ <reports>
+ <report>javadoc</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <version>2.11</version>
+ <configuration>
+ <configLocation>${basedir}/checkstyle.xml</configLocation>
+ <suppressionsLocation>${basedir}/checkstyle-suppressions.xml</suppressionsLocation>
+ <enableRulesSummary>false</enableRulesSummary>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <!-- Parent pom does not (yet) exclude these -->
+ <configuration>
+ <excludes>
+ <exclude>.checkstyle</exclude>
+ <exclude>.fbprefs</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+
+ </plugins>
+ </reporting>
+
+ <profiles>
+ <profile>
+ <!-- Temporary hack to suppress Javadoc 8 errors -->
+ <id>javadoc_8</id>
+ <activation>
+ <jdk>1.8</jdk>
+ </activation>
+ <properties>
+ <!-- Disable Xdoclint, until JavaDoc issues are fixed -->
+ <additionalparam>-Xdoclint:none</additionalparam>
+ </properties>
+ </profile>
+ </profiles>
+
+</project>
diff --git a/api/src/main/assembly/bin.xml b/api/src/main/assembly/bin.xml
new file mode 100644
index 0000000..3c114dd
--- /dev/null
+++ b/api/src/main/assembly/bin.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+-->
+<assembly
+ xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
+ <id>bin</id>
+ <formats>
+ <format>tar.gz</format>
+ <format>zip</format>
+ </formats>
+ <fileSets>
+ <fileSet>
+ <includes>
+ <include>README*</include>
+ <include>LICENSE*</include>
+ <include>NOTICE*</include>
+ <include>RELEASE-NOTES.txt</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>target</directory>
+ <outputDirectory></outputDirectory>
+ <includes>
+ <include>commons-net-${project.version}.jar</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>target/site/apidocs</directory>
+ <outputDirectory>apidocs</outputDirectory>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ </fileSet>
+ <!-- Include sources jar for IDEs -->
+ <fileSet>
+ <directory>target</directory>
+ <outputDirectory></outputDirectory>
+ <includes>
+ <include>commons-net-${project.version}-sources.jar</include>
+ </includes>
+ </fileSet>
+ <!-- Include examples as binary jar -->
+ <fileSet>
+ <directory>target</directory>
+ <outputDirectory></outputDirectory>
+ <includes>
+ <include>commons-net-examples-${project.version}.jar</include>
+ </includes>
+ </fileSet>
+ <!-- Include example sources for developers -->
+ <fileSet>
+ <directory>src/main/java/examples</directory>
+ <outputDirectory>examples</outputDirectory>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+</assembly>
diff --git a/api/src/main/assembly/src.xml b/api/src/main/assembly/src.xml
new file mode 100644
index 0000000..a5f8da1
--- /dev/null
+++ b/api/src/main/assembly/src.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+-->
+<assembly
+ xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
+ <id>src</id>
+ <formats>
+ <format>tar.gz</format>
+ <format>zip</format>
+ </formats>
+ <baseDirectory>${artifactId}-${version}-src</baseDirectory>
+ <fileSets>
+ <fileSet>
+ <includes>
+ <include>README*</include>
+ <include>LICENSE*</include>
+ <include>NOTICE*</include>
+ <include>RELEASE-NOTES.txt</include>
+ <include>pom.xml</include>
+ <include>findbugs-exclude-filter.xml</include>
+ <include>checkstyle*.xml</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>src</directory>
+ </fileSet>
+ </fileSets>
+</assembly>
+
diff --git a/api/src/main/java/org/apache/commons/rdf/BlankNode.java b/api/src/main/java/org/apache/commons/rdf/BlankNode.java
new file mode 100644
index 0000000..2fcf23b
--- /dev/null
+++ b/api/src/main/java/org/apache/commons/rdf/BlankNode.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf;
+
+/**
+ * A Blank Node represents a resource,
+ * but does not indicate a URI for the resource. Blank nodes act like
+ * existentially qualified variables in first order logic.
+ *
+ * An <a href= "http://www.w3.org/TR/rdf11-concepts/#dfn-blank-node" >RDF-1.1
+ * Blank Node</a>, as defined by <a href=
+ * "http://www.w3.org/TR/rdf11-concepts/#section-blank-nodes" >RDF-1.1 Concepts
+ * and Abstract Syntax</a>, a W3C Recommendation published on 25 February 2014.<br>
+ *
+ * Note that: Blank nodes are disjoint from IRIs and literals. Otherwise,
+ * the set of possible blank nodes is arbitrary. RDF makes no reference to any
+ * internal structure of blank nodes.
+ *
+ *
+ * @see <a href= "http://www.w3.org/TR/rdf11-concepts/#dfn-blank-node">RDF-1.1
+ * Blank Node</a>
+ */
+public class BlankNode implements BlankNodeOrIri {
+
+}
diff --git a/api/src/main/java/org/apache/commons/rdf/BlankNodeOrIri.java b/api/src/main/java/org/apache/commons/rdf/BlankNodeOrIri.java
new file mode 100644
index 0000000..0a292d8
--- /dev/null
+++ b/api/src/main/java/org/apache/commons/rdf/BlankNodeOrIri.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf;
+
+/**
+ * Represents a <code>Resource</code> that is not a <code>Literal</code>.
+ * This is a marker interface implemented by <code>UriRef</code>
+ * and <code>BNode</code>.
+ *
+ * @author reto
+ */
+public interface BlankNodeOrIri extends RdfTerm {
+
+}
diff --git a/api/src/main/java/org/apache/commons/rdf/Graph.java b/api/src/main/java/org/apache/commons/rdf/Graph.java
new file mode 100644
index 0000000..5a188ff
--- /dev/null
+++ b/api/src/main/java/org/apache/commons/rdf/Graph.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.concurrent.locks.ReadWriteLock;
+import org.apache.commons.rdf.event.FilterTriple;
+import org.apache.commons.rdf.event.GraphListener;
+
+
+/**
+ * A set of triples (as it doesn't allow duplicates), it does however
+ * not extend {@link java.util.Set} as it doesn't inherit its
+ * specification for <code>hashCode()</code> and <code>equals</code>.
+ * It is possible to add <code>GraphListener</code> to listen for modifications
+ * in the triples.
+ *
+ * @author reto
+ */
+public interface Graph extends Collection<Triple> {
+
+ /**
+ * Filters triples given a pattern.
+ * filter(null, null, null) returns the same as iterator()
+ *
+ * @param subject
+ * @param predicate
+ * @param object
+ * @return <code>Iterator</code>
+ */
+ public Iterator<Triple> filter(BlankNodeOrIri subject, Iri predicate,
+ RdfTerm object);
+
+ /**
+ * Returns true if <code>other</code> describes the same graph and will
+ * always describe the same graph as this instance, false otherwise.
+ * It returns true if this == other or if it
+ * is otherwise guaranteed that changes to one of the instances are
+ * immediately reflected in the other or if both graphs are immutable.
+ *
+ * @param other
+ * @return true if other == this
+ */
+ @Override
+ public boolean equals(Object other);
+
+ /**
+ * Returns an ImutableGraph describing the graph at the current point in
+ * time. if <code>this</code> is an instance of ImmutableGraph this can
+ * safely return <code>this</code>.
+ *
+ * @return the current time slice of the possibly mutable graph represented by the instance.
+ */
+ public ImmutableGraph getImmutableGraph();
+
+ /**
+ * The lock provided by this methods allows to create read- and write-locks
+ * that span multiple method calls. Having a read locks prevents other
+ * threads from writing to this Graph, having a write-lock prevents other
+ * threads from reading and writing. Implementations would typically
+ * return a <code>java.util.concurrent.locks.ReentrantReadWriteLock</code>.
+ * Immutable instances (such as instances of <code>ImmutableGraph</code>)
+ * or instances used in transaction where concurrent acces of the same
+ * instance is not an issue may return a no-op ReadWriteLock (i.e. one
+ * which returned ReadLock and WriteLock instances of which the methods do
+ * not do anything)
+ *
+ * @return the lock of this Graph
+ */
+ ReadWriteLock getLock();
+}
diff --git a/api/src/main/java/org/apache/commons/rdf/ImmutableGraph.java b/api/src/main/java/org/apache/commons/rdf/ImmutableGraph.java
new file mode 100644
index 0000000..a3b0211
--- /dev/null
+++ b/api/src/main/java/org/apache/commons/rdf/ImmutableGraph.java
@@ -0,0 +1,55 @@
+ /*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf;
+
+/**
+ * A graph, modeled as a set of triples.
+ * This interface does not extend java.util.Set because of the different
+ * identity constraints, i.e. two <code>Graph</code>s may be equal (isomorphic)
+ * even if the set of triples are not.
+ *
+ * Implementations MUST be immutable and throw respective exceptions, when
+ * add/remove-methods are called.
+ *
+ * @see org.apache.clerezza.rdf.core.impl.AbstractGraph
+ * @author reto
+ *
+ */
+public interface ImmutableGraph extends Graph {
+
+ /**
+ * Returns true if two graphs are isomorphic
+ *
+ * @return true if two graphs are isomorphic
+ */
+ @Override
+ public boolean equals(Object obj);
+
+ /**
+ * Return the sum of the blank-nodes independent hashes of the triples.
+ * More precisely the hash of the triple is calculated as follows:
+ * (hash(subject) >> 1) ^ hash(hashCode) ^ (hash(hashCode) << 1)
+ * Where the hash-fucntion return the hashCode of the argument
+ * for grounded arguments and 0 otherwise.
+ *
+ * @return hash code
+ */
+ @Override
+ public int hashCode();
+}
\ No newline at end of file
diff --git a/api/src/main/java/org/apache/commons/rdf/Iri.java b/api/src/main/java/org/apache/commons/rdf/Iri.java
new file mode 100644
index 0000000..e1ef0f7
--- /dev/null
+++ b/api/src/main/java/org/apache/commons/rdf/Iri.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf;
+
+import java.io.Serializable;
+
+/**
+ * Represents an RDF URI Reference
+ *
+ * RDF URI References are defined in section 6.4 RDF URI References of
+ * http://www.w3.org/TR/2004/REC-rdf-concepts-20040210/#section-Graph-URIref
+ *
+ * Note that an RDF URI Reference is not the same as defined by RFC3986,
+ * RDF URI References support most unicode characters
+ *
+ * @author reto
+ */
+public class Iri implements BlankNodeOrIri, Serializable {
+
+ private String unicodeString;
+
+ public Iri(String unicodeString) {
+ this.unicodeString = unicodeString;
+ }
+
+ /**
+ * @return the unicode string that produces the URI
+ */
+ public String getUnicodeString() {
+ return unicodeString;
+ }
+
+ /**
+ * Returns true iff <code>obj</code> == <code>UriRef</code>
+ *
+ * @param obj
+ * @return true if obj is an instanceof UriRef with
+ * the same unicode-string, false otherwise
+ */
+ @Override
+ public boolean equals(Object obj) {
+
+ if (!(obj instanceof Iri)) {
+ return false;
+ }
+
+ return unicodeString.equals(((Iri) obj).getUnicodeString());
+ }
+
+ /**
+ * @return 5 + the hashcode of the string
+ */
+ @Override
+ public int hashCode() {
+ int hash = 5 + unicodeString.hashCode();
+ return hash;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append('<');
+ buffer.append(unicodeString);
+ buffer.append('>');
+ return buffer.toString();
+ }
+}
\ No newline at end of file
diff --git a/api/src/main/java/org/apache/commons/rdf/Language.java b/api/src/main/java/org/apache/commons/rdf/Language.java
new file mode 100644
index 0000000..03f328c
--- /dev/null
+++ b/api/src/main/java/org/apache/commons/rdf/Language.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf;
+
+/**
+ * Represents a language as expressed by the RDF 4646 language tag
+ *
+ * @author reto
+ */
+public class Language {
+
+ private String id;
+
+ /**
+ * Constructs the language tag defined by RDF 4646, normalized to lowercase.
+ *
+ * @param the id as defined by RDF 4646, normalized to lowercase.
+ */
+ public Language(String id) {
+ if ((id == null) || (id.equals(""))) {
+ throw new IllegalArgumentException("A language id may not be null or empty");
+ }
+ this.id = id;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == null) {
+ return false;
+ }
+ if (other instanceof Language) {
+ return id.equals(((Language) other).id);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return id;
+ }
+}
diff --git a/api/src/main/java/org/apache/commons/rdf/Literal.java b/api/src/main/java/org/apache/commons/rdf/Literal.java
new file mode 100644
index 0000000..cf5e1ee
--- /dev/null
+++ b/api/src/main/java/org/apache/commons/rdf/Literal.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf;
+
+
+/**
+ * Represents a literal value that can be a node in an RDF Graph.
+ * Literals are used to identify values such as numbers and dates by
+ * means of a lexical representation. There are two types of literals
+ * represented by the subinterfaces {@link PlainLiteral}
+ * and {@link TypedLiteral}
+ *
+ * @author reto
+ */
+public interface Literal extends RdfTerm {
+
+ /**
+ * The lexical form of this literal, represented by a <a
+ * href="http://www.unicode.org/versions/latest/">Unicode string</a>.
+ *
+ * @return The lexical form of this literal.
+ * @see <a
+ * href="http://www.w3.org/TR/rdf11-concepts/#dfn-lexical-form">RDF-1.1
+ * Literal lexical form</a>
+ */
+ String getLexicalForm();
+
+ /**
+ * The IRI identifying the datatype that determines how the lexical form
+ * maps to a literal value.
+ *
+ * @return The datatype IRI for this literal.
+ * @see <a
+ * href="http://www.w3.org/TR/rdf11-concepts/#dfn-datatype-iri">RDF-1.1
+ * Literal datatype IRI</a>
+ */
+ Iri getDataType();
+
+ /**
+ * If and only if the datatype IRI is <a
+ * href="http://www.w3.org/1999/02/22-rdf-syntax-ns#langString"
+ * >http://www.w3.org/1999/02/22-rdf-syntax-ns#langString</a>, the language
+ * tag for this Literal is a language tag as defined by <a
+ * href="http://tools.ietf.org/html/bcp47">BCP47</a>.<br>
+ * If the datatype IRI is not <a
+ * href="http://www.w3.org/1999/02/22-rdf-syntax-ns#langString"
+ * >http://www.w3.org/1999/02/22-rdf-syntax-ns#langString</a>, this method
+ * must null.
+ *
+ * @return The language tag of the literal or null if no language tag is defined
+ * @see <a
+ * href="http://www.w3.org/TR/rdf11-concepts/#dfn-language-tag">RDF-1.1
+ * Literal language tag</a>
+ */
+ public Language getLanguage();
+
+ /**
+ * Returns true if <code>obj</code> is an instance of
+ * <code>literal</code> that is term-equal with this, false otherwise
+ *
+ * Two literals are term-equal (the same RDF literal) if and only if the
+ * two lexical forms, the two datatype IRIs, and the two language tags (if
+ * any) compare equal, character by character.
+ *
+ * @return true if obj equals this, false otherwise.
+ */
+ public boolean equals(Object obj);
+
+ /**
+ * Returns the hash code of the lexical form plus the hash code of the
+ * datatype plus if the literal has a language the hash code of the
+ * language.
+ *
+ * @return hash code
+ */
+ public int hashCode();
+}
diff --git a/api/src/main/java/org/apache/commons/rdf/RdfTerm.java b/api/src/main/java/org/apache/commons/rdf/RdfTerm.java
new file mode 100644
index 0000000..8f0fb40
--- /dev/null
+++ b/api/src/main/java/org/apache/commons/rdf/RdfTerm.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf;
+
+/**
+ * An <a href= "http://www.w3.org/TR/rdf11-concepts/#dfn-rdf-term" >RDF-1.1
+ * Term</a>, as defined by <a href= "http://www.w3.org/TR/rdf11-concepts/"
+ * >RDF-1.1 Concepts and Abstract Syntax</a>, a W3C Recommendation published on
+ * 25 February 2014.<br>
+ *
+ * @see <a href= "http://www.w3.org/TR/rdf11-concepts/#dfn-rdf-term" >RDF-1.1
+ * Term</a>
+ */
+public interface RdfTerm {
+
+}
diff --git a/api/src/main/java/org/apache/commons/rdf/Triple.java b/api/src/main/java/org/apache/commons/rdf/Triple.java
new file mode 100644
index 0000000..2a1569e
--- /dev/null
+++ b/api/src/main/java/org/apache/commons/rdf/Triple.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf;
+
+/**
+ * A structure containing a subject, a predicate, and an object.
+ * Also known as a statement.
+ *
+ * @author reto
+ */
+public interface Triple {
+
+ BlankNodeOrIri getSubject();
+
+ Iri getPredicate();
+
+ RdfTerm getObject();
+
+ /**
+ *
+ * @param obj
+ * @return true iff subject, predicate, and object of both triples are equal
+ */
+ @Override
+ boolean equals(Object obj);
+
+ /**
+ * The hash code is computed as follow
+ * (subject.hashCode() >> 1) ^ predicate.hashCode() ^ object.hashCode() << 1)
+ *
+ * Note that the hash returned is computed including the hash of BNodes, so
+ * it is not blank-node blind as in Graph.
+ *
+ * This would have to change if triple should extend Graph
+ *
+ * @return hash code
+ */
+ @Override
+ int hashCode();
+
+}
diff --git a/api/src/main/java/org/apache/commons/rdf/WatchableGraph.java b/api/src/main/java/org/apache/commons/rdf/WatchableGraph.java
new file mode 100644
index 0000000..6367333
--- /dev/null
+++ b/api/src/main/java/org/apache/commons/rdf/WatchableGraph.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.concurrent.locks.ReadWriteLock;
+import org.apache.commons.rdf.event.FilterTriple;
+import org.apache.commons.rdf.event.GraphListener;
+
+
+/**
+ * An extension to the Graph interface that allows to add throws events
+ * on modifications.
+ *
+ * @author reto
+ */
+public interface WatchableGraph extends Graph {
+
+
+ /**
+ * Adds the specified <code>GraphListener</code> to the graph. This listener
+ * will be notified, when the graph is modified and the <code>Triple</code>
+ * that was part of the modifiaction matched the specified
+ * <code>FilterTriple</code>. The notification will be passed to the
+ * listener after the specified delay time (in milli-seconds) has passed.
+ * If more matching events occur during the delay period, then they are
+ * passed all together at the end of the delay period. If the the listener
+ * unregisters or the platform is stopped within the period then the already
+ * occurred events may not be delivered.
+ *
+ * All implementations support this method, immutable implementations will
+ * typically provide an empty implementation, they shall not throw an
+ * exception.
+ *
+ * Implementation of which the triples change over time without add- and
+ * remove-methods being called (e.g. implementation dynamically generating
+ * their triples on invocation of the filer-method) may choose not to, or
+ * only partially propagate their changes to the listener. They should
+ * describe the behavior in the documentation of the class.
+ *
+ * Implementations should keep weak references the listeners, so that the
+ * listener can be garbage collected if its no longer referenced by another
+ * object.
+ *
+ * If delay is 0 notification will happen synchroneously.
+ *
+ * @param listener The listener that will be notified
+ * @param filter The triple filter with which triples are tested,
+ * that were part of the modification.
+ * @param delay The time period afer which the listener will be notified in milliseconds.
+ */
+ public void addGraphListener(GraphListener listener, FilterTriple filter,
+ long delay);
+
+ /**
+ * Adds the specified <code>GraphListener</code> to the graph. This listener
+ * will be notified, when the graph is modified and the <code>Triple</code>
+ * that was part of the modifiaction matched the specified
+ * <code>FilterTriple</code>. The notification will be passed without delay.
+ *
+ * Same as <code>addGraphListener(listener, filter, 0).
+ *
+ * @param listener The listener that will be notified
+ * @param filter The triple filter with which triples are tested,
+ * that were part of the modification.
+ */
+ public void addGraphListener(GraphListener listener, FilterTriple filter);
+
+ /**
+ * Removes the specified <code>GraphListener</code> from the graph. This
+ * listener will no longer be notified, when the graph is modified.
+ *
+ * @param listener The listener to be removed.
+ */
+ public void removeGraphListener(GraphListener listener);
+
+}
diff --git a/api/src/main/java/org/apache/commons/rdf/event/AddEvent.java b/api/src/main/java/org/apache/commons/rdf/event/AddEvent.java
new file mode 100644
index 0000000..1d4a835
--- /dev/null
+++ b/api/src/main/java/org/apache/commons/rdf/event/AddEvent.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf.event;
+
+import org.apache.commons.rdf.Triple;
+import org.apache.commons.rdf.Graph;
+
+/**
+ * This class represent a addition event that occured on a
+ * <code>TripleCollection</code>.
+ *
+ * @author rbn
+ */
+public class AddEvent extends GraphEvent {
+
+
+ public AddEvent(Graph graph, Triple triple) {
+ super(graph, triple);
+ }
+
+}
diff --git a/api/src/main/java/org/apache/commons/rdf/event/FilterTriple.java b/api/src/main/java/org/apache/commons/rdf/event/FilterTriple.java
new file mode 100644
index 0000000..3480c13
--- /dev/null
+++ b/api/src/main/java/org/apache/commons/rdf/event/FilterTriple.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf.event;
+
+import org.apache.commons.rdf.BlankNodeOrIri;
+import org.apache.commons.rdf.RdfTerm;
+import org.apache.commons.rdf.Triple;
+import org.apache.commons.rdf.Iri;
+
+/**
+ * The <code>FilterTriple</code> class provides a match()-method that tests
+ * if a <code>Triple</code> match a certain triple pattern.
+ *
+ * @author mir
+ */
+public class FilterTriple {
+
+ private BlankNodeOrIri subject;
+ private Iri predicate;
+ private RdfTerm object;
+
+ /**
+ * Creates a new <code>FilterTriple</code>. The specified subject,
+ * predicate and object are used to test a given <code>Triple</code>. Any
+ * of these values can be null, which acts as wildcard in the test.
+ *
+ * @param subject the subject.
+ * @param predicate the predicate.
+ * @param object the object.
+ */
+ public FilterTriple (BlankNodeOrIri subject, Iri predicate, RdfTerm object) {
+ this.subject = subject;
+ this.predicate = predicate;
+ this.object = object;
+ }
+
+ /**
+ * Returns true if the subject, predicate and object of the specified
+ * <code>Triple</code> match the subject, predicate and object of this
+ * <code>FilterTriple</code>. Null values in the <code>FilterTriple</code>
+ * act as wildcards.
+ * @param triple
+ * @return
+ */
+ public boolean match(Triple triple) {
+ boolean subjectMatch, predicateMatch, objectMatch;
+ if (this.subject == null) {
+ subjectMatch = true;
+ } else {
+ subjectMatch = this.subject.equals(triple.getSubject());
+ }
+ if (this.predicate == null) {
+ predicateMatch = true;
+ } else {
+ predicateMatch = this.predicate.equals(triple.getPredicate());
+ }
+ if (this.object == null) {
+ objectMatch = true;
+ } else {
+ objectMatch = this.object.equals(triple.getObject());
+ }
+ return subjectMatch && predicateMatch && objectMatch;
+ }
+
+ @Override
+ public String toString() {
+ return "FilterTriples: "+subject+" "+predicate+" "+object;
+ }
+
+}
diff --git a/api/src/main/java/org/apache/commons/rdf/event/GraphEvent.java b/api/src/main/java/org/apache/commons/rdf/event/GraphEvent.java
new file mode 100644
index 0000000..d055088
--- /dev/null
+++ b/api/src/main/java/org/apache/commons/rdf/event/GraphEvent.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf.event;
+
+import org.apache.commons.rdf.Triple;
+import org.apache.commons.rdf.Graph;
+
+/**
+ * This class represent a modification event that occured on a
+ * <code>TripleCollection</code>. A <code>GraphEvent</code> object keeps
+ * information about this event. These information are: The <code>Triple</code>
+ * that was part of the modification, the type of modification (addition or
+ * removal) and the <code>TripleCollection</code> that was modified.
+ *
+ * @author mir
+ */
+public class GraphEvent {
+
+ private Graph graph;
+ private Triple triple;
+
+ protected GraphEvent(Graph graph, Triple triple) {
+ this.graph = graph;
+ this.triple = triple;
+ }
+
+ /**
+ * Returns the <code>TripleCollection</code> that was modified in the event.
+ * @return the graph
+ */
+ public Graph getGraph() {
+ return graph;
+ }
+
+
+ /**
+ * Return the <code>Triple</code> that was part of the modification.
+ * @return the triple
+ */
+ public Triple getTriple() {
+ return triple;
+ }
+}
diff --git a/api/src/main/java/org/apache/commons/rdf/event/GraphListener.java b/api/src/main/java/org/apache/commons/rdf/event/GraphListener.java
new file mode 100644
index 0000000..8d0b257
--- /dev/null
+++ b/api/src/main/java/org/apache/commons/rdf/event/GraphListener.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf.event;
+
+import java.util.List;
+
+/**
+ * A class that is interested in graph events implements this interface and
+ * is then added as listener to a <code>ListenableTripleCollection</code> or
+ * one of its subclasses. When the <code>ListenableTripleCollection</code> is
+ * modified, then the <code>GraphListener</code> is notified.
+ *
+ * @author mir
+ */
+public interface GraphListener {
+
+ /**
+ * This method is called when a <code>ListenableTripleCollection</code> was
+ * modified, to which this <code>GraphListener</code> was added. A
+ * <code>List</code> containing <code>GraphEvent</code>s are passed as
+ * argument. The list contains all events in which a triple was part of
+ * the modification that matched the <code>FilterTriple</code> which was passed
+ * as argument when the listener was added.
+ * @param events
+ */
+ public void graphChanged(List<GraphEvent> events);
+}
diff --git a/api/src/main/java/org/apache/commons/rdf/event/RemoveEvent.java b/api/src/main/java/org/apache/commons/rdf/event/RemoveEvent.java
new file mode 100644
index 0000000..60150d6
--- /dev/null
+++ b/api/src/main/java/org/apache/commons/rdf/event/RemoveEvent.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf.event;
+
+import org.apache.commons.rdf.Triple;
+import org.apache.commons.rdf.Graph;
+
+/**
+ * This class represent a removal event that occured on a
+ * <code>TripleCollection</code>.
+ *
+ * @author rbn
+ */
+public class RemoveEvent extends GraphEvent {
+
+
+ public RemoveEvent(Graph graph, Triple triple) {
+ super(graph, triple);
+ }
+
+}
diff --git a/api/src/main/java/org/apache/commons/rdf/package-info.java b/api/src/main/java/org/apache/commons/rdf/package-info.java
new file mode 100644
index 0000000..da34f2d
--- /dev/null
+++ b/api/src/main/java/org/apache/commons/rdf/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+/**
+ * Common RDF API
+ */
+package org.apache.commons.rdf;
\ No newline at end of file
diff --git a/api/src/site/custom/project-info-report.properties b/api/src/site/custom/project-info-report.properties
new file mode 100644
index 0000000..ec62c64
--- /dev/null
+++ b/api/src/site/custom/project-info-report.properties
@@ -0,0 +1,24 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+
+# Replace SCM report description in index page
+report.scm.description=This document lists ways to access the online source repository.
+
+# Replace SCM report text for viewvc section
+report.scm.webaccess.title=Browser (HTTP) Access
+report.scm.webaccess.url=The following is a link to a browsable version of the source repository. \
+Please use the "Anonymous Access" or "Developer Access" URL if you want to check out the source using your SCM client.
\ No newline at end of file
diff --git a/api/src/site/resources/download_net.cgi b/api/src/site/resources/download_net.cgi
new file mode 100644
index 0000000..495cde1
--- /dev/null
+++ b/api/src/site/resources/download_net.cgi
@@ -0,0 +1,4 @@
+#!/bin/sh
+# Just call the standard mirrors.cgi script. It will use download.html
+# as the input template.
+exec /www/www.apache.org/dyn/mirrors/mirrors.cgi $*
\ No newline at end of file
diff --git a/api/src/site/site.xml b/api/src/site/site.xml
new file mode 100644
index 0000000..6a45085
--- /dev/null
+++ b/api/src/site/site.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+-->
+<project name="Apache Commons Net">
+
+ <bannerRight>
+ <name>Apache Commons Net</name>
+ <src>/images/net-logo-white.png</src>
+ <href>/index.html</href>
+ <alt>Commons Net&trade; logo</alt>
+ </bannerRight>
+
+ <body>
+ <menu name="Documentation">
+ <item name="Overview" href="index.html"/>
+ </menu>
+ <menu name="Development">
+ <item name="Coding Specifications" href="code-standards.html"/>
+ <item name="SVN repository" href="source-repository.html"/>
+ </menu>
+
+ </body>
+
+</project>
diff --git a/api/src/site/xdoc/code-standards.xml b/api/src/site/xdoc/code-standards.xml
new file mode 100644
index 0000000..6cc29a3
--- /dev/null
+++ b/api/src/site/xdoc/code-standards.xml
@@ -0,0 +1,187 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+-->
+
+<document>
+
+ <properties>
+ <title>Coding Standards</title>
+ <author email="jon@latchkey.com">Jon S. Stevens</author>
+ <author email="jvanzyl@apache.org">Jason van Zyl</author>
+ </properties>
+
+<body>
+
+<section name="Coding Standards">
+
+<p>
+This document describes a list of coding conventions that are required
+for code submissions to the project. By default, the coding conventions
+for most Open Source Projects should follow the existing coding conventions
+in the code that you are working on. For example, if the bracket is on
+the same line as the if statement, then you should write all your code
+to have that convention.
+</p>
+
+<p>
+<strong>If you commit code that does not follow these conventions, you
+are responsible for also fixing your own code.</strong>
+</p>
+
+<p>
+Below is a list of coding conventions that are specific to Apache Commons Net
+everything else not specificially mentioned here should follow the official
+<a href="http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html">Sun
+Java Coding Conventions</a>.
+</p>
+
+<p>
+1. Brackets should begin and end on a new line and should exist even
+for one line statements. Examples:
+</p>
+
+<source test=""><![CDATA[
+if ( foo )
+{
+ // code here
+}
+
+try
+{
+ // code here
+}
+catch (Exception bar)
+{
+ // code here
+}
+finally
+{
+ // code here
+}
+
+while ( true )
+{
+ // code here
+}
+]]></source>
+
+<p>
+2. Though it's considered okay to include spaces inside parens, the
+preference is to not include them. Both of the following are okay:
+</p>
+
+<source test=""><![CDATA[
+if (foo)
+
+or
+
+if ( foo )
+]]></source>
+
+<p>
+3. 4 space indent. <strong>NO tabs</strong>. Period. We understand
+that many developers like to use tabs, but the fact of the matter is
+that in a distributed development environment where diffs are sent to
+the mailing lists by both developers and the version control system
+(which sends commit log messages), the use tabs makes it impossible to
+preserve legibility.
+</p>
+
+<p>
+In Emacs-speak, this translates to the following command:
+</p>
+
+<source><![CDATA[
+(setq-default tab-width 4 indent-tabs-mode nil)
+]]></source>
+
+<p>
+4. Native linefeeds (svn:eol-style native) for all .java source code and text files.
+Platform specific files should have the platform specific linefeeds.
+</p>
+
+<p>
+5. JavaDoc <strong>MUST</strong> exist on all public and protected methods.
+JavaDoc on private and default access methods and members is preferred and
+encouraged. If your code modifications use an existing class/method/variable
+which lacks JavaDoc, it is required that you add it. This will improve the
+project as a whole.
+</p>
+
+<p>
+6. The Apache License header <strong>MUST</strong> be placed at the top
+of each and every file.
+</p>
+
+<p>
+9. Import statements must be fully qualified for clarity.
+</p>
+
+<source><![CDATA[
+import java.util.ArrayList;
+import java.util.Hashtable;
+
+import org.apache.foo.Bar;
+import org.apache.bar.Foo;
+]]></source>
+
+<p>
+And not
+</p>
+
+<source><![CDATA[
+import java.util.*;
+import org.apache.foo.*;
+import org.apache.bar.*;
+]]></source>
+
+<hr noshade="true" size="1"/>
+
+<p>
+X/Emacs users might appreciate this in their .emacs file.
+</p>
+
+<source><![CDATA[
+(defun apache-jakarta-mode ()
+ "The Java mode specialization for Apache Jakarta projects."
+ (if (not (assoc "apache-jakarta" c-style-alist))
+ ;; Define the Apache Jakarta cc-mode style.
+ (c-add-style "apache-jakarta" '("java" (indent-tabs-mode . nil))))
+
+ (c-set-style "apache-jakarta")
+ (c-set-offset 'substatement-open 0 nil)
+ (setq mode-name "Apache Jakarta")
+
+ ;; Turn on syntax highlighting when X is running.
+ (if (boundp 'window-system)
+ (progn (setq font-lock-support-mode 'lazy-lock-mode)
+ (font-lock-mode t))))
+
+;; Activate Jakarta mode.
+(if (fboundp 'jde-mode)
+ (add-hook 'jde-mode-hook 'apache-jakarta-mode)
+ (add-hook 'java-mode-hook 'apache-jakarta-mode))
+]]></source>
+
+<p>
+Thanks for your cooperation.
+</p>
+
+</section>
+
+</body>
+</document>
diff --git a/api/src/site/xdoc/index.xml b/api/src/site/xdoc/index.xml
new file mode 100644
index 0000000..7a7a1ec
--- /dev/null
+++ b/api/src/site/xdoc/index.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+-->
+<document>
+
+ <properties>
+ <title>Overview</title>
+ <author email="dev@commons.apache.org">Apache Commons Documentation Team</author>
+ </properties>
+
+ <body>
+
+ <section name="Apache Commons RDF">
+ <p>
+ Apache Commons RDF provides an API modelling the RDF data model as defined by
+ http://www.w3.org/TR/rdf11-concepts/
+ </p>
+ </section>
+ <section name="Features">
+ <p>
+ This Library shall
+ <ul>
+ <li>Allow to access, modify nad monitor RDF data</li>
+ <li>Support all concepts defined by the RDF Abstract Syntax</li>
+ <li>Provide an easy to use API</li>
+ <li>Support both triple stores as well as the wrapping other sources</li>
+ <li>Allow to seamlessly use instances coming from different sources</li>
+ <li>Integrate well with existing Java APIs</li>
+ </ul>
+ </p>
+ </section>
+
+</document>
+
diff --git a/doap_rdf.rdf b/doap_rdf.rdf
new file mode 100644
index 0000000..a7a5e17
--- /dev/null
+++ b/doap_rdf.rdf
@@ -0,0 +1,40 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+-->
+<rdf:RDF xmlns="http://usefulinc.com/ns/doap#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:asfext="http://projects.apache.org/ns/asfext#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:doap="http://usefulinc.com/ns/doap#" xml:lang="en">
+ <Project rdf:about="http://commons.apache.org/rdf/">
+ <name>Apache Commons RDF</name>
+ <homepage rdf:resource="http://commons.apache.org/rdf/"/>
+ <programming-language>Java</programming-language>
+ <category rdf:resource="http://projects.apache.org/category/library"/>
+ <license rdf:resource="http://usefulinc.com/doap/licenses/asl20"/>
+ <bug-database rdf:resource="https://issues.apache.org/jira/browse/RDF"/>
+ <download-page rdf:resource="http://commons.apache.org/rdf/download_net.cgi"/>
+ <asfext:pmc rdf:resource="http://commons.apache.org/"/>
+ <shortdesc xml:lang="en">Apache Commons Rdf</shortdesc>
+ <description xml:lang="en"/>
+ <repository>
+ <SVNRepository>
+ <browse rdf:resource="http://svn.apache.org/repos/asf/commons/proper/rdf/trunk"/>
+ <location rdf:resource="http://svn.apache.org/repos/asf/commons/proper/rdf"/>
+ </SVNRepository>
+ </repository>
+ <release>
+ </release>
+ <mailing-list rdf:resource="http://commons.apache.org/mail-lists.html"/>
+ </Project>
+</rdf:RDF>
diff --git a/impl.sparql/pom.xml b/impl.sparql/pom.xml
new file mode 100644
index 0000000..8fe7681
--- /dev/null
+++ b/impl.sparql/pom.xml
@@ -0,0 +1,53 @@
+<?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">
+ <parent>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-parent</artifactId>
+ <version>37</version>
+ <relativePath />
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>commons-rdf</groupId>
+ <artifactId>commons-rdf-impl-sparql</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <packaging>jar</packaging>
+ <name>Apache Commons RDF SPARQL backed implementation.</name>
+ <description>An implementation of the rdf commons API backed by a sparql
+ endpoint. STATUS: Incomplete, currecnt code only supports reading
+ graphs and does not yet support BlankNodes.</description>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <commons.encoding>UTF-8</commons.encoding>
+ <maven.compiler.source>1.7</maven.compiler.source>
+ <maven.compiler.target>1.7</maven.compiler.target>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ <version>4.4</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-rdf</groupId>
+ <artifactId>commons-rdf-api</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-rdf</groupId>
+ <artifactId>commons-rdf-impl-utils</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jena</groupId>
+ <artifactId>jena-fuseki</artifactId>
+ <version>1.1.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
diff --git a/impl.sparql/src/main/java/org/apache/commons/rdf/impl/sparql/SparqlBNode.java b/impl.sparql/src/main/java/org/apache/commons/rdf/impl/sparql/SparqlBNode.java
new file mode 100644
index 0000000..c74aa06
--- /dev/null
+++ b/impl.sparql/src/main/java/org/apache/commons/rdf/impl/sparql/SparqlBNode.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2015 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.rdf.impl.sparql;
+
+import java.util.Collection;
+import java.util.Objects;
+import org.apache.commons.rdf.BlankNode;
+import org.apache.commons.rdf.BlankNodeOrIri;
+import org.apache.commons.rdf.ImmutableGraph;
+import org.apache.commons.rdf.Iri;
+import org.apache.commons.rdf.RdfTerm;
+import org.apache.commons.rdf.Triple;
+import org.apache.commons.rdf.impl.utils.TripleImpl;
+import org.apache.commons.rdf.impl.utils.simple.SimpleGraph;
+
+/**
+ *
+ * @author developer
+ */
+class SparqlBNode extends BlankNode {
+
+ private final static Iri internalBNodeId = new Iri("urn:x-internalid:fdmpoihdfw");
+
+ final ImmutableGraph context;
+ private final int isoDistinguisher;
+
+ SparqlBNode(BlankNode node, Collection<Triple> context, int isoDistinguisher) {
+ this.isoDistinguisher = isoDistinguisher;
+ final SimpleGraph contextBuider = new SimpleGraph();
+ for (Triple triple : context) {
+ BlankNodeOrIri subject = triple.getSubject();
+ RdfTerm object = triple.getObject();
+ contextBuider.add(new TripleImpl(subject.equals(node) ? internalBNodeId : subject,
+ triple.getPredicate(),
+ object.equals(node) ? internalBNodeId : object));
+ }
+ this.context = contextBuider.getImmutableGraph();
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 7+isoDistinguisher;
+ hash = 61 * hash + Objects.hashCode(this.context);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final SparqlBNode other = (SparqlBNode) obj;
+ if (isoDistinguisher != other.isoDistinguisher) {
+ return false;
+ }
+ return Objects.equals(this.context, other.context);
+ }
+}
diff --git a/impl.sparql/src/main/java/org/apache/commons/rdf/impl/sparql/SparqlClient.java b/impl.sparql/src/main/java/org/apache/commons/rdf/impl/sparql/SparqlClient.java
new file mode 100644
index 0000000..ca3f619
--- /dev/null
+++ b/impl.sparql/src/main/java/org/apache/commons/rdf/impl/sparql/SparqlClient.java
@@ -0,0 +1,222 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.apache.commons.rdf.impl.sparql;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.apache.http.HttpEntity;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+import javax.xml.parsers.*;
+import org.apache.commons.rdf.BlankNode;
+import org.apache.commons.rdf.BlankNodeOrIri;
+import org.apache.commons.rdf.Iri;
+import org.apache.commons.rdf.Language;
+import org.apache.commons.rdf.Literal;
+import org.apache.commons.rdf.RdfTerm;
+import org.apache.commons.rdf.Triple;
+import org.apache.commons.rdf.impl.utils.AbstractLiteral;
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+
+/**
+ *
+ * @author developer
+ */
+public class SparqlClient {
+
+ final String endpoint;
+
+ public SparqlClient(final String endpoint) {
+ this.endpoint = endpoint;
+ }
+
+ List<Map<String, RdfTerm>> queryResultSet(final String query) throws IOException {
+ CloseableHttpClient httpclient = HttpClients.createDefault();
+ HttpPost httpPost = new HttpPost(endpoint);
+ List<NameValuePair> nvps = new ArrayList<NameValuePair>();
+ nvps.add(new BasicNameValuePair("query", query));
+ httpPost.setEntity(new UrlEncodedFormEntity(nvps));
+ CloseableHttpResponse response2 = httpclient.execute(httpPost);
+
+ try {
+ HttpEntity entity2 = response2.getEntity();
+ InputStream in = entity2.getContent();
+ SAXParserFactory spf = SAXParserFactory.newInstance();
+ spf.setNamespaceAware(true);
+ SAXParser saxParser = spf.newSAXParser();
+ XMLReader xmlReader = saxParser.getXMLReader();
+ final SparqlsResultsHandler sparqlsResultsHandler = new SparqlsResultsHandler();
+ xmlReader.setContentHandler(sparqlsResultsHandler);
+ xmlReader.parse(new InputSource(in));
+ /*
+ for (int ch = in.read(); ch != -1; ch = in.read()) {
+ System.out.print((char)ch);
+ }
+ */
+ // do something useful with the response body
+ // and ensure it is fully consumed
+ EntityUtils.consume(entity2);
+ return sparqlsResultsHandler.getResults();
+ } catch (ParserConfigurationException ex) {
+ throw new RuntimeException(ex);
+ } catch (SAXException ex) {
+ throw new RuntimeException(ex);
+ } finally {
+ response2.close();
+ }
+
+ }
+
+ final public static class SparqlsResultsHandler extends DefaultHandler {
+
+ private String currentBindingName;
+ private Map<String, RdfTerm> currentResult = null;
+ private final List<Map<String, RdfTerm>> results = new ArrayList<>();
+ private boolean readingValue;
+ private String lang; //the xml:lang attribute of a literal
+ private String value;
+ private Map<String, BlankNode> bNodeMap = new HashMap<>();
+ private static final Iri XSD_STRING = new Iri("http://www.w3.org/2001/XMLSchema#string");
+
+ private RdfTerm getBNode(String value) {
+ if (!bNodeMap.containsKey(value)) {
+ bNodeMap.put(value, new BlankNode());
+ }
+ return bNodeMap.get(value);
+ }
+
+ private List<Map<String, RdfTerm>> getResults() {
+ return results;
+ }
+
+ enum BindingType {
+
+ uri, bnode, literal;
+ }
+
+ @Override
+ public void startDocument() throws SAXException {
+
+ }
+
+ @Override
+ public void startElement(String namespaceURI,
+ String localName,
+ String qName,
+ Attributes atts)
+ throws SAXException {
+ if ("http://www.w3.org/2005/sparql-results#".equals(namespaceURI)) {
+ if ("result".equals(localName)) {
+ if (currentResult != null) {
+ throw new SAXException("unexpected tag <result>");
+ }
+ currentResult = new HashMap<>();
+ } else if ("binding".equals(localName)) {
+ if (currentResult == null) {
+ throw new SAXException("unexpected tag <binding>");
+ }
+ currentBindingName = atts.getValue("name");
+ } else if ("uri".equals(localName) || "bnode".equals(localName) || "literal".equals(localName)) {
+ if (readingValue) {
+ throw new SAXException("unexpected tag <" + localName + ">");
+ }
+ lang = atts.getValue("http://www.w3.org/XML/1998/namespace", "lang");
+ readingValue = true;
+ }
+ }
+
+ //System.out.println(namespaceURI);
+ //System.out.println(qName);
+ }
+
+ @Override
+ public void characters(char[] chars, int start, int length) throws SAXException {
+ if (readingValue) {
+ value = new String(chars, start, length);
+ //System.err.println(value + start + ", " + length);
+ }
+ }
+
+ @Override
+ public void endElement(String namespaceURI,
+ String localName,
+ String qName)
+ throws SAXException {
+ if ("http://www.w3.org/2005/sparql-results#".equals(namespaceURI)) {
+ if ("result".equals(localName)) {
+ results.add(currentResult);
+ currentResult = null;
+ } else if ("binding".equals(localName)) {
+ if (currentBindingName == null) {
+ throw new SAXException("unexpected tag </binding>");
+ }
+ currentBindingName = null;
+ } else {
+ try {
+ BindingType b = BindingType.valueOf(localName);
+ RdfTerm rdfTerm = null;
+ final Language language = lang == null? null : new Language(lang);;
+ switch (b) {
+ case uri:
+ rdfTerm = new Iri(value);
+ break;
+ case bnode:
+ rdfTerm = getBNode(value);
+ break;
+ case literal:
+ final String lf = value;
+ rdfTerm = new AbstractLiteral() {
+
+ @Override
+ public String getLexicalForm() {
+ return lf;
+ }
+
+ @Override
+ public Iri getDataType() {
+ //TODO implement
+ return XSD_STRING;
+ }
+
+ @Override
+ public Language getLanguage() {
+ return language;
+ }
+ };
+ break;
+ }
+ currentResult.put(currentBindingName, rdfTerm);
+ readingValue = false;
+ } catch (IllegalArgumentException e) {
+ //not uri|bnode|literal
+ }
+ }
+ }
+ }
+
+ public void endDocument() throws SAXException {
+ //System.out.println("results: " + results.size());
+ }
+
+ }
+
+}
diff --git a/impl.sparql/src/main/java/org/apache/commons/rdf/impl/sparql/SparqlGraph.java b/impl.sparql/src/main/java/org/apache/commons/rdf/impl/sparql/SparqlGraph.java
new file mode 100644
index 0000000..64b6133
--- /dev/null
+++ b/impl.sparql/src/main/java/org/apache/commons/rdf/impl/sparql/SparqlGraph.java
@@ -0,0 +1,439 @@
+/*
+ * Copyright 2015 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.rdf.impl.sparql;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.apache.commons.rdf.BlankNode;
+import org.apache.commons.rdf.BlankNodeOrIri;
+import org.apache.commons.rdf.Iri;
+import org.apache.commons.rdf.Literal;
+import org.apache.commons.rdf.RdfTerm;
+import org.apache.commons.rdf.Triple;
+import org.apache.commons.rdf.impl.utils.AbstractGraph;
+import org.apache.commons.rdf.impl.utils.TripleImpl;
+
+/**
+ *
+ * @author reto
+ */
+public class SparqlGraph extends AbstractGraph {
+
+ private static final int MAX_ISOMORPHIC_BNODES = 1000;
+ private static final Logger log = Logger.getLogger(SparqlGraph.class.getName());
+
+ final SparqlClient sparqlClient;
+
+ /**
+ * Constructs a Graph representing the default graph at the specified
+ * endpoint
+ */
+ public SparqlGraph(final String endpoint) {
+ sparqlClient = new SparqlClient(endpoint);
+ }
+
+ @Override
+ protected Iterator<Triple> performFilter(final BlankNodeOrIri filterSubject,
+ final Iri filterPredicate, final RdfTerm filterObject) {
+ try {
+ final StringBuilder queryBuilder = new StringBuilder();
+ queryBuilder.append("SELECT ?s ?p ?o WHERE { ");
+ if (filterSubject == null) {
+ queryBuilder.append("?s");
+ } else {
+ queryBuilder.append(asSparqlTerm(filterSubject));
+ }
+ queryBuilder.append(' ');
+ if (filterPredicate == null) {
+ queryBuilder.append("?p");
+ } else {
+ queryBuilder.append(asSparqlTerm(filterPredicate));
+ }
+ queryBuilder.append(' ');
+ if (filterObject == null) {
+ queryBuilder.append("?o");
+ } else {
+ queryBuilder.append(asSparqlTerm(filterObject));
+ }
+ queryBuilder.append(" }");
+ final List<Map<String, RdfTerm>> sparqlResults = sparqlClient.queryResultSet(queryBuilder.toString());
+ //first to triples without bnode-conversion
+ //rawTripkles contains the triples with the BNodes from the result set
+ final Collection<Triple> rawTriples = new ArrayList<>();
+ for (Map<String, RdfTerm> result : sparqlResults) {
+ rawTriples.add(new TripleImpl(filterSubject != null ? filterSubject : (BlankNodeOrIri) result.get("s"),
+ filterPredicate != null ? filterPredicate : (Iri) result.get("p"),
+ filterObject != null ? filterObject : result.get("o")));
+
+ }
+ //then bnode conversion
+ final Iterator<Triple> rawTriplesIter = rawTriples.iterator();
+ //this is basically just wokring around the lack of (named) nested functions
+ return (new Callable<Iterator<Triple>>() {
+
+ final Map<BlankNode, SparqlBNode> nodeMap = new HashMap<>();
+
+ private RdfTerm useSparqlNode(RdfTerm node) throws IOException {
+ if (node instanceof BlankNodeOrIri) {
+ return useSparqlNode((BlankNodeOrIri) node);
+ }
+ return node;
+ }
+
+ private BlankNodeOrIri useSparqlNode(BlankNodeOrIri node) throws IOException {
+ if (node instanceof BlankNode) {
+ if (!nodeMap.containsKey(node)) {
+ createBlankNodesForcontext((BlankNode) node);
+ }
+ if (!nodeMap.containsKey(node)) {
+ throw new RuntimeException("no Bnode created");
+ }
+ return nodeMap.get(node);
+ } else {
+ return node;
+ }
+ }
+
+ private void createBlankNodesForcontext(final BlankNode node) throws IOException {
+ final Collection<Triple> context = getContext(node);
+ final Set<BlankNode> rawNodes = new HashSet<>();
+ for (Triple triple : context) {
+ {
+ final BlankNodeOrIri subject = triple.getSubject();
+ if (subject instanceof BlankNode) {
+ rawNodes.add((BlankNode) subject);
+ }
+ }
+ {
+ final RdfTerm object = triple.getObject();
+ if (object instanceof BlankNode) {
+ rawNodes.add((BlankNode) object);
+ }
+ }
+ }
+ final Set<SparqlBNode> createdSparqlNodes = new HashSet<>();
+ //final Map<BlankNode, SparqlBNode> preliminaryNodes = new HashMap<>();
+ for (BlankNode rawNode : rawNodes) {
+ for (int i = 0; i < MAX_ISOMORPHIC_BNODES; i++) {
+ SparqlBNode sparqlBNode = new SparqlBNode(rawNode, context, i);
+ if (!createdSparqlNodes.contains(sparqlBNode)) {
+ nodeMap.put(rawNode, sparqlBNode);
+ createdSparqlNodes.add(sparqlBNode);
+ break;
+ }
+ }
+ }
+ }
+
+ private Collection<Triple> getContext(final BlankNode node) throws IOException {
+ //we need to get the cntext of the BNode
+ //if the filter was for (null, null, null) we have the whole
+ //bnode context in the reuslt set, otherwise we need to get
+ //more triples from the endpoint,
+ //let's first handle the easy case
+ if ((filterSubject == null) && (filterPredicate == null)
+ && (filterObject == null)) {
+ return getContextInRaw(node);
+ } else {
+ final Collection<Triple> startContext = getContextInRaw(node);
+ final Set<Collection<Triple>> expandedContexts = expandContext(startContext);
+ //expand bnode context
+ //note that there might be different contexts for
+ //a bnode as present in the current result set
+ //in this case we just haveto make sure we don't
+ //pick the same context for different bnodes in the resultset
+
+ //TODO make sure we don't take one that has already been used
+ return expandedContexts.iterator().next();
+ }
+
+ }
+
+ private Collection<Triple> getContextInRaw(BlankNode node) {
+ final Collection<Triple> context = new ArrayList<>();
+ for (Triple rawTriple : rawTriples) {
+ BlankNodeOrIri rawSubject = rawTriple.getSubject();
+ RdfTerm rawObject = rawTriple.getObject();
+ if (rawSubject.equals(node) || rawObject.equals(node)) {
+ context.add(rawTriple);
+ }
+ }
+ return context;
+ }
+
+ @Override
+ public Iterator<Triple> call() throws Exception {
+ return new Iterator<Triple>() {
+
+ @Override
+ public boolean hasNext() {
+ return rawTriplesIter.hasNext();
+ }
+
+ @Override
+ public Triple next() {
+ try {
+ Triple rawTriple = rawTriplesIter.next();
+ return new TripleImpl(useSparqlNode(rawTriple.getSubject()),
+ rawTriple.getPredicate(),
+ useSparqlNode(rawTriple.getObject()));
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ };
+ }
+
+ /**
+ * returns all MSGs that are supergraphs of startContext
+ *
+ * @param startContext
+ * @return
+ */
+ private Set<Collection<Triple>> expandContext(Collection<Triple> startContext) throws IOException {
+ final Collection<String> triplePatterns = new ArrayList<>();
+ int varCounter = 0;
+ final Map<BlankNode, String> bNodeVarNameMap = new HashMap<>();
+ for (Triple t : startContext) {
+ final StringBuilder builder = new StringBuilder();
+ {
+ final BlankNodeOrIri s = t.getSubject();
+ String varName;
+ if (s instanceof BlankNode) {
+ if (bNodeVarNameMap.containsKey(s)) {
+ varName = bNodeVarNameMap.get(s);
+ } else {
+ varName = "v" + (varCounter++);
+ bNodeVarNameMap.put((BlankNode) s, varName);
+
+ }
+ builder.append('?');
+ builder.append(varName);
+ } else {
+ builder.append(asSparqlTerm(s));
+ }
+ }
+ builder.append(' ');
+ builder.append(asSparqlTerm(t.getPredicate()));
+ builder.append(' ');
+ {
+ final RdfTerm o = t.getObject();
+ String varName;
+ if (o instanceof BlankNode) {
+ if (bNodeVarNameMap.containsKey(o)) {
+ varName = bNodeVarNameMap.get(o);
+ } else {
+ varName = "v" + (varCounter++);
+ bNodeVarNameMap.put((BlankNode) o, varName);
+ }
+ builder.append('?');
+ builder.append(varName);
+ } else {
+ builder.append(asSparqlTerm(o));
+ }
+ }
+ builder.append('.');
+ triplePatterns.add(builder.toString());
+
+ }
+ final StringBuilder queryBuilder = new StringBuilder();
+ queryBuilder.append("SELECT * WHERE {\n ");
+ for (String triplePattern : triplePatterns) {
+ queryBuilder.append(triplePattern);
+ queryBuilder.append('\n');
+ }
+ Set<BlankNode> bNodesInContext = bNodeVarNameMap.keySet();
+ for (BlankNode bNode : bNodesInContext) {
+ final String bNodeVarLabel = bNodeVarNameMap.get(bNode);
+ //looking for outgoing properties of the bnode
+ queryBuilder.append("OPTIONAL { ");
+ queryBuilder.append('?');
+ queryBuilder.append(bNodeVarLabel);
+ queryBuilder.append(' ');
+ queryBuilder.append("?po");
+ queryBuilder.append(bNodeVarLabel);
+ queryBuilder.append(" ?o");
+ queryBuilder.append(bNodeVarLabel);
+ queryBuilder.append(" } .\n");
+ //looking for incoming properties of the bnode
+ queryBuilder.append("OPTIONAL { ");
+ queryBuilder.append("?s");
+ queryBuilder.append(bNodeVarLabel);
+ queryBuilder.append(' ');
+ queryBuilder.append("?pi");
+ queryBuilder.append(bNodeVarLabel);
+ queryBuilder.append(" ?");
+ queryBuilder.append(bNodeVarLabel);
+ queryBuilder.append(" } .\n");
+ }
+ queryBuilder.append(" }");
+ final List<Map<String, RdfTerm>> expansionQueryResults = sparqlClient.queryResultSet(queryBuilder.toString());
+ Set<Collection<Triple>> expandedContexts = new HashSet<>();
+ //the query results may or may be from disjoint supergraphs
+ //we expand them all as if they are different which may lead
+ //us to the same MSG multiple times
+ RESULTS:
+ for (Map<String, RdfTerm> expansionQueryResult : expansionQueryResults) {
+ Collection<Triple> expandedContext = new HashSet<>();
+ Map<BlankNode, BlankNode> newBNodesToOldBNodes = new HashMap<>();
+ for (BlankNode oldBNode : bNodesInContext) {
+ final String bNodeVarLabel = bNodeVarNameMap.get(oldBNode);
+ final RdfTerm newNode = expansionQueryResult.get(bNodeVarLabel);
+ if (!(newNode instanceof BlankNode)) {
+ //this subgraph is't a match
+ continue RESULTS;
+ }
+ newBNodesToOldBNodes.put((BlankNode) newNode, oldBNode);
+ }
+ expandedContext.addAll(startContext);
+ boolean newBNodeIntroduced = false;
+ boolean newTripleAdded = false;
+ for (BlankNode oldBNode : bNodesInContext) {
+ final String bNodeVarLabel = bNodeVarNameMap.get(oldBNode);
+ {
+ final Iri newPredicate = (Iri) expansionQueryResult.get("po" + bNodeVarLabel);
+ if (newPredicate != null) {
+ RdfTerm newObject = expansionQueryResult.get("o" + bNodeVarLabel);
+ if (newObject instanceof BlankNode) {
+ if (newBNodesToOldBNodes.containsKey(newObject)) {
+ //point back to BNode in startContext
+ newObject = newBNodesToOldBNodes.get(newObject);
+ } else {
+ newBNodeIntroduced = true;
+ }
+ }
+ if (expandedContext.add(new TripleImpl(oldBNode, newPredicate, newObject))) {
+ newTripleAdded = true;
+ }
+ }
+ }
+ {
+ final Iri newPredicate = (Iri) expansionQueryResult.get("pi" + bNodeVarLabel);
+ if (newPredicate != null) {
+ RdfTerm newSubject = expansionQueryResult.get("s" + bNodeVarLabel);
+ if (newSubject instanceof BlankNode) {
+ if (newBNodesToOldBNodes.containsKey(newSubject)) {
+ //point back to BNode in startContext
+ newSubject = newBNodesToOldBNodes.get(newSubject);
+ } else {
+ newBNodeIntroduced = true;
+ }
+ }
+ if (expandedContext.add(new TripleImpl((BlankNodeOrIri) newSubject, newPredicate, oldBNode))) {
+ newTripleAdded = true;
+ }
+ }
+ }
+ }
+ if (newBNodeIntroduced) {
+ //we could be more efficient than this ans just expand the newly introduced bnodes
+ expandedContexts.addAll(expandContext(expandedContext));
+ } else {
+ if (newTripleAdded) {
+ //look for more results
+ expandedContexts.addAll(expandContext(expandedContext));
+ //expandedContexts.add(expandedContext);
+ }
+ }
+
+ }
+ if (expandedContexts.isEmpty()) {
+ expandedContexts.add(startContext);
+ }
+ return expandedContexts;
+ }
+
+ }).call();
+ } catch (AlienBNodeException e) {
+ return new Iterator<Triple>() {
+
+ @Override
+ public boolean hasNext() {
+ return false;
+ }
+
+ @Override
+ public Triple next() {
+ throw new NoSuchElementException();
+ }
+ };
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ @Override
+ protected int performSize() {
+ try {
+ return sparqlClient.queryResultSet("SELECT * WHERE { ?s ?p ?o}").size();
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ private String asSparqlTerm(Iri iri) {
+ return "<" + iri.getUnicodeString() + ">";
+ }
+
+ private String asSparqlTerm(Literal literal) {
+ //TODO langauge and datatype
+ return "\"" + literal.getLexicalForm() + "\"";
+ }
+
+ private String asSparqlTerm(BlankNode bnode) {
+ if (!(bnode instanceof SparqlBNode)) {
+ throw new AlienBNodeException();
+ }
+ //this requires adding additional clauses to the graph pattern
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ private String asSparqlTerm(BlankNodeOrIri term) {
+ if (term instanceof Iri) {
+ return asSparqlTerm((Iri) term);
+ } else {
+ return asSparqlTerm((BlankNode) term);
+ }
+ }
+
+ private String asSparqlTerm(RdfTerm term) {
+ if (term instanceof BlankNodeOrIri) {
+ return asSparqlTerm((BlankNodeOrIri) term);
+ } else {
+ return asSparqlTerm((Literal) term);
+ }
+ }
+
+ private static class AlienBNodeException extends RuntimeException {
+
+ public AlienBNodeException() {
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/BNodeCircleTest.java b/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/BNodeCircleTest.java
new file mode 100644
index 0000000..5208d34
--- /dev/null
+++ b/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/BNodeCircleTest.java
@@ -0,0 +1,101 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.apache.commons.rdf.impl.sparql;
+
+import com.hp.hpl.jena.query.DatasetAccessor;
+import com.hp.hpl.jena.query.DatasetAccessorFactory;
+import java.io.File;
+import java.io.IOException;
+import java.net.ServerSocket;
+import org.apache.jena.fuseki.EmbeddedFusekiServer;
+import com.hp.hpl.jena.rdf.model.Model;
+import com.hp.hpl.jena.rdf.model.ModelFactory;
+import java.io.InputStream;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import org.apache.commons.rdf.BlankNode;
+import org.apache.commons.rdf.BlankNodeOrIri;
+import org.apache.commons.rdf.Graph;
+import org.apache.commons.rdf.Iri;
+import org.apache.commons.rdf.Language;
+import org.apache.commons.rdf.Literal;
+import org.apache.commons.rdf.RdfTerm;
+import org.apache.commons.rdf.Triple;
+import org.apache.commons.rdf.impl.utils.PlainLiteralImpl;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ *
+ * @author reto
+ */
+public class BNodeCircleTest {
+
+ final static int serverPort = findFreePort();
+ static EmbeddedFusekiServer server;
+
+ @BeforeClass
+ public static void prepare() throws IOException {
+ final String serviceURI = "http://localhost:" + serverPort + "/ds/data";
+ final DatasetAccessor accessor = DatasetAccessorFactory.createHTTP(serviceURI);
+ final InputStream in = BNodeCircleTest.class.getResourceAsStream("bnode-circle.ttl");
+ final Model m = ModelFactory.createDefaultModel();
+ String base = "http://example.org/";
+ m.read(in, base, "TURTLE");
+ server = EmbeddedFusekiServer.memTDB(serverPort, "/ds");//dataSet.getAbsolutePath());
+ server.start();
+ System.out.println("Started fuseki on port " + serverPort);
+ accessor.putModel(m);
+ }
+
+ @AfterClass
+ public static void cleanup() {
+ server.stop();
+ }
+
+ @Test
+ public void graphSize() {
+ final Graph graph = new SparqlGraph("http://localhost:" + serverPort + "/ds/query");
+ Assert.assertEquals("Graph not of the exepected size", 2, graph.size());
+ }
+
+
+
+ @Test
+ public void nullFilter() {
+ final Graph graph = new SparqlGraph("http://localhost:" + serverPort + "/ds/query");
+
+ final Iri foafKnows = new Iri("http://xmlns.com/foaf/0.1/knows");
+
+ final Iterator<Triple> iter = graph.filter(null, null, null);
+ Assert.assertTrue(iter.hasNext());
+ final Triple triple1 = iter.next();
+ final BlankNodeOrIri subject = triple1.getSubject();
+ final RdfTerm object = triple1.getObject();
+ Assert.assertTrue(subject instanceof BlankNode);
+ Assert.assertTrue(object instanceof BlankNode);
+ Assert.assertNotEquals(subject, object);
+ Assert.assertTrue(iter.hasNext());
+ }
+
+
+
+
+ public static int findFreePort() {
+ int port = 0;
+ try (ServerSocket server = new ServerSocket(0);) {
+ port = server.getLocalPort();
+ } catch (Exception e) {
+ throw new RuntimeException("unable to find a free port");
+ }
+ return port;
+ }
+
+}
diff --git a/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/BNodeTest.java b/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/BNodeTest.java
new file mode 100644
index 0000000..a376fcd
--- /dev/null
+++ b/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/BNodeTest.java
@@ -0,0 +1,137 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.apache.commons.rdf.impl.sparql;
+
+import com.hp.hpl.jena.query.DatasetAccessor;
+import com.hp.hpl.jena.query.DatasetAccessorFactory;
+import java.io.File;
+import java.io.IOException;
+import java.net.ServerSocket;
+import org.apache.jena.fuseki.EmbeddedFusekiServer;
+import com.hp.hpl.jena.rdf.model.Model;
+import com.hp.hpl.jena.rdf.model.ModelFactory;
+import java.io.InputStream;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import org.apache.commons.rdf.BlankNode;
+import org.apache.commons.rdf.BlankNodeOrIri;
+import org.apache.commons.rdf.Graph;
+import org.apache.commons.rdf.Iri;
+import org.apache.commons.rdf.Language;
+import org.apache.commons.rdf.Literal;
+import org.apache.commons.rdf.RdfTerm;
+import org.apache.commons.rdf.Triple;
+import org.apache.commons.rdf.impl.utils.PlainLiteralImpl;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ *
+ * @author reto
+ */
+public class BNodeTest {
+
+ final static int serverPort = findFreePort();
+ static EmbeddedFusekiServer server;
+
+ @BeforeClass
+ public static void prepare() throws IOException {
+ final String serviceURI = "http://localhost:" + serverPort + "/ds/data";
+ final DatasetAccessor accessor = DatasetAccessorFactory.createHTTP(serviceURI);
+ final InputStream in = BNodeTest.class.getResourceAsStream("simple-bnode.ttl");
+ final Model m = ModelFactory.createDefaultModel();
+ String base = "http://example.org/";
+ m.read(in, base, "TURTLE");
+ server = EmbeddedFusekiServer.memTDB(serverPort, "/ds");//dataSet.getAbsolutePath());
+ server.start();
+ System.out.println("Started fuseki on port " + serverPort);
+ accessor.putModel(m);
+ }
+
+ @AfterClass
+ public static void cleanup() {
+ server.stop();
+ }
+
+ @Test
+ public void graphSize() {
+ final Graph graph = new SparqlGraph("http://localhost:" + serverPort + "/ds/query");
+ Assert.assertEquals("Graph not of the exepected size", 3, graph.size());
+ }
+
+ /* Filtering with a Bode that cannot be in graph
+ */
+ @Test
+ public void filterAlienBNode() {
+ final Graph graph = new SparqlGraph("http://localhost:" + serverPort + "/ds/query");
+
+ final BlankNode blankNode = new BlankNode();
+ final Iterator<Triple> iter = graph.filter(blankNode, null, null);
+ Assert.assertFalse(iter.hasNext());
+ }
+
+ @Test
+ public void bNodeIdentity() {
+ final Graph graph = new SparqlGraph("http://localhost:" + serverPort + "/ds/query");
+
+ final Iri foafPerson = new Iri("http://xmlns.com/foaf/0.1/Person");
+ final Iri foafName = new Iri("http://xmlns.com/foaf/0.1/name");
+ final Iri foafKnows = new Iri("http://xmlns.com/foaf/0.1/knows");
+ final Iri rdfType = new Iri("http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
+
+ final Iterator<Triple> iter = graph.filter(null, foafName, null);
+ Assert.assertTrue(iter.hasNext());
+ final BlankNodeOrIri namedThing = iter.next().getSubject();
+ Assert.assertTrue(namedThing instanceof BlankNode);
+
+ final Iterator<Triple> iter2 = graph.filter(null, rdfType, foafPerson);
+ Assert.assertTrue(iter2.hasNext());
+ final BlankNodeOrIri person = iter2.next().getSubject();
+ Assert.assertTrue(person instanceof BlankNode);
+ Assert.assertEquals(namedThing, person);
+
+ final Iterator<Triple> iter3 = graph.filter(null, foafKnows, null);
+ Assert.assertTrue(iter3.hasNext());
+ final RdfTerm knownThing = iter3.next().getObject();
+ Assert.assertTrue(knownThing instanceof BlankNode);
+ Assert.assertEquals(knownThing, person);
+ Assert.assertEquals(namedThing, knownThing);
+ }
+
+ @Ignore
+ @Test
+ public void filter1() {
+ final Graph graph = new SparqlGraph("http://localhost:" + serverPort + "/ds/query");
+
+ final Iri foafPerson = new Iri("http://xmlns.com/foaf/0.1/Person");
+ final Iri foafName = new Iri("http://xmlns.com/foaf/0.1/name");
+ final Iri rdfType = new Iri("http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
+
+ final Iterator<Triple> iter = graph.filter(null, foafName, null);
+ Assert.assertTrue(iter.hasNext());
+ final BlankNodeOrIri person = iter.next().getSubject();
+ Assert.assertTrue(person instanceof BlankNode);
+
+ final Iterator<Triple> iter2 = graph.filter(person, rdfType, null);
+ Assert.assertTrue(iter2.hasNext());
+ }
+
+
+ public static int findFreePort() {
+ int port = 0;
+ try (ServerSocket server = new ServerSocket(0);) {
+ port = server.getLocalPort();
+ } catch (Exception e) {
+ throw new RuntimeException("unable to find a free port");
+ }
+ return port;
+ }
+
+}
diff --git a/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/SparqlGraphTest.java b/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/SparqlGraphTest.java
new file mode 100644
index 0000000..e75bc2c
--- /dev/null
+++ b/impl.sparql/src/test/java/org/apache/commons/rdf/impl/sparql/SparqlGraphTest.java
@@ -0,0 +1,104 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.apache.commons.rdf.impl.sparql;
+
+import com.hp.hpl.jena.query.DatasetAccessor;
+import com.hp.hpl.jena.query.DatasetAccessorFactory;
+import java.io.File;
+import java.io.IOException;
+import java.net.ServerSocket;
+import org.apache.jena.fuseki.EmbeddedFusekiServer;
+import com.hp.hpl.jena.rdf.model.Model;
+import com.hp.hpl.jena.rdf.model.ModelFactory;
+import java.io.InputStream;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import org.apache.commons.rdf.Graph;
+import org.apache.commons.rdf.Iri;
+import org.apache.commons.rdf.Language;
+import org.apache.commons.rdf.Literal;
+import org.apache.commons.rdf.RdfTerm;
+import org.apache.commons.rdf.Triple;
+import org.apache.commons.rdf.impl.utils.PlainLiteralImpl;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ * @author reto
+ */
+public class SparqlGraphTest {
+
+ final static int serverPort = findFreePort();
+ static EmbeddedFusekiServer server;
+
+ @BeforeClass
+ public static void prepare() throws IOException {
+ final String serviceURI = "http://localhost:" + serverPort + "/ds/data";
+ final DatasetAccessor accessor = DatasetAccessorFactory.createHTTP(serviceURI);
+ final InputStream in = SparqlGraphTest.class.getResourceAsStream("grounded.ttl");
+ final Model m = ModelFactory.createDefaultModel();
+ String base = "http://example.org/";
+ m.read(in, base, "TURTLE");
+ server = EmbeddedFusekiServer.memTDB(serverPort, "/ds");//dataSet.getAbsolutePath());
+ server.start();
+ System.out.println("Started fuseki on port " + serverPort);
+ accessor.putModel(m);
+ }
+
+ @AfterClass
+ public static void cleanup() {
+ server.stop();
+ }
+
+ @Test
+ public void graphSize() {
+ final Graph graph = new SparqlGraph("http://localhost:" + serverPort + "/ds/query");
+ Assert.assertEquals("Graph not of the exepected size", 8, graph.size());
+ }
+
+ @Test
+ public void filter1() {
+ final Graph graph = new SparqlGraph("http://localhost:" + serverPort + "/ds/query");
+ final Iri spiderman = new Iri("http://example.org/#spiderman");
+ final Iri greenGoblin = new Iri("http://example.org/#green-goblin");
+ final Iri enemyOf = new Iri("http://www.perceive.net/schemas/relationship/enemyOf");
+ final Iri foafName = new Iri("http://xmlns.com/foaf/0.1/name");
+ {
+ final Iterator<Triple> iter = graph.filter(spiderman, null, greenGoblin);
+ Assert.assertTrue(iter.hasNext());
+ Assert.assertEquals(enemyOf, iter.next().getPredicate());
+ Assert.assertFalse(iter.hasNext());
+ }
+ {
+ final Iterator<Triple> iter = graph.filter(spiderman, foafName, null);
+ Set<Literal> names = new HashSet<>();
+ for (int i = 0; i < 2; i++) {
+ Assert.assertTrue(iter.hasNext());
+ RdfTerm name = iter.next().getObject();
+ Assert.assertTrue(name instanceof Literal);
+ names.add((Literal)name);
+ }
+ Assert.assertFalse(iter.hasNext());
+ Assert.assertTrue(names.contains(new PlainLiteralImpl("Spiderman")));
+ Assert.assertTrue(names.contains(new PlainLiteralImpl("Человек-паук", new Language("ru"))));
+ }
+ }
+
+ public static int findFreePort() {
+ int port = 0;
+ try (ServerSocket server = new ServerSocket(0);) {
+ port = server.getLocalPort();
+ } catch (Exception e) {
+ throw new RuntimeException("unable to find a free port");
+ }
+ return port;
+ }
+
+}
diff --git a/impl.sparql/src/test/resources/org/apache/commons/rdf/impl/sparql/bnode-circle.ttl b/impl.sparql/src/test/resources/org/apache/commons/rdf/impl/sparql/bnode-circle.ttl
new file mode 100644
index 0000000..f03ab4d
--- /dev/null
+++ b/impl.sparql/src/test/resources/org/apache/commons/rdf/impl/sparql/bnode-circle.ttl
@@ -0,0 +1,7 @@
+@base <http://example.org/> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix foaf: <http://xmlns.com/foaf/0.1/> .
+
+_:a foaf:knows _:b .
+_:b foaf:knows _:a .
\ No newline at end of file
diff --git a/impl.sparql/src/test/resources/org/apache/commons/rdf/impl/sparql/grounded.ttl b/impl.sparql/src/test/resources/org/apache/commons/rdf/impl/sparql/grounded.ttl
new file mode 100644
index 0000000..ccc39c4
--- /dev/null
+++ b/impl.sparql/src/test/resources/org/apache/commons/rdf/impl/sparql/grounded.ttl
@@ -0,0 +1,16 @@
+@base <http://example.org/> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix foaf: <http://xmlns.com/foaf/0.1/> .
+@prefix rel: <http://www.perceive.net/schemas/relationship/> .
+
+<#green-goblin>
+ rel:enemyOf <#spiderman> ;
+ a foaf:Person ; # in the context of the Marvel universe
+ foaf:name "Green Goblin" ;
+ foaf:age 128 .
+
+<#spiderman>
+ rel:enemyOf <#green-goblin> ;
+ a foaf:Person ;
+ foaf:name "Spiderman", "Человек-паук"@ru .
\ No newline at end of file
diff --git a/impl.sparql/src/test/resources/org/apache/commons/rdf/impl/sparql/simple-bnode.ttl b/impl.sparql/src/test/resources/org/apache/commons/rdf/impl/sparql/simple-bnode.ttl
new file mode 100644
index 0000000..6bcf67f
--- /dev/null
+++ b/impl.sparql/src/test/resources/org/apache/commons/rdf/impl/sparql/simple-bnode.ttl
@@ -0,0 +1,7 @@
+@base <http://example.org/> .
+@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix foaf: <http://xmlns.com/foaf/0.1/> .
+
+<http://example.org/#me> foaf:knows [ a foaf:Person;
+ foaf:name "Alice Barker"].
\ No newline at end of file
diff --git a/impl.utils/pom.xml b/impl.utils/pom.xml
new file mode 100644
index 0000000..9a17a90
--- /dev/null
+++ b/impl.utils/pom.xml
@@ -0,0 +1,398 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+
+-->
+
+<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/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-parent</artifactId>
+ <version>37</version>
+ <relativePath />
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>commons-rdf</groupId>
+ <artifactId>commons-rdf-impl-utils</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ <name>Apache Commons RDF Implementation Utils</name>
+ <description>
+ Apache Commons RDF provides an API modelling the RDF data model as defined by
+ http://www.w3.org/TR/rdf11-concepts/
+ </description>
+ <url>http://commons.apache.org/sandbox/commons-rdf/</url>
+ <!-- TBD
+ <issueManagement>
+ <system>jira</system>
+ <url>http://issues.apache.org/jira/browse/RDF</url>
+ </issueManagement>
+ -->
+ <inceptionYear>2014</inceptionYear>
+ <scm>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/rdf/trunk</connection>
+ <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/rdf/trunk</developerConnection>
+ <url>http://svn.apache.org/viewvc/commons/proper/rdf/trunk</url>
+ </scm>
+
+
+ <dependencies>
+ <dependency>
+ <groupId>commons-rdf</groupId>
+ <artifactId>commons-rdf-api</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.12</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>1.7.7</version>
+ <type>jar</type>
+ </dependency>
+ </dependencies>
+
+ <distributionManagement>
+ <site>
+ <id>apache.website</id>
+ <name>Apache Commons Site</name>
+ <url>${commons.deployment.protocol}://people.apache.org/www/commons.apache.org/${commons.componentid}</url>
+ </site>
+ </distributionManagement>
+
+ <properties>
+ <maven.compiler.source>1.7</maven.compiler.source>
+ <maven.compiler.target>1.7</maven.compiler.target>
+ <commons.javadoc.java.link>http://docs.oracle.com/javase/7/docs/api/</commons.javadoc.java.link>
+ <commons.componentid>rdf</commons.componentid>
+ <commons.release.version>${project.version}</commons.release.version>
+<!-- <commons.rc.version>RC1</commons.rc.version>
+ <commons.release.desc>(Requires Java ${maven.compiler.target} or later)</commons.release.desc>
+ <commons.release.2.version>1.4.1</commons.release.2.version>
+ <commons.release.2.binary.suffix />
+ <commons.release.2.desc>(Requires Java 1.3 or later)</commons.release.2.desc> -->
+ <!-- TBD <commons.jira.id>RDF</commons.jira.id>
+ <commons.jira.pid></commons.jira.pid> -->
+ </properties>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>${commons.compiler.version}</version>
+ <configuration>
+ <!-- Fix incremental compiler bug, see https://jira.codehaus.org/browse/MCOMPILER-205 etc. -->
+ <excludes>
+ <exclude>**/package-info.java</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ <plugins>
+
+ <!-- Exclude examples from binary jar -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <excludes>
+ <exclude>examples/**</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+
+ <!-- Exclude examples from source jar -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-source-plugin</artifactId>
+ <configuration>
+ <excludes>
+ <exclude>examples/**</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <excludes>
+ <exclude>**/*FunctionalTest.java</exclude>
+ <exclude>**/POP3*Test.java</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <configuration>
+ <descriptors>
+ <descriptor>src/main/assembly/bin.xml</descriptor>
+ <descriptor>src/main/assembly/src.xml</descriptor>
+ </descriptors>
+ <tarLongFileMode>gnu</tarLongFileMode>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <configuration>
+ <target>
+ <jar destfile="target/commons-net-ftp-${project.version}.jar">
+ <metainf dir="${basedir}" includes="NOTICE.txt,LICENSE.txt" />
+ <manifest>
+ <attribute name="Extension-Name" value="org.apache.commons.net" />
+ <attribute name="Specification-Title" value="${project.name}" />
+ <attribute name="Implementation-Title" value="${project.name}" />
+ <attribute name="Implementation-Vendor" value="${project.organization.name}" />
+ <attribute name="Implementation-Version" value="${project.version}" />
+ <attribute name="Implementation-Vendor-Id" value="org.apache" />
+ <attribute name="Implementation-Build" value="${implementation.build}"/>
+ <attribute name="X-Compile-Source-JDK" value="${maven.compiler.source}" />
+ <attribute name="X-Compile-Target-JDK" value="${maven.compiler.target}" />
+ </manifest>
+ <fileset dir="target/classes" includes="org/apache/commons/net/ftp/**,org/apache/commons/net/*,org/apache/commons/net/io/*,org/apache/commons/net/util/*" />
+ </jar>
+ <!--
+ Create the binary examples jar, which will be added to the binary zip/tgz,
+ but not deployed independently to Maven
+ -->
+ <jar destfile="target/commons-net-examples-${project.version}.jar">
+ <metainf dir="${basedir}" includes="NOTICE.txt,LICENSE.txt" />
+ <manifest>
+ <attribute name="Extension-Name" value="org.apache.commons.net" />
+ <attribute name="Specification-Title" value="${project.name}" />
+ <attribute name="Implementation-Title" value="${project.name}" />
+ <attribute name="Implementation-Vendor" value="${project.organization.name}" />
+ <attribute name="Implementation-Version" value="${project.version}" />
+ <attribute name="Implementation-Vendor-Id" value="org.apache" />
+ <attribute name="Implementation-Build" value="${implementation.build}"/>
+ <attribute name="X-Compile-Source-JDK" value="${maven.compiler.source}" />
+ <attribute name="X-Compile-Target-JDK" value="${maven.compiler.target}" />
+ <!-- Helper application -->
+ <attribute name="Main-Class" value="examples/Main" />
+ <!-- Allow java -jar examples.jar to work -->
+ <attribute name="Class-Path" value="commons-net-${project.version}.jar" />
+ </manifest>
+ <fileset dir="target/classes" includes="examples/**" />
+ </jar>
+ </target>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <!-- Attaches the commons-net-ftp and examples JARs to the Maven lifecycle
+ to ensure they will be signed and deployed as normal -->
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.8</version>
+ <executions>
+ <execution>
+ <id>attach-artifacts</id>
+ <phase>package</phase>
+ <goals>
+ <goal>attach-artifact</goal>
+ </goals>
+ <configuration>
+ <artifacts>
+ <artifact>
+ <file>target/commons-net-ftp-${project.version}.jar</file>
+ <type>jar</type>
+ <classifier>ftp</classifier>
+ </artifact>
+ <artifact>
+ <file>target/commons-net-examples-${project.version}.jar</file>
+ <type>jar</type>
+ <classifier>examples</classifier>
+ </artifact>
+ </artifacts>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- Exclude examples from Javadoc jar -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <excludePackageNames>examples.*</excludePackageNames>
+ </configuration>
+ </plugin>
+
+ <!-- Copy the examples sources -->
+ <plugin>
+ <artifactId>maven-resources-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>copy-resources</id>
+ <phase>pre-site</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${basedir}/target/site/examples</outputDirectory>
+ <resources>
+ <resource>
+ <directory>src/main/java/examples</directory>
+ <excludes>
+ <exclude>**/Main.java</exclude>
+ </excludes>
+ <filtering>false</filtering>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-scm-publish-plugin</artifactId>
+ <configuration>
+ <ignorePathsToDelete>
+ <ignorePathToDelete>javadocs</ignorePathToDelete>
+ </ignorePathsToDelete>
+ </configuration>
+ </plugin>
+
+ </plugins>
+
+ </build>
+
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-changes-plugin</artifactId>
+ <version>${commons.changes.version}</version>
+ <configuration>
+ <issueLinkTemplatePerSystem>
+ <default>%URL%/%ISSUE%</default>
+ </issueLinkTemplatePerSystem>
+ <template>release-notes.vm</template>
+ <templateDirectory>src/changes</templateDirectory>
+ <!-- Add sample JIRA report - 'mvn changes:jira-report' or 'mvn site' -->
+ <onlyCurrentVersion>false</onlyCurrentVersion>
+ <columnNames>Fix Version,Key,Component,Summary,Type,Resolution,Status</columnNames>
+ <!-- Sort cols have to be reversed in JIRA 4 -->
+ <sortColumnNames>Key DESC,Type,Fix Version DESC</sortColumnNames>
+ <resolutionIds>Fixed</resolutionIds>
+ <statusIds>Resolved,Closed</statusIds>
+ <!-- Don't include sub-task -->
+ <typeIds>Bug,New Feature,Task,Improvement,Wish,Test</typeIds>
+ <fixVersionIds>${commons.release.version}</fixVersionIds>
+ <!-- The default is 100 -->
+ <maxEntries>100</maxEntries>
+ </configuration>
+ <reportSets>
+ <reportSet>
+ <reports>
+ <report>changes-report</report>
+ <report>jira-report</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ </plugin>
+
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>findbugs-maven-plugin</artifactId>
+ <version>2.5.5</version>
+ <configuration>
+ <excludeFilterFile>findbugs-exclude-filter.xml</excludeFilterFile>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>clirr-maven-plugin</artifactId>
+ <configuration>
+ <excludes>
+ <exclude>examples/**</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <excludePackageNames>examples.*</excludePackageNames>
+ </configuration>
+ <reportSets>
+ <reportSet>
+ <reports>
+ <report>javadoc</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-checkstyle-plugin</artifactId>
+ <version>2.11</version>
+ <configuration>
+ <configLocation>${basedir}/checkstyle.xml</configLocation>
+ <suppressionsLocation>${basedir}/checkstyle-suppressions.xml</suppressionsLocation>
+ <enableRulesSummary>false</enableRulesSummary>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <!-- Parent pom does not (yet) exclude these -->
+ <configuration>
+ <excludes>
+ <exclude>.checkstyle</exclude>
+ <exclude>.fbprefs</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+
+ </plugins>
+ </reporting>
+
+ <profiles>
+ <profile>
+ <!-- Temporary hack to suppress Javadoc 8 errors -->
+ <id>javadoc_8</id>
+ <activation>
+ <jdk>1.8</jdk>
+ </activation>
+ <properties>
+ <!-- Disable Xdoclint, until JavaDoc issues are fixed -->
+ <additionalparam>-Xdoclint:none</additionalparam>
+ </properties>
+ </profile>
+ </profiles>
+
+</project>
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/AbstractGraph.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/AbstractGraph.java
new file mode 100644
index 0000000..2c99679
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/AbstractGraph.java
@@ -0,0 +1,316 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf.impl.utils;
+
+import java.lang.ref.WeakReference;
+import java.util.AbstractCollection;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import java.util.Set;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import org.apache.commons.rdf.BlankNodeOrIri;
+import org.apache.commons.rdf.RdfTerm;
+import org.apache.commons.rdf.Triple;
+import org.apache.commons.rdf.Graph;
+import org.apache.commons.rdf.ImmutableGraph;
+import org.apache.commons.rdf.Iri;
+import org.apache.commons.rdf.WatchableGraph;
+import org.apache.commons.rdf.event.AddEvent;
+import org.apache.commons.rdf.event.FilterTriple;
+import org.apache.commons.rdf.event.GraphEvent;
+import org.apache.commons.rdf.event.GraphListener;
+import org.apache.commons.rdf.event.RemoveEvent;
+import org.apache.commons.rdf.impl.utils.debug.ReentrantReadWriteLockTracker;
+import org.apache.commons.rdf.impl.utils.simple.SimpleImmutableGraph;
+
+/**
+ * An abstract implementation of <code>Graph</code> implementing
+ * <code>iterator</code> and <code>contains</code> calling <code>filter</code>.
+ *
+ * @author reto
+ */
+public abstract class AbstractGraph extends AbstractCollection<Triple>
+ implements Graph {
+
+
+ private static final String DEBUG_MODE = "rdfLocksDebugging";
+ private final ReadWriteLock lock;
+
+ private final Lock readLock;
+ private final Lock writeLock;
+
+ /**
+ * Constructs a LocalbleMGraph for an Graph.
+ *
+ * @param providedMGraph a non-lockable graph
+ */
+ public AbstractGraph() {
+ {
+ String debugMode = System.getProperty(DEBUG_MODE);
+ if (debugMode != null && debugMode.toLowerCase().equals("true")) {
+ lock = new ReentrantReadWriteLockTracker();
+ } else {
+ lock = new ReentrantReadWriteLock();
+ }
+ }
+ readLock = lock.readLock();
+ writeLock = lock.writeLock();
+ }
+
+ public AbstractGraph(final ReadWriteLock lock) {
+ this.lock = lock;
+ readLock = lock.readLock();
+ writeLock = lock.writeLock();
+ }
+
+ @Override
+ public ReadWriteLock getLock() {
+ return lock;
+ }
+
+ @Override
+ public ImmutableGraph getImmutableGraph() {
+ readLock.lock();
+ try {
+ return performGetImmutableGraph();
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ public ImmutableGraph performGetImmutableGraph() {
+ return new SimpleImmutableGraph(this);
+ }
+
+ @Override
+ public Iterator<Triple> filter(BlankNodeOrIri subject, Iri predicate, RdfTerm object) {
+ readLock.lock();
+ try {
+ return new LockingIterator(performFilter(subject, predicate, object), lock);
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ public int size() {
+ readLock.lock();
+ try {
+ return performSize();
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ public boolean isEmpty() {
+ readLock.lock();
+ try {
+ return performIsEmpty();
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ @SuppressWarnings("element-type-mismatch")
+ public boolean contains(Object o) {
+ readLock.lock();
+ try {
+ return performContains(o);
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ public Iterator<Triple> iterator() {
+ readLock.lock();
+ try {
+ return new LockingIterator(performIterator(), lock);
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ public Object[] toArray() {
+ readLock.lock();
+ try {
+ return performToArray();
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ public <T> T[] toArray(T[] a) {
+ readLock.lock();
+ try {
+ return performToArray(a);
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> c) {
+ readLock.lock();
+ try {
+ return performContainsAll(c);
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ public boolean add(Triple e) {
+ writeLock.lock();
+ try {
+ return performAdd(e);
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ writeLock.lock();
+ try {
+ return performRemove(o);
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends Triple> c) {
+ writeLock.lock();
+ try {
+ return performAddAll(c);
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> c) {
+ writeLock.lock();
+ try {
+ return performRemoveAll(c);
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ @Override
+ public boolean retainAll(Collection<?> c) {
+ writeLock.lock();
+ try {
+ return performRetainAll(c);
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ @Override
+ public void clear() {
+ writeLock.lock();
+ try {
+ performClear();
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+
+ @Override
+ public boolean equals(Object obj) {
+ /*if (obj == null) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ if (obj.getClass() != getClass()) {
+ return false;
+ }*/
+ return this == obj;
+ }
+
+
+ protected abstract Iterator<Triple> performFilter(BlankNodeOrIri subject, Iri predicate, RdfTerm object);
+
+ protected abstract int performSize();
+
+ protected boolean performIsEmpty() {
+ return super.isEmpty();
+ }
+
+ protected Object[] performToArray() {
+ return super.toArray();
+ }
+
+ protected boolean performRemove(Object o) {
+ return super.remove(o);
+ }
+
+ protected boolean performAddAll(Collection<? extends Triple> c) {
+ return super.addAll(c);
+ }
+
+ protected boolean performRemoveAll(Collection<?> c) {
+ return super.removeAll(c);
+ }
+
+ protected boolean performRetainAll(Collection<?> c) {
+ return super.retainAll(c);
+ }
+
+ protected void performClear() {
+ super.clear();
+ }
+
+ protected boolean performContains(Object o) {
+ return super.contains(o);
+ }
+
+ protected Iterator<Triple> performIterator() {
+ return performFilter(null, null, null);
+ }
+
+ protected boolean performContainsAll(Collection<?> c) {
+ return super.containsAll(c);
+ }
+
+ protected <T> T[] performToArray(T[] a) {
+ return super.toArray(a);
+ }
+
+ protected boolean performAdd(Triple e) {
+ return super.add(e);
+ }
+
+
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/AbstractImmutableGraph.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/AbstractImmutableGraph.java
new file mode 100644
index 0000000..912a5ff
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/AbstractImmutableGraph.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf.impl.utils;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.commons.rdf.BlankNode;
+import org.apache.commons.rdf.ImmutableGraph;
+import org.apache.commons.rdf.RdfTerm;
+import org.apache.commons.rdf.Triple;
+import org.apache.commons.rdf.impl.utils.graphmatching.GraphMatcher;
+
+/**
+ * <code>AbstractGraph</code> is an abstract implementation of <code>ImmutableGraph</code>
+ * implementing the <code>equals</code> and the <code>hashCode</code> methods.
+ *
+ * @author reto
+ *
+ */
+public abstract class AbstractImmutableGraph extends AbstractGraph
+ implements ImmutableGraph {
+
+ public final synchronized int hashCode() {
+ int result = 0;
+ for (Iterator<Triple> iter = iterator(); iter.hasNext();) {
+ result += getBlankNodeBlindHash(iter.next());
+ }
+ return result;
+ }
+
+ /**
+ * @param triple
+ * @return hash without BNode hashes
+ */
+ private int getBlankNodeBlindHash(Triple triple) {
+ int hash = triple.getPredicate().hashCode();
+ RdfTerm subject = triple.getSubject();
+
+ if (!(subject instanceof BlankNode)) {
+ hash ^= subject.hashCode() >> 1;
+ }
+ RdfTerm object = triple.getObject();
+ if (!(object instanceof BlankNode)) {
+ hash ^= object.hashCode() << 1;
+ }
+
+ return hash;
+ }
+
+ @Override
+ public boolean add(Triple e) {
+ throw new UnsupportedOperationException("Graphs are not mutable, use Graph");
+
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends Triple> c) {
+ throw new UnsupportedOperationException("Graphs are not mutable, use Graph");
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ throw new UnsupportedOperationException("Graphs are not mutable, use Graph");
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> c) {
+ throw new UnsupportedOperationException("Graphs are not mutable, use Graph");
+ }
+
+ @Override
+ public void clear() {
+ throw new UnsupportedOperationException("Graphs are not mutable, use Graph");
+ }
+
+
+ @Override
+ public ImmutableGraph getImmutableGraph() {
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof ImmutableGraph)) {
+ return false;
+ }
+ if (hashCode() != obj.hashCode()) {
+ return false;
+ }
+ return GraphMatcher.getValidMapping(this, (ImmutableGraph) obj) != null;
+ }
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/AbstractLiteral.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/AbstractLiteral.java
new file mode 100644
index 0000000..e1fac11
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/AbstractLiteral.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2015 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.rdf.impl.utils;
+
+import org.apache.commons.rdf.Literal;
+
+/**
+ *
+ * @author developer
+ */
+public abstract class AbstractLiteral implements Literal {
+
+ @Override
+ public int hashCode() {
+ int result = 0;
+ if (getLanguage() != null) {
+ result = getLanguage().hashCode();
+ }
+ result += getLexicalForm().hashCode();
+ result += getDataType().hashCode();
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof Literal) {
+ Literal other = (Literal) obj;
+
+ if (getLanguage() == null) {
+ if (other.getLanguage() != null) {
+ return false;
+ }
+ } else {
+ if (!getLanguage().equals(other.getLanguage())) {
+ return false;
+ }
+ }
+ boolean res = getDataType().equals(other.getDataType()) && getLexicalForm().equals(other.getLexicalForm());
+ return res;
+ } else {
+ return false;
+ }
+ }
+
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/DelayedNotificator.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/DelayedNotificator.java
new file mode 100644
index 0000000..8fc8e92
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/DelayedNotificator.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf.impl.utils;
+
+import java.lang.ref.WeakReference;
+import java.util.*;
+
+import org.apache.commons.rdf.event.GraphEvent;
+import org.apache.commons.rdf.event.GraphListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author reto
+ */
+class DelayedNotificator {
+
+ private static final Logger log = LoggerFactory.getLogger(DelayedNotificator.class);
+ private static Timer timer = new Timer("Event delivery timer",true);
+
+ static class ListenerHolder {
+
+ long delay;
+ List<GraphEvent> events = null;
+ WeakReference<GraphListener> listenerRef;
+
+ public ListenerHolder(GraphListener listener, long delay) {
+ this.listenerRef = new WeakReference<GraphListener>(listener);
+ this.delay = delay;
+ }
+
+ private void registerEvent(GraphEvent event) {
+ synchronized (this) {
+ if (events == null) {
+ events = new ArrayList<GraphEvent>();
+ events.add(event);
+ timer.schedule(new TimerTask() {
+
+ @Override
+ public void run() {
+ List<GraphEvent> eventsLocal;
+ synchronized (ListenerHolder.this) {
+ eventsLocal = events;
+ events = null;
+ }
+ GraphListener listener = listenerRef.get();
+ if (listener == null) {
+ log.debug("Ignoring garbage collected listener");
+ } else {
+ try {
+ listener.graphChanged(eventsLocal);
+ } catch (Exception e) {
+ log.warn("Exception delivering ImmutableGraph event", e);
+ }
+ }
+ }
+ }, delay);
+ } else {
+ events.add(event);
+ }
+ }
+ }
+ }
+
+ private final Map<GraphListener, ListenerHolder> map = Collections.synchronizedMap(
+ new WeakHashMap<GraphListener, ListenerHolder>());
+
+ void addDelayedListener(GraphListener listener, long delay) {
+ map.put(listener, new ListenerHolder(listener, delay));
+ }
+
+ /**
+ * removes a Listener, this doesn't prevent the listenerRef from receiving
+ * events alreay scheduled.
+ *
+ * @param listenerRef
+ */
+ void removeDelayedListener(GraphListener listener) {
+ map.remove(listener);
+ }
+
+ /**
+ * if the listenerRef has not been registered as delayed listenerRef te events is
+ * forwarded synchroneously
+ * @param event
+ */
+ void sendEventToListener(GraphListener listener, GraphEvent event) {
+ ListenerHolder holder = map.get(listener);
+ if (holder == null) {
+ listener.graphChanged(Collections.singletonList(event));
+ } else {
+ holder.registerEvent(event);
+ }
+ }
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/LockingIterator.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/LockingIterator.java
new file mode 100644
index 0000000..8f6945e
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/LockingIterator.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf.impl.utils;
+
+import java.util.Iterator;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import org.apache.commons.rdf.Triple;
+
+/**
+ * Wrapps an iterator<Triple> reading entering a read-lock on every invocation
+ * of hasNext and next
+ * @author reto
+ */
+class LockingIterator implements Iterator<Triple> {
+
+ private Iterator<Triple> base;
+ private Lock readLock;
+ private Lock writeLock;
+
+ public LockingIterator(Iterator<Triple> iterator, ReadWriteLock lock) {
+ base = iterator;
+ readLock = lock.readLock();
+ writeLock = lock.writeLock();
+ }
+
+ @Override
+ public boolean hasNext() {
+ readLock.lock();
+ try {
+ return base.hasNext();
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ public Triple next() {
+ readLock.lock();
+ try {
+ return base.next();
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ @Override
+ public void remove() {
+ writeLock.lock();
+ try {
+ base.remove();
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/PlainLiteralImpl.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/PlainLiteralImpl.java
new file mode 100644
index 0000000..5dcbaf7
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/PlainLiteralImpl.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf.impl.utils;
+
+import java.io.Serializable;
+import org.apache.commons.rdf.Iri;
+
+import org.apache.commons.rdf.Language;
+import org.apache.commons.rdf.Literal;
+
+/**
+ *
+ * @author reto
+ */
+public class PlainLiteralImpl implements Literal, Serializable {
+
+ private String lexicalForm;
+ private Language language = null;
+
+ public PlainLiteralImpl(String value) {
+ if (value == null) {
+ throw new IllegalArgumentException("The literal string cannot be null");
+ }
+ this.lexicalForm = value;
+ }
+
+ public PlainLiteralImpl(String value, Language language) {
+ if (value == null) {
+ throw new IllegalArgumentException("The literal string cannot be null");
+ }
+ this.lexicalForm = value;
+ this.language = language;
+ }
+
+ @Override
+ public String getLexicalForm() {
+ return lexicalForm;
+ }
+
+ @Override
+ public boolean equals(Object otherObj) {
+ if (!(otherObj instanceof Literal)) {
+ return false;
+ }
+ Literal other = (Literal) otherObj;
+ if (!lexicalForm.equals(other.getLexicalForm())) {
+ return false;
+ }
+ if (language != null) {
+ return language.equals(other.getLanguage());
+ }
+ if (other.getLanguage() != null) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = lexicalForm.hashCode() + XSD_STRING_HASH;
+ if (language != null) {
+ hash += language.hashCode();
+ }
+ return hash;
+ }
+
+ @Override
+ public Language getLanguage() {
+ return language;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer result = new StringBuffer();
+ result.append('\"').append(lexicalForm).append('\"');
+ if (language != null) {
+ result.append("@").append(language.toString());
+ }
+ return result.toString();
+ }
+
+ @Override
+ public Iri getDataType() {
+ return XSD_STRING;
+ }
+ private static final Iri XSD_STRING = new Iri("http://www.w3.org/2001/XMLSchema#string");
+ private static final int XSD_STRING_HASH = XSD_STRING.hashCode();
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/TripleImpl.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/TripleImpl.java
new file mode 100644
index 0000000..ece7d55
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/TripleImpl.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf.impl.utils;
+
+import org.apache.commons.rdf.BlankNodeOrIri;
+import org.apache.commons.rdf.RdfTerm;
+import org.apache.commons.rdf.Triple;
+import org.apache.commons.rdf.Iri;
+
+/**
+ *
+ * @author reto
+ */
+public class TripleImpl implements Triple {
+
+ private final BlankNodeOrIri subject;
+ private final Iri predicate;
+ private final RdfTerm object;
+
+ /**
+ * Creates a new <code>TripleImpl</code>.
+ *
+ * @param subject the subject.
+ * @param predicate the predicate.
+ * @param object the object.
+ * @throws IllegalArgumentException if an attribute is <code>null</code>.
+ */
+ public TripleImpl(BlankNodeOrIri subject, Iri predicate, RdfTerm object) {
+ if (subject == null) {
+ throw new IllegalArgumentException("Invalid subject: null");
+ } else if (predicate == null) {
+ throw new IllegalArgumentException("Invalid predicate: null");
+ } else if (object == null) {
+ throw new IllegalArgumentException("Invalid object: null");
+ }
+ this.subject = subject;
+ this.predicate = predicate;
+ this.object = object;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof Triple)) {
+ return false;
+ }
+ final Triple other = (Triple) obj;
+ if (!this.subject.equals(other.getSubject())) {
+ return false;
+ }
+ if (!this.predicate.equals(other.getPredicate())) {
+ return false;
+ }
+ if (!this.object.equals(other.getObject())) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return (subject.hashCode() >> 1) ^ predicate.hashCode() ^ (object.hashCode() << 1);
+ }
+
+ @Override
+ public BlankNodeOrIri getSubject() {
+ return subject;
+ }
+
+ public Iri getPredicate() {
+ return predicate;
+ }
+
+ public RdfTerm getObject() {
+ return object;
+ }
+
+ @Override
+ public String toString() {
+ return subject + " " + predicate + " " + object + ".";
+ }
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/TypedLiteralImpl.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/TypedLiteralImpl.java
new file mode 100644
index 0000000..45863ff
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/TypedLiteralImpl.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf.impl.utils;
+
+import java.io.Serializable;
+
+import org.apache.commons.rdf.Iri;
+import org.apache.commons.rdf.Language;
+import org.apache.commons.rdf.Literal;
+
+/**
+ *
+ * @author reto
+ */
+public class TypedLiteralImpl extends AbstractLiteral implements Serializable {
+ private String lexicalForm;
+ private Iri dataType;
+ private int hashCode;
+
+ /**
+ * @param lexicalForm
+ * @param dataType
+ */
+ public TypedLiteralImpl(String lexicalForm, Iri dataType) {
+ this.lexicalForm = lexicalForm;
+ this.dataType = dataType;
+ this.hashCode = lexicalForm.hashCode()+dataType.hashCode();
+ }
+
+ public Iri getDataType() {
+ return dataType;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.clerezza.rdf.core.LiteralNode#getLexicalForm()
+ */
+ @Override
+ public String getLexicalForm() {
+ return lexicalForm;
+ }
+
+ @Override
+ public int hashCode() {
+ return hashCode;
+ }
+
+
+ @Override
+ public String toString() {
+ StringBuffer result = new StringBuffer();
+ result.append('\"');
+ result.append(getLexicalForm());
+ result.append('\"');
+ result.append("^^");
+ result.append(getDataType());
+ return result.toString();
+ }
+
+ @Override
+ public Language getLanguage() {
+ return null;
+ }
+
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/WatchableGraphWrapper.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/WatchableGraphWrapper.java
new file mode 100644
index 0000000..76b9283
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/WatchableGraphWrapper.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright 2015 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.rdf.impl.utils;
+
+import java.lang.ref.WeakReference;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.locks.ReadWriteLock;
+import org.apache.commons.rdf.BlankNodeOrIri;
+import org.apache.commons.rdf.Graph;
+import org.apache.commons.rdf.ImmutableGraph;
+import org.apache.commons.rdf.Iri;
+import org.apache.commons.rdf.RdfTerm;
+import org.apache.commons.rdf.Triple;
+import org.apache.commons.rdf.WatchableGraph;
+import org.apache.commons.rdf.event.AddEvent;
+import org.apache.commons.rdf.event.FilterTriple;
+import org.apache.commons.rdf.event.GraphEvent;
+import org.apache.commons.rdf.event.GraphListener;
+import org.apache.commons.rdf.event.RemoveEvent;
+
+/**
+ *
+ * @author developer
+ */
+public class WatchableGraphWrapper implements WatchableGraph {
+
+ final Graph wrapped;
+
+ public WatchableGraphWrapper(Graph wrapped) {
+ this.wrapped = wrapped;
+ }
+
+
+ //all listeners
+ private final Set<ListenerConfiguration> listenerConfigs = Collections.synchronizedSet(
+ new HashSet<ListenerConfiguration>());
+ private DelayedNotificator delayedNotificator = new DelayedNotificator();
+
+ @Override
+ public Iterator<Triple> iterator() {
+ return filter(null, null, null);
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ if (!(o instanceof Triple)) {
+ return false;
+ }
+ Triple t = (Triple) o;
+ return filter(t.getSubject(), t.getPredicate(), t.getObject()).hasNext();
+ }
+
+ @Override
+ public Iterator<Triple> filter(BlankNodeOrIri subject, Iri predicate,
+ RdfTerm object) {
+ final Iterator<Triple> baseIter = wrapped.filter(subject, predicate, object);
+ return new Iterator<Triple>() {
+
+ Triple currentTriple = null;
+
+ @Override
+ public boolean hasNext() {
+ return baseIter.hasNext();
+ }
+
+ @Override
+ public Triple next() {
+ currentTriple = baseIter.next();
+ return currentTriple;
+ }
+
+ @Override
+ public void remove() {
+ baseIter.remove();
+ dispatchEvent(new RemoveEvent(WatchableGraphWrapper.this, currentTriple));
+ }
+ };
+ }
+
+ @Override
+ public boolean add(Triple triple) {
+ boolean success = performAdd(triple);
+ if (success) {
+ dispatchEvent(new AddEvent(this, triple));
+ }
+ return success;
+ }
+
+ /**
+ * A subclass of <code>AbstractGraph</code> should override
+ * this method instead of <code>add</code> for Graph event support to be
+ * added.
+ *
+ * @param e The triple to be added to the triple collection
+ * @return
+ */
+ protected boolean performAdd(Triple e) {
+ return wrapped.add(e);
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ Triple triple = (Triple) o;
+ boolean success = performRemove(triple);
+ if (success) {
+ dispatchEvent(new RemoveEvent(this, triple));
+ }
+ return success;
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> c) {
+ boolean modified = false;
+ for (Iterator<? extends Object> it = c.iterator(); it.hasNext();) {
+ Object object = it.next();
+ if (remove(object)) {
+ modified = true;
+ }
+ }
+ return modified;
+ }
+
+ /**
+ * A subclass of <code>AbstractGraph</code> should override
+ * this method instead of <code>remove</code> for ImmutableGraph event support to be
+ * added.
+ *
+ * @param o The triple to be removed from the triple collection
+ * @return
+ */
+ protected boolean performRemove(Triple triple) {
+ Iterator<Triple> e = filter(null, null, null);
+ while (e.hasNext()) {
+ if (triple.equals(e.next())) {
+ e.remove();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Dispatches a <code>GraphEvent</code> to all registered listeners for which
+ * the specified <code>Triple</code> matches the <code>FilterTriple</code>s
+ * of the listeners.
+ *
+ * @param triple The Triple that was modified
+ * @param type The type of modification
+ */
+ protected void dispatchEvent(GraphEvent event) {
+ synchronized(listenerConfigs) {
+ Iterator<ListenerConfiguration> iter = listenerConfigs.iterator();
+ while (iter.hasNext()) {
+ ListenerConfiguration config = iter.next();
+ GraphListener registeredListener = config.getListener();
+ if (registeredListener == null) {
+ iter.remove();
+ continue;
+ }
+ if (config.getFilter().match(event.getTriple())) {
+ delayedNotificator.sendEventToListener(registeredListener, event);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void addGraphListener(GraphListener listener, FilterTriple filter) {
+ addGraphListener(listener, filter, 0);
+ }
+
+ @Override
+ public void addGraphListener(GraphListener listener, FilterTriple filter,
+ long delay) {
+ listenerConfigs.add(new ListenerConfiguration(listener, filter));
+ if (delay > 0) {
+ delayedNotificator.addDelayedListener(listener, delay);
+ }
+ }
+
+ @Override
+ public void removeGraphListener(GraphListener listener) {
+ synchronized(listenerConfigs) {
+ Iterator<ListenerConfiguration> iter = listenerConfigs.iterator();
+ while (iter.hasNext()) {
+ ListenerConfiguration listenerConfig = iter.next();
+ GraphListener registeredListener = listenerConfig.getListener();
+ if ((registeredListener == null) || (registeredListener.equals(listener))) {
+ iter.remove();
+ }
+ }
+ }
+ delayedNotificator.removeDelayedListener(listener);
+ }
+
+ @Override
+ public ImmutableGraph getImmutableGraph() {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+
+ @Override
+ public ReadWriteLock getLock() {
+ return wrapped.getLock();
+ }
+
+ @Override
+ public int size() {
+ return wrapped.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return wrapped.isEmpty();
+ }
+
+ @Override
+ public Object[] toArray() {
+ return wrapped.toArray();
+ }
+
+ @Override
+ public <T> T[] toArray(T[] a) {
+ return wrapped.toArray(a);
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> c) {
+ return wrapped.containsAll(c);
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends Triple> c) {
+ return wrapped.addAll(c);
+ }
+
+ @Override
+ public boolean retainAll(Collection<?> c) {
+ return wrapped.retainAll(c);
+ }
+
+ @Override
+ public void clear() {
+ wrapped.clear();
+ }
+
+ private static class ListenerConfiguration {
+
+ private WeakReference<GraphListener> listenerRef;
+ private FilterTriple filter;
+
+ private ListenerConfiguration(GraphListener listener, FilterTriple filter) {
+ this.listenerRef = new WeakReference<GraphListener>(listener);
+ this.filter = filter;
+ }
+
+ /**
+ * @return the listener
+ */
+ GraphListener getListener() {
+ GraphListener listener = listenerRef.get();
+ return listener;
+ }
+
+ /**
+ * @return the filter
+ */
+ FilterTriple getFilter() {
+ return filter;
+ }
+ }
+
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/debug/ReadLockDebug.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/debug/ReadLockDebug.java
new file mode 100644
index 0000000..f2b93b8
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/debug/ReadLockDebug.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.commons.rdf.impl.utils.debug;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
+
+/**
+ *
+ * @author mir
+ */
+public class ReadLockDebug extends ReadLock {
+
+ ReentrantReadWriteLockTracker lock;
+ StackTraceElement[] stackTrace;
+
+ ReadLock readLock;
+ public ReadLockDebug(ReentrantReadWriteLockTracker lock) {
+ super(lock);
+ this.lock = lock;
+ this.readLock = lock.realReadLock();
+ }
+
+ @Override
+ public void lock() {
+ readLock.lock();
+ lock.addLockedReadLock(this);
+ stackTrace = Thread.currentThread().getStackTrace();
+ }
+
+ @Override
+ public void lockInterruptibly() throws InterruptedException {
+ readLock.lockInterruptibly();
+ }
+
+ @Override
+ public Condition newCondition() {
+ return readLock.newCondition();
+ }
+
+ @Override
+ public String toString() {
+ return readLock.toString();
+ }
+
+ @Override
+ public boolean tryLock() {
+ return readLock.tryLock();
+ }
+
+ @Override
+ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
+ return readLock.tryLock(timeout, unit);
+ }
+
+ @Override
+ public void unlock() {
+ readLock.unlock();
+ lock.removeReadLock(this);
+ stackTrace = null;
+ }
+
+ public StackTraceElement[] getStackTrace() {
+ return stackTrace;
+ }
+
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/debug/ReentrantReadWriteLockTracker.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/debug/ReentrantReadWriteLockTracker.java
new file mode 100644
index 0000000..65abf32
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/debug/ReentrantReadWriteLockTracker.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf.impl.utils.debug;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ *
+ * @author mir
+ */
+public class ReentrantReadWriteLockTracker extends ReentrantReadWriteLock {
+
+
+ private Set<ReadLockDebug> lockedReadLocks = Collections.synchronizedSet(new HashSet<ReadLockDebug>());
+ private final WriteLockDebug writeLock = new WriteLockDebug(this);
+ @Override
+ protected Thread getOwner() {
+ return super.getOwner();
+ }
+
+ @Override
+ protected Collection<Thread> getQueuedReaderThreads() {
+ return super.getQueuedReaderThreads();
+ }
+
+ @Override
+ protected Collection<Thread> getQueuedThreads() {
+ return super.getQueuedThreads();
+ }
+
+ @Override
+ protected Collection<Thread> getQueuedWriterThreads() {
+ return super.getQueuedWriterThreads();
+ }
+
+ @Override
+ public int getReadHoldCount() {
+ return super.getReadHoldCount();
+ }
+
+ @Override
+ public int getReadLockCount() {
+ return super.getReadLockCount();
+ }
+
+ @Override
+ public int getWaitQueueLength(Condition condition) {
+ return super.getWaitQueueLength(condition);
+ }
+
+ @Override
+ protected Collection<Thread> getWaitingThreads(Condition condition) {
+ return super.getWaitingThreads(condition);
+ }
+
+ @Override
+ public int getWriteHoldCount() {
+ return super.getWriteHoldCount();
+ }
+
+ @Override
+ public boolean hasWaiters(Condition condition) {
+ return super.hasWaiters(condition);
+ }
+
+ @Override
+ public boolean isWriteLocked() {
+ return super.isWriteLocked();
+ }
+
+ @Override
+ public boolean isWriteLockedByCurrentThread() {
+ return super.isWriteLockedByCurrentThread();
+ }
+
+ @Override
+ public ReadLock readLock() {
+ return new ReadLockDebug(this);
+ }
+
+ ReadLock realReadLock() {
+ return super.readLock();
+ }
+
+ WriteLock realWriteLock() {
+ return super.writeLock();
+ }
+
+ @Override
+ public String toString() {
+ return super.toString();
+ }
+
+ @Override
+ public WriteLockDebug writeLock() {
+ return writeLock;
+ }
+
+ void addLockedReadLock(ReadLockDebug lock) {
+ lockedReadLocks.add(lock);
+ }
+
+ void removeReadLock(ReadLockDebug lock) {
+ lockedReadLocks.remove(lock);
+ }
+
+ public Set<ReadLockDebug> getLockedReadLocks() {
+ return lockedReadLocks;
+ }
+
+
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/debug/WriteLockDebug.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/debug/WriteLockDebug.java
new file mode 100644
index 0000000..0231331
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/debug/WriteLockDebug.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.commons.rdf.impl.utils.debug;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
+
+/**
+ *
+ * @author mir
+ */
+public class WriteLockDebug extends WriteLock {
+
+ private ReentrantReadWriteLockTracker lock;
+ private WriteLock writeLock;
+ private StackTraceElement[] stackTrace;
+
+ public WriteLockDebug(ReentrantReadWriteLockTracker lock) {
+ super(lock);
+ this.lock = lock;
+ this.writeLock = lock.realWriteLock();
+ }
+
+ @Override
+ public int getHoldCount() {
+ return writeLock.getHoldCount();
+ }
+
+ @Override
+ public boolean isHeldByCurrentThread() {
+ return writeLock.isHeldByCurrentThread();
+ }
+
+ @Override
+ public void lock() {
+ writeLock.lock();
+ stackTrace = Thread.currentThread().getStackTrace();
+ }
+
+ @Override
+ public void lockInterruptibly() throws InterruptedException {
+ writeLock.lockInterruptibly();
+ }
+
+ @Override
+ public Condition newCondition() {
+ return writeLock.newCondition();
+ }
+
+ @Override
+ public boolean tryLock() {
+ return writeLock.tryLock();
+ }
+
+ @Override
+ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
+ return writeLock.tryLock(timeout, unit);
+ }
+
+ @Override
+ public void unlock() {
+ writeLock.unlock();
+ stackTrace = null;
+ }
+
+ public StackTraceElement[] getStackTrace() {
+ return stackTrace;
+ }
+
+
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/GraphMatcher.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/GraphMatcher.java
new file mode 100644
index 0000000..70f5437
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/GraphMatcher.java
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.commons.rdf.impl.utils.graphmatching;
+
+
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.rdf.BlankNode;
+import org.apache.commons.rdf.BlankNodeOrIri;
+import org.apache.commons.rdf.Graph;
+import org.apache.commons.rdf.RdfTerm;
+import org.apache.commons.rdf.Triple;
+import org.apache.commons.rdf.impl.utils.TripleImpl;
+import org.apache.commons.rdf.impl.utils.simple.SimpleMGraph;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author reto
+ *
+ */
+public class GraphMatcher {
+
+
+ private final static Logger log = LoggerFactory.getLogger(GraphMatcher.class);
+
+ /**
+ * get a mapping from g1 to g2 or null if the graphs are not isomorphic. The
+ * returned map maps each <code>BNode</code>s from g1 to one
+ * of g2. If the graphs are ground graphs the method return an empty map if
+ * the ImmutableGraph are equals and null otherwise.
+ * <p/>
+ * NOTE: This method does not returned mapping from blank nodes to grounded
+ * nodes, a bnode in g1 is not a vraiable that may match any node, but must
+ * match a bnode in g2.
+ * <p/>
+ *
+ * On the algorithm:<br/>
+ * - In a first step it checked if every grounded triple in g1 matches one
+ * in g2<br/>
+ * - [optional] blank node blind matching</br>
+ * - in a map mbng1 bnode of g1 is mapped to a set of of its
+ * properties and inverse properties, this is the predicate and the object
+ * or subject respectively, analoguosly in mbgn2 every bnode of g2<br/>
+ * - based on the incoming and outgoing properties a hash is calculated for
+ * each bnode, in the first step when calculating the hash aconstant value
+ * is taken for the bnodes that might be subject or object in the (inverse properties)
+ * - hash-classes:
+ *
+ * @param g1
+ * @param g2
+ * @return a Set of NodePairs
+ */
+ public static Map<BlankNode, BlankNode> getValidMapping(Graph og1, Graph og2) {
+ Graph g1 = new SimpleMGraph(og1);
+ Graph g2 = new SimpleMGraph(og2);
+ if (!Utils.removeGrounded(g1,g2)) {
+ return null;
+ }
+ final HashMatching hashMatching;
+ try {
+ hashMatching = new HashMatching(g1, g2);
+ } catch (GraphNotIsomorphicException ex) {
+ return null;
+ }
+ Map<BlankNode, BlankNode> matchings = hashMatching.getMatchings();
+ if (g1.size() > 0) {
+ //start trial an error matching
+ //TODO (CLEREZZA-81) at least in the situation where one matching
+ //group is big (approx > 5) we should switch back to hash-based matching
+ //after a first guessed matching, rather than try all permutations
+ Map<BlankNode, BlankNode> remainingMappings = trialAndErrorMatching(g1, g2, hashMatching.getMatchingGroups());
+ if (remainingMappings == null) {
+ return null;
+ } else {
+ matchings.putAll(remainingMappings);
+ }
+ }
+ return matchings;
+ }
+
+ private static Map<BlankNode, BlankNode> trialAndErrorMatching(Graph g1, Graph g2,
+ Map<Set<BlankNode>, Set<BlankNode>> matchingGroups) {
+ if (log.isDebugEnabled()) {
+ Set<BlankNode> bn1 = Utils.getBNodes(g1);
+ log.debug("doing trial and error matching for {} bnodes, " +
+ "in graphs of size: {}.", bn1.size(), g1.size());
+ }
+ Iterator<Map<BlankNode, BlankNode>> mappingIter
+ = GroupMappingIterator.create(matchingGroups);
+ while (mappingIter.hasNext()) {
+ Map<BlankNode, BlankNode> map = mappingIter.next();
+ if (checkMapping(g1, g2, map)) {
+ return map;
+ }
+ }
+ return null;
+ }
+
+ private static boolean checkMapping(Graph g1, Graph g2, Map<BlankNode, BlankNode> map) {
+ for (Triple triple : g1) {
+ if (!g2.contains(map(triple, map))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static Triple map(Triple triple, Map<BlankNode, BlankNode> map) {
+ final BlankNodeOrIri oSubject = triple.getSubject();
+
+ BlankNodeOrIri subject = oSubject instanceof BlankNode ?
+ map.get((BlankNode)oSubject) : oSubject;
+
+ RdfTerm oObject = triple.getObject();
+ RdfTerm object = oObject instanceof BlankNode ?
+ map.get((BlankNode)oObject) : oObject;
+ return new TripleImpl(subject, triple.getPredicate(), object);
+ }
+
+
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/GraphNotIsomorphicException.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/GraphNotIsomorphicException.java
new file mode 100644
index 0000000..42de52e
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/GraphNotIsomorphicException.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.commons.rdf.impl.utils.graphmatching;
+
+/**
+ *
+ * @author reto
+ */
+class GraphNotIsomorphicException extends Exception {
+
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/GroupMappingIterator.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/GroupMappingIterator.java
new file mode 100644
index 0000000..f79bd2a
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/GroupMappingIterator.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2010 reto.
+ *
+ * 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.
+ * under the License.
+ */
+
+package org.apache.commons.rdf.impl.utils.graphmatching;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+/**
+ * Iterates over all mappings from each element of every Set<T> to each
+ * elemenent of their corresponding Set<U>.
+ *
+ * @author reto
+ */
+class GroupMappingIterator<T,U> implements Iterator<Map<T, U>> {
+
+ private Iterator<Map<T, U>> firstPartIter;
+ private Map<T, U> currentFirstPart;
+ final private Map<Set<T>, Set<U>> restMap;
+ private Iterator<Map<T, U>> currentRestPartIter;
+
+ static <T,U> Iterator<Map<T, U>> create(Map<Set<T>, Set<U>> matchingGroups) {
+ if (matchingGroups.size() > 1) {
+ return new GroupMappingIterator<T, U>(matchingGroups);
+ } else {
+ if (matchingGroups.size() == 0) {
+ return new ArrayList<Map<T, U>>(0).iterator();
+ }
+ Map.Entry<Set<T>, Set<U>> entry = matchingGroups.entrySet().iterator().next();
+ return new MappingIterator<T,U>(entry.getKey(),
+ entry.getValue());
+ }
+ }
+
+ private GroupMappingIterator(Map<Set<T>, Set<U>> matchingGroups) {
+ if (matchingGroups.size() == 0) {
+ throw new IllegalArgumentException("matchingGroups must not be empty");
+ }
+ restMap = new HashMap<Set<T>, Set<U>>();
+ boolean first = true;
+ for (Map.Entry<Set<T>, Set<U>> entry : matchingGroups.entrySet()) {
+ if (first) {
+ firstPartIter = new MappingIterator<T,U>(entry.getKey(),
+ entry.getValue());
+ first = false;
+ } else {
+ restMap.put(entry.getKey(), entry.getValue());
+ }
+ }
+ currentRestPartIter = create(restMap);
+ currentFirstPart = firstPartIter.next();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return firstPartIter.hasNext() || currentRestPartIter.hasNext();
+ }
+
+ @Override
+ public Map<T, U> next() {
+ Map<T, U> restPart;
+ if (currentRestPartIter.hasNext()) {
+ restPart = currentRestPartIter.next();
+ } else {
+ if (firstPartIter.hasNext()) {
+ currentFirstPart = firstPartIter.next();
+ currentRestPartIter = create(restMap);
+ restPart = currentRestPartIter.next();
+ } else {
+ throw new NoSuchElementException();
+ }
+ }
+ Map<T, U> result = new HashMap<T, U>(restPart);
+ result.putAll(currentFirstPart);
+ return result;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/HashMatching.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/HashMatching.java
new file mode 100644
index 0000000..ae419f6
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/HashMatching.java
@@ -0,0 +1,268 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.commons.rdf.impl.utils.graphmatching;
+
+
+import org.apache.commons.rdf.impl.utils.graphmatching.collections.IntHashMap;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.rdf.BlankNode;
+import org.apache.commons.rdf.Graph;
+import org.apache.commons.rdf.BlankNodeOrIri;
+import org.apache.commons.rdf.RdfTerm;
+import org.apache.commons.rdf.Triple;
+import org.apache.commons.rdf.Graph;
+import org.apache.commons.rdf.Iri;
+import org.apache.commons.rdf.impl.utils.TripleImpl;
+import org.apache.commons.rdf.impl.utils.graphmatching.collections.IntIterator;
+
+/**
+ *
+ * @author reto
+ */
+public class HashMatching {
+
+ private Map<BlankNode, BlankNode> matchings = new HashMap<BlankNode, BlankNode>();
+ private Map<Set<BlankNode>, Set<BlankNode>> matchingGroups;
+
+ /**
+ * tc1 and tc2 will be modified: the triples containing no unmatched bnode
+ * will be removed
+ *
+ * @param tc1
+ * @param tc2
+ * @throws GraphNotIsomorphicException
+ */
+ HashMatching(Graph tc1, Graph tc2) throws GraphNotIsomorphicException {
+ int foundMatchings = 0;
+ int foundMatchingGroups = 0;
+ Map<BlankNode, Integer> bNodeHashMap = new HashMap<BlankNode, Integer>();
+ while (true) {
+ bNodeHashMap = matchByHashes(tc1, tc2, bNodeHashMap);
+ if (bNodeHashMap == null) {
+ throw new GraphNotIsomorphicException();
+ }
+ if (matchings.size() == foundMatchings) {
+ if (!(matchingGroups.size() > foundMatchingGroups)) {
+ break;
+ }
+ }
+ foundMatchings = matchings.size();
+ foundMatchingGroups = matchingGroups.size();
+ }
+ }
+
+ /**
+ *
+ * @return a map containing set of which each bnodes mappes one of the other set
+ */
+ public Map<Set<BlankNode>, Set<BlankNode>> getMatchingGroups() {
+ return matchingGroups;
+ }
+
+ public Map<BlankNode, BlankNode> getMatchings() {
+ return matchings;
+ }
+
+
+ private static IntHashMap<Set<BlankNode>> getHashNodes(Map<BlankNode,
+ Set<Property>> bNodePropMap, Map<BlankNode, Integer> bNodeHashMap) {
+ IntHashMap<Set<BlankNode>> result = new IntHashMap<Set<BlankNode>>();
+ for (Map.Entry<BlankNode, Set<Property>> entry : bNodePropMap.entrySet()) {
+ int hash = computeHash(entry.getValue(), bNodeHashMap);
+ Set<BlankNode> bNodeSet = result.get(hash);
+ if (bNodeSet == null) {
+ bNodeSet = new HashSet<BlankNode>();
+ result.put(hash,bNodeSet);
+ }
+ bNodeSet.add(entry.getKey());
+ }
+ return result;
+ }
+ /*
+ * returns a Map from bnodes to hash that can be used for future
+ * refinements, this could be separate for each ImmutableGraph.
+ *
+ * triples no longer containing an unmatched bnodes ae removed.
+ *
+ * Note that the matched node are not guaranteed to be equals, but only to
+ * be the correct if the graphs are isomorphic.
+ */
+ private Map<BlankNode, Integer> matchByHashes(Graph g1, Graph g2,
+ Map<BlankNode, Integer> bNodeHashMap) {
+ Map<BlankNode, Set<Property>> bNodePropMap1 = getBNodePropMap(g1);
+ Map<BlankNode, Set<Property>> bNodePropMap2 = getBNodePropMap(g2);
+ IntHashMap<Set<BlankNode>> hashNodeMap1 = getHashNodes(bNodePropMap1, bNodeHashMap);
+ IntHashMap<Set<BlankNode>> hashNodeMap2 = getHashNodes(bNodePropMap2, bNodeHashMap);
+ if (!hashNodeMap1.keySet().equals(hashNodeMap2.keySet())) {
+ return null;
+ }
+
+ matchingGroups = new HashMap<Set<BlankNode>, Set<BlankNode>>();
+ IntIterator hashIter = hashNodeMap1.keySet().intIterator();
+ while (hashIter.hasNext()) {
+ int hash = hashIter.next();
+ Set<BlankNode> nodes1 = hashNodeMap1.get(hash);
+ Set<BlankNode> nodes2 = hashNodeMap2.get(hash);
+ if (nodes1.size() != nodes2.size()) {
+ return null;
+ }
+ if (nodes1.size() != 1) {
+ matchingGroups.put(nodes1, nodes2);
+ continue;
+ }
+ final BlankNode bNode1 = nodes1.iterator().next();
+ final BlankNode bNode2 = nodes2.iterator().next();
+ matchings.put(bNode1,bNode2);
+ //in the graphs replace node occurences with grounded node,
+ BlankNodeOrIri mappedNode = new MappedNode(bNode1, bNode2);
+ replaceNode(g1,bNode1, mappedNode);
+ replaceNode(g2, bNode2, mappedNode);
+ //remove grounded triples
+ if (!Utils.removeGrounded(g1,g2)) {
+ return null;
+ }
+ }
+ Map<BlankNode, Integer> result = new HashMap<BlankNode, Integer>();
+ addInverted(result, hashNodeMap1);
+ addInverted(result, hashNodeMap2);
+ return result;
+ }
+ private static int computeHash(Set<Property> propertySet, Map<BlankNode, Integer> bNodeHashMap) {
+ int result = 0;
+ for (Property property : propertySet) {
+ result += property.hashCode(bNodeHashMap);
+ }
+ return result;
+ }
+ private static Map<BlankNode, Set<Property>> getBNodePropMap(Graph g) {
+ Set<BlankNode> bNodes = Utils.getBNodes(g);
+ Map<BlankNode, Set<Property>> result = new HashMap<BlankNode, Set<Property>>();
+ for (BlankNode bNode : bNodes) {
+ result.put(bNode, getProperties(bNode, g));
+ }
+ return result;
+ }
+ private static Set<Property> getProperties(BlankNode bNode, Graph g) {
+ Set<Property> result = new HashSet<Property>();
+ Iterator<Triple> ti = g.filter(bNode, null, null);
+ while (ti.hasNext()) {
+ Triple triple = ti.next();
+ result.add(new ForwardProperty(triple.getPredicate(), triple.getObject()));
+ }
+ ti = g.filter(null, null, bNode);
+ while (ti.hasNext()) {
+ Triple triple = ti.next();
+ result.add(new BackwardProperty(triple.getSubject(), triple.getPredicate()));
+ }
+ return result;
+ }
+ private static int nodeHash(RdfTerm resource, Map<BlankNode, Integer> bNodeHashMap) {
+ if (resource instanceof BlankNode) {
+ Integer mapValue = bNodeHashMap.get((BlankNode)resource);
+ if (mapValue == null) {
+ return 0;
+ } else {
+ return mapValue;
+ }
+ } else {
+ return resource.hashCode();
+ }
+ }
+ private static void replaceNode(Graph graph, BlankNode bNode, BlankNodeOrIri replacementNode) {
+ Set<Triple> triplesToRemove = new HashSet<Triple>();
+ for (Triple triple : graph) {
+ Triple replacementTriple = getReplacement(triple, bNode, replacementNode);
+ if (replacementTriple != null) {
+ triplesToRemove.add(triple);
+ graph.add(replacementTriple);
+ }
+ }
+ graph.removeAll(triplesToRemove);
+ }
+ private static Triple getReplacement(Triple triple, BlankNode bNode, BlankNodeOrIri replacementNode) {
+ if (triple.getSubject().equals(bNode)) {
+ if (triple.getObject().equals(bNode)) {
+ return new TripleImpl(replacementNode, triple.getPredicate(), replacementNode);
+ } else {
+ return new TripleImpl(replacementNode, triple.getPredicate(), triple.getObject());
+ }
+ } else {
+ if (triple.getObject().equals(bNode)) {
+ return new TripleImpl(triple.getSubject(), triple.getPredicate(), replacementNode);
+ } else {
+ return null;
+ }
+ }
+ }
+ private static void addInverted(Map<BlankNode, Integer> result, IntHashMap<Set<BlankNode>> hashNodeMap) {
+ for (int hash : hashNodeMap.keySet()) {
+ Set<BlankNode> bNodes = hashNodeMap.get(hash);
+ for (BlankNode bNode : bNodes) {
+ result.put(bNode, hash);
+ }
+ }
+ }
+
+ private static class BackwardProperty implements Property {
+ private BlankNodeOrIri subject;
+ private Iri predicate;
+
+ public BackwardProperty(BlankNodeOrIri subject, Iri predicate) {
+ this.subject = subject;
+ this.predicate = predicate;
+ }
+
+ @Override
+ public int hashCode(Map<BlankNode, Integer> bNodeHashMap) {
+ return 0xFF ^ predicate.hashCode() ^ nodeHash(subject, bNodeHashMap);
+ }
+
+ }
+ private static class ForwardProperty implements Property {
+ private Iri predicate;
+ private RdfTerm object;
+
+ public ForwardProperty(Iri predicate, RdfTerm object) {
+ this.predicate = predicate;
+ this.object = object;
+ }
+
+ @Override
+ public int hashCode(Map<BlankNode, Integer> bNodeHashMap) {
+ return predicate.hashCode() ^ nodeHash(object, bNodeHashMap);
+ }
+ }
+ private static class MappedNode implements BlankNodeOrIri {
+ private BlankNode bNode1, bNode2;
+
+ public MappedNode(BlankNode bNode1, BlankNode bNode2) {
+ this.bNode1 = bNode1;
+ this.bNode2 = bNode2;
+ }
+
+ }
+ private static interface Property {
+ public int hashCode(Map<BlankNode, Integer> bNodeHashMap);
+ }
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/MappingIterator.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/MappingIterator.java
new file mode 100644
index 0000000..dea95b5
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/MappingIterator.java
@@ -0,0 +1,76 @@
+package org.apache.commons.rdf.impl.utils.graphmatching;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * An iterator over all possible mapping beetween the elemnets of two sets of
+ * the same size, each mapping maps each element from set1 to a disctinct one of
+ * set2.
+ *
+ *
+ *
+ * @author reto
+ */
+class MappingIterator<T,U> implements Iterator<Map<T, U>> {
+
+ private List<T> list1;
+ private Iterator<List<U>> permutationList2Iterator;
+
+
+ public MappingIterator(Set<T> set1, Set<U> set2) {
+ if (set1.size() != set2.size()) {
+ throw new IllegalArgumentException();
+ }
+ this.list1 = new ArrayList<T>(set1);
+ permutationList2Iterator = new PermutationIterator<U>(
+ new ArrayList<U>(set2));
+ }
+
+ @Override
+ public boolean hasNext() {
+ return permutationList2Iterator.hasNext();
+ }
+
+ @Override
+ public Map<T, U> next() {
+ List<U> list2 = permutationList2Iterator.next();
+ Map<T, U> result = new HashMap<T, U>(list1.size());
+ for (int i = 0; i < list1.size(); i++) {
+ result.put(list1.get(i), list2.get(i));
+ }
+ return result;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+
+
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/PermutationIterator.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/PermutationIterator.java
new file mode 100644
index 0000000..6b6fa07
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/PermutationIterator.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.commons.rdf.impl.utils.graphmatching;
+
+
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ *
+ * An Iterator over all permuations of a list.
+ *
+ * @author reto
+ */
+class PermutationIterator<T> implements Iterator<List<T>> {
+
+ private Iterator<List<T>> restIterator;
+ private List<T> list;
+ private List<T> next;
+ int posInList = 0; //the position of the last element of next returned list
+ //with list, this is the one excluded from restIterator
+
+ PermutationIterator(List<T> list) {
+ this.list = Collections.unmodifiableList(list);
+ if (list.size() > 1) {
+ createRestList();
+ }
+ prepareNext();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return next != null;
+ }
+
+ @Override
+ public List<T> next() {
+ List<T> result = next;
+ if (result == null) {
+ throw new NoSuchElementException();
+ }
+ prepareNext();
+ return result;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Not supported");
+ }
+
+ private void createRestList() {
+ List<T> restList = new ArrayList<T>(list);
+ restList.remove(posInList);
+ restIterator = new PermutationIterator<T>(restList);
+ }
+
+ private void prepareNext() {
+ next = getNext();
+
+ }
+ private List<T> getNext() {
+ if (list.size() == 0) {
+ return null;
+ }
+ if (list.size() == 1) {
+ if (posInList++ == 0) {
+ return new ArrayList<T>(list);
+ } else {
+ return null;
+ }
+ } else {
+ if (!restIterator.hasNext()) {
+ if (posInList < (list.size()-1)) {
+ posInList++;
+ createRestList();
+ } else {
+ return null;
+ }
+ }
+ List<T> result = restIterator.next();
+ result.add(list.get(posInList));
+ return result;
+ }
+ }
+
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/Utils.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/Utils.java
new file mode 100644
index 0000000..25a7a4b
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/Utils.java
@@ -0,0 +1,82 @@
+package org.apache.commons.rdf.impl.utils.graphmatching;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ *
+*/
+
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.commons.rdf.BlankNode;
+import org.apache.commons.rdf.Triple;
+
+public class Utils {
+
+ static Set<BlankNode> getBNodes(Collection<Triple> s) {
+ Set<BlankNode> result = new HashSet<BlankNode>();
+ for (Triple triple : s) {
+ if (triple.getSubject() instanceof BlankNode) {
+ result.add((BlankNode) triple.getSubject());
+ }
+ if (triple.getObject() instanceof BlankNode) {
+ result.add((BlankNode) triple.getObject());
+ }
+ }
+ return result;
+ }
+
+ /**
+ * removes the common grounded triples from s1 and s2. returns false if
+ * a grounded triple is not in both sets, true otherwise
+ */
+ static boolean removeGrounded(Collection<Triple> s1, Collection<Triple> s2) {
+ Iterator<Triple> triplesIter = s1.iterator();
+ while (triplesIter.hasNext()) {
+ Triple triple = triplesIter.next();
+ if (!isGrounded(triple)) {
+ continue;
+ }
+ if (!s2.remove(triple)) {
+ return false;
+ }
+ triplesIter.remove();
+ }
+ //for efficiency we might skip this (redefine method)
+ for (Triple triple : s2) {
+ if (isGrounded(triple)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean isGrounded(Triple triple) {
+ if (triple.getSubject() instanceof BlankNode) {
+ return false;
+ }
+ if (triple.getObject() instanceof BlankNode) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/collections/IntHashMap.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/collections/IntHashMap.java
new file mode 100644
index 0000000..922ae47
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/collections/IntHashMap.java
@@ -0,0 +1,377 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ *
+ * 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.
+ */
+
+/*
+ * Note: originally released under the GNU LGPL v2.1,
+ * but rereleased by the original author under the ASF license (above).
+ */
+
+package org.apache.commons.rdf.impl.utils.graphmatching.collections;
+
+
+
+/**
+ * <p>A hash map that uses primitive ints for the key rather than objects.</p>
+ *
+ * <p>Note that this class is for internal optimization purposes only, and may
+ * not be supported in future releases of Jakarta Commons Lang. Utilities of
+ * this sort may be included in future releases of Jakarta Commons Collections.</p>
+ *
+ * @author Justin Couch
+ * @author Alex Chaffee (alex@apache.org)
+ * @author Stephen Colebourne
+ * @since 2.0
+ * @version $Revision: 1.2 $
+ * @see java.util.HashMap
+ */
+public class IntHashMap<T> {
+
+
+ private IntSet keySet = new IntHashSet();
+
+ /**
+ * The hash table data.
+ */
+ private transient Entry<T> table[];
+
+ /**
+ * The total number of entries in the hash table.
+ */
+ private transient int count;
+
+ /**
+ * The table is rehashed when its size exceeds this threshold. (The
+ * value of this field is (int)(capacity * loadFactor).)
+ *
+ * @serial
+ */
+ private int threshold;
+
+ /**
+ * The load factor for the hashtable.
+ *
+ * @serial
+ */
+ private float loadFactor;
+
+ /**
+ * <p>Innerclass that acts as a datastructure to create a new entry in the
+ * table.</p>
+ */
+ private static class Entry<T> {
+ int hash;
+ int key;
+ T value;
+ Entry<T> next;
+
+ /**
+ * <p>Create a new entry with the given values.</p>
+ *
+ * @param hash The code used to hash the object with
+ * @param key The key used to enter this in the table
+ * @param value The value for this key
+ * @param next A reference to the next entry in the table
+ */
+ protected Entry(int hash, int key, T value, Entry<T> next) {
+ this.hash = hash;
+ this.key = key;
+ this.value = value;
+ this.next = next;
+ }
+ }
+
+ /**
+ * <p>Constructs a new, empty hashtable with a default capacity and load
+ * factor, which is <code>20</code> and <code>0.75</code> respectively.</p>
+ */
+ public IntHashMap() {
+ this(20, 0.75f);
+ }
+
+ /**
+ * <p>Constructs a new, empty hashtable with the specified initial capacity
+ * and default load factor, which is <code>0.75</code>.</p>
+ *
+ * @param initialCapacity the initial capacity of the hashtable.
+ * @throws IllegalArgumentException if the initial capacity is less
+ * than zero.
+ */
+ public IntHashMap(int initialCapacity) {
+ this(initialCapacity, 0.75f);
+ }
+
+ /**
+ * <p>Constructs a new, empty hashtable with the specified initial
+ * capacity and the specified load factor.</p>
+ *
+ * @param initialCapacity the initial capacity of the hashtable.
+ * @param loadFactor the load factor of the hashtable.
+ * @throws IllegalArgumentException if the initial capacity is less
+ * than zero, or if the load factor is nonpositive.
+ */
+ public IntHashMap(int initialCapacity, float loadFactor) {
+ super();
+ if (initialCapacity < 0) {
+ throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
+ }
+ if (loadFactor <= 0) {
+ throw new IllegalArgumentException("Illegal Load: " + loadFactor);
+ }
+ if (initialCapacity == 0) {
+ initialCapacity = 1;
+ }
+
+ this.loadFactor = loadFactor;
+ table = new Entry[initialCapacity];
+ threshold = (int) (initialCapacity * loadFactor);
+ }
+
+ /**
+ * <p>Returns the number of keys in this hashtable.</p>
+ *
+ * @return the number of keys in this hashtable.
+ */
+ public int size() {
+ return count;
+ }
+
+ /**
+ * <p>Tests if this hashtable maps no keys to values.</p>
+ *
+ * @return <code>true</code> if this hashtable maps no keys to values;
+ * <code>false</code> otherwise.
+ */
+ public boolean isEmpty() {
+ return count == 0;
+ }
+
+ /**
+ * <p>Tests if some key maps into the specified value in this hashtable.
+ * This operation is more expensive than the <code>containsKey</code>
+ * method.</p>
+ *
+ * <p>Note that this method is identical in functionality to containsValue,
+ * (which is part of the Map interface in the collections framework).</p>
+ *
+ * @param value a value to search for.
+ * @return <code>true</code> if and only if some key maps to the
+ * <code>value</code> argument in this hashtable as
+ * determined by the <tt>equals</tt> method;
+ * <code>false</code> otherwise.
+ * @throws NullPointerException if the value is <code>null</code>.
+ * @see #containsKey(int)
+ * @see #containsValue(Object)
+ * @see java.util.Map
+ */
+ public boolean contains(Object value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+
+ Entry tab[] = table;
+ for (int i = tab.length; i-- > 0;) {
+ for (Entry e = tab[i]; e != null; e = e.next) {
+ if (e.value.equals(value)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * <p>Returns <code>true</code> if this HashMap maps one or more keys
+ * to this value.</p>
+ *
+ * <p>Note that this method is identical in functionality to contains
+ * (which predates the Map interface).</p>
+ *
+ * @param value value whose presence in this HashMap is to be tested.
+ * @see java.util.Map
+ * @since JDK1.2
+ */
+ public boolean containsValue(Object value) {
+ return contains(value);
+ }
+
+ /**
+ * <p>Tests if the specified object is a key in this hashtable.</p>
+ *
+ * @param key possible key.
+ * @return <code>true</code> if and only if the specified object is a
+ * key in this hashtable, as determined by the <tt>equals</tt>
+ * method; <code>false</code> otherwise.
+ * @see #contains(Object)
+ */
+ public boolean containsKey(int key) {
+ Entry tab[] = table;
+ int hash = key;
+ int index = (hash & 0x7FFFFFFF) % tab.length;
+ for (Entry e = tab[index]; e != null; e = e.next) {
+ if (e.hash == hash) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * <p>Returns the value to which the specified key is mapped in this map.</p>
+ *
+ * @param key a key in the hashtable.
+ * @return the value to which the key is mapped in this hashtable;
+ * <code>null</code> if the key is not mapped to any value in
+ * this hashtable.
+ * @see #put(int, Object)
+ */
+ public T get(int key) {
+ Entry<T> tab[] = table;
+ int hash = key;
+ int index = (hash & 0x7FFFFFFF) % tab.length;
+ for (Entry<T> e = tab[index]; e != null; e = e.next) {
+ if (e.hash == hash) {
+ return e.value;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * <p>Increases the capacity of and internally reorganizes this
+ * hashtable, in order to accommodate and access its entries more
+ * efficiently.</p>
+ *
+ * <p>This method is called automatically when the number of keys
+ * in the hashtable exceeds this hashtable's capacity and load
+ * factor.</p>
+ */
+ protected void rehash() {
+ int oldCapacity = table.length;
+ Entry<T> oldMap[] = table;
+
+ int newCapacity = oldCapacity * 2 + 1;
+ Entry<T> newMap[] = new Entry[newCapacity];
+
+ threshold = (int) (newCapacity * loadFactor);
+ table = newMap;
+
+ for (int i = oldCapacity; i-- > 0;) {
+ for (Entry<T> old = oldMap[i]; old != null;) {
+ Entry<T> e = old;
+ old = old.next;
+
+ int index = (e.hash & 0x7FFFFFFF) % newCapacity;
+ e.next = newMap[index];
+ newMap[index] = e;
+ }
+ }
+ }
+
+ /**
+ * <p>Maps the specified <code>key</code> to the specified
+ * <code>value</code> in this hashtable. The key cannot be
+ * <code>null</code>. </p>
+ *
+ * <p>The value can be retrieved by calling the <code>get</code> method
+ * with a key that is equal to the original key.</p>
+ *
+ * @param key the hashtable key.
+ * @param value the value.
+ * @return the previous value of the specified key in this hashtable,
+ * or <code>null</code> if it did not have one.
+ * @throws NullPointerException if the key is <code>null</code>.
+ * @see #get(int)
+ */
+ public Object put(int key, T value) {
+ keySet.add(key);
+ // Makes sure the key is not already in the hashtable.
+ Entry<T> tab[] = table;
+ int hash = key;
+ int index = (hash & 0x7FFFFFFF) % tab.length;
+ for (Entry<T> e = tab[index]; e != null; e = e.next) {
+ if (e.hash == hash) {
+ T old = e.value;
+ e.value = value;
+ return old;
+ }
+ }
+
+ if (count >= threshold) {
+ // Rehash the table if the threshold is exceeded
+ rehash();
+
+ tab = table;
+ index = (hash & 0x7FFFFFFF) % tab.length;
+ }
+
+ // Creates the new entry.
+ Entry<T> e = new Entry<T>(hash, key, value, tab[index]);
+ tab[index] = e;
+ count++;
+ return null;
+ }
+
+ /**
+ * <p>Removes the key (and its corresponding value) from this
+ * hashtable.</p>
+ *
+ * <p>This method does nothing if the key is not present in the
+ * hashtable.</p>
+ *
+ * @param key the key that needs to be removed.
+ * @return the value to which the key had been mapped in this hashtable,
+ * or <code>null</code> if the key did not have a mapping.
+ */
+ /*public Object remove(int key) {
+ Entry tab[] = table;
+ int hash = key;
+ int index = (hash & 0x7FFFFFFF) % tab.length;
+ for (Entry e = tab[index], prev = null; e != null; prev = e, e = e.next) {
+ if (e.hash == hash) {
+ if (prev != null) {
+ prev.next = e.next;
+ } else {
+ tab[index] = e.next;
+ }
+ count--;
+ Object oldValue = e.value;
+ e.value = null;
+ return oldValue;
+ }
+ }
+ return null;
+ }*/
+
+ /**
+ * <p>Clears this hashtable so that it contains no keys.</p>
+ */
+ public synchronized void clear() {
+ keySet.clear();
+ Entry tab[] = table;
+ for (int index = tab.length; --index >= 0;) {
+ tab[index] = null;
+ }
+ count = 0;
+ }
+
+ public IntSet keySet() {
+ return keySet;
+ }
+
+
+
+}
+
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/collections/IntHashSet.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/collections/IntHashSet.java
new file mode 100644
index 0000000..4dd92b1
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/collections/IntHashSet.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.rdf.impl.utils.graphmatching.collections;
+
+import java.util.HashSet;
+import java.util.Iterator;
+
+/**
+ * This is currently just a placeholder implementation based onm HashSet<Integer>
+ * an efficient implementation is to store the primitives directly.
+ *
+ * @author reto
+ */
+public class IntHashSet extends HashSet<Integer> implements IntSet {
+
+ @Override
+ public IntIterator intIterator() {
+ final Iterator<Integer> base = iterator();
+ return new IntIterator() {
+
+ @Override
+ public int nextInt() {
+ return base.next();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return base.hasNext();
+ }
+
+ @Override
+ public Integer next() {
+ return base.next();
+ }
+
+ @Override
+ public void remove() {
+ base.remove();
+ }
+ };
+ }
+
+ @Override
+ public void add(int i) {
+ super.add((Integer)i);
+ }
+
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/collections/IntIterator.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/collections/IntIterator.java
new file mode 100644
index 0000000..050cf82
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/collections/IntIterator.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.rdf.impl.utils.graphmatching.collections;
+
+import java.util.Iterator;
+
+
+/**
+ * An iterator allowing to iterate over ints, Iterator<Integer> is extended for
+ * compatibility, however accessing nextInt allows faster implementations.
+ *
+ * @author reto
+ */
+public interface IntIterator extends Iterator<Integer> {
+ public int nextInt();
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/collections/IntSet.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/collections/IntSet.java
new file mode 100644
index 0000000..5c3e465
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/graphmatching/collections/IntSet.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2002-2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.rdf.impl.utils.graphmatching.collections;
+
+import java.util.Set;
+
+/**
+ * A IntSet allows directly adding primitive ints to a set, Set<Integer> is
+ * extended, but accessingt he respective methods is less efficient.
+ *
+ * @author reto
+ */
+public interface IntSet extends Set<Integer> {
+ /**
+ *
+ * @return an iterator over the primitive int
+ */
+ public IntIterator intIterator();
+
+ public void add(int i);
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/package-info.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/package-info.java
new file mode 100644
index 0000000..a1fa1c5
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+/**
+ * Common RDF API Implementation utilities.
+ */
+package org.apache.commons.rdf.impl.utils;
\ No newline at end of file
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/simple/SimpleGraph.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/simple/SimpleGraph.java
new file mode 100644
index 0000000..9b60a15
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/simple/SimpleGraph.java
@@ -0,0 +1,218 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf.impl.utils.simple;
+
+import org.apache.commons.rdf.impl.utils.AbstractGraph;
+import java.lang.ref.SoftReference;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.commons.rdf.BlankNodeOrIri;
+import org.apache.commons.rdf.ImmutableGraph;
+import org.apache.commons.rdf.RdfTerm;
+import org.apache.commons.rdf.Triple;
+import org.apache.commons.rdf.Iri;
+
+/**
+ * For now this is a minimalistic implementation, without any indexes or other
+ * optimizations.
+ *
+ * @author reto
+ */
+public class SimpleGraph extends AbstractGraph {
+
+ final Set<Triple> triples;
+
+ private boolean checkConcurrency = false;
+
+ class SimpleIterator implements Iterator<Triple> {
+
+ private Iterator<Triple> listIter;
+ private boolean isValid = true;
+
+ public SimpleIterator(Iterator<Triple> listIter) {
+ this.listIter = listIter;
+ }
+ private Triple currentNext;
+
+ @Override
+ public boolean hasNext() {
+ checkValidity();
+ return listIter.hasNext();
+ }
+
+ @Override
+ public Triple next() {
+ checkValidity();
+ currentNext = listIter.next();
+ return currentNext;
+ }
+
+ @Override
+ public void remove() {
+ checkValidity();
+ listIter.remove();
+ triples.remove(currentNext);
+ invalidateIterators(this);
+ }
+
+ private void checkValidity() throws ConcurrentModificationException {
+ if (checkConcurrency && !isValid) {
+ throw new ConcurrentModificationException();
+ }
+ }
+
+ private void invalidate() {
+ isValid = false;
+ }
+ }
+
+ private final Set<SoftReference<SimpleIterator>> iterators =
+ Collections.synchronizedSet(new HashSet<SoftReference<SimpleIterator>>());
+
+ /**
+ * Creates an empty SimpleGraph
+ */
+ public SimpleGraph() {
+ triples = Collections.synchronizedSet(new HashSet<Triple>());
+ }
+
+ /**
+ * Creates a SimpleGraph using the passed iterator, the iterator
+ * is consumed before the constructor returns
+ *
+ * @param iterator
+ */
+ public SimpleGraph(Iterator<Triple> iterator) {
+ triples = new HashSet<Triple>();
+ while (iterator.hasNext()) {
+ Triple triple = iterator.next();
+ triples.add(triple);
+ }
+ }
+
+ /**
+ * Creates a SimpleGraph for the specified set of triples,
+ * subsequent modification of baseSet do affect the created instance.
+ *
+ * @param baseSet
+ */
+ public SimpleGraph(Set<Triple> baseSet) {
+ this.triples = baseSet;
+ }
+
+ /**
+ * Creates a SimpleGraph for the specified collection of triples,
+ * subsequent modification of baseSet do not affect the created instance.
+ *
+ * @param baseSet
+ */
+ public SimpleGraph(Collection<Triple> baseCollection) {
+ this.triples = new HashSet<Triple>(baseCollection);
+ }
+
+ @Override
+ public int performSize() {
+ return triples.size();
+ }
+
+ @Override
+ public Iterator<Triple> performFilter(final BlankNodeOrIri subject, final Iri predicate, final RdfTerm object) {
+ final List<Triple> tripleList = new ArrayList<Triple>();
+ synchronized (triples) {
+ Iterator<Triple> baseIter = triples.iterator();
+ while (baseIter.hasNext()) {
+ Triple triple = baseIter.next();
+ if ((subject != null)
+ && (!triple.getSubject().equals(subject))) {
+ continue;
+ }
+ if ((predicate != null)
+ && (!triple.getPredicate().equals(predicate))) {
+ continue;
+ }
+ if ((object != null)
+ && (!triple.getObject().equals(object))) {
+ continue;
+ }
+ tripleList.add(triple);
+ }
+
+ final Iterator<Triple> listIter = tripleList.iterator();
+ SimpleIterator resultIter = new SimpleIterator(listIter);
+ if (checkConcurrency) {
+ iterators.add(new SoftReference<SimpleIterator>(resultIter));
+ }
+ return resultIter;
+ }
+ }
+
+
+ @Override
+ public boolean performAdd(Triple e) {
+ boolean modified = triples.add(e);
+ if (modified) {
+ invalidateIterators(null);
+ }
+ return modified;
+ }
+
+ private void invalidateIterators(SimpleIterator caller) {
+ if (!checkConcurrency) {
+ return;
+ }
+ Set<SoftReference> oldReferences = new HashSet<SoftReference>();
+ synchronized(iterators) {
+ for (SoftReference<SimpleGraph.SimpleIterator> softReference : iterators) {
+ SimpleIterator simpleIterator = softReference.get();
+ if (simpleIterator == null) {
+ oldReferences.add(softReference);
+ continue;
+ }
+ if (simpleIterator != caller) {
+ simpleIterator.invalidate();
+ }
+ }
+ }
+ iterators.removeAll(oldReferences);
+ }
+
+ /**
+ * Specifies whether or not to throw <code>ConcurrentModificationException</code>s,
+ * if this simple triple collection is modified concurrently. Concurrency
+ * check is set to false by default.
+ *
+ * @param bool Specifies whether or not to check concurrent modifications.
+ */
+ public void setCheckConcurrency(boolean bool) {
+ checkConcurrency = bool;
+ }
+
+
+ @Override
+ public ImmutableGraph getImmutableGraph() {
+ return new SimpleImmutableGraph(this);
+ }
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/simple/SimpleImmutableGraph.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/simple/SimpleImmutableGraph.java
new file mode 100644
index 0000000..bc50a09
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/simple/SimpleImmutableGraph.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf.impl.utils.simple;
+
+import org.apache.commons.rdf.impl.utils.AbstractImmutableGraph;
+import java.util.Iterator;
+
+import org.apache.commons.rdf.BlankNodeOrIri;
+import org.apache.commons.rdf.RdfTerm;
+import org.apache.commons.rdf.Triple;
+import org.apache.commons.rdf.Graph;
+import org.apache.commons.rdf.Iri;
+
+/**
+ *
+ * @author reto
+ */
+public class SimpleImmutableGraph extends AbstractImmutableGraph {
+
+ private Graph graph;
+
+ /**
+ * Creates a ImmutableGraph with the triples in Graph
+ *
+ * @param Graph the collection of triples this ImmutableGraph shall consist of
+ */
+ public SimpleImmutableGraph(Graph Graph) {
+ this.graph = new SimpleGraph(Graph.iterator());
+ }
+
+ /**
+ * Creates a ImmutableGraph with the triples in Graph.
+ *
+ * This construction allows to specify if the Graph might change
+ * in future. If GraphWillNeverChange is set to true it will
+ * assume that the collection never changes, in this case the collection
+ * isn't copied making things more efficient.
+ *
+ * @param Graph the collection of triples this ImmutableGraph shall consist of
+ * @param GraphWillNeverChange true if the caller promises Graph will never change
+ */
+ public SimpleImmutableGraph(Graph Graph, boolean GraphWillNeverChange) {
+ if (!GraphWillNeverChange) {
+ this.graph = new SimpleGraph(Graph.iterator());
+ } else {
+ this.graph = Graph;
+ }
+ }
+
+ public SimpleImmutableGraph(Iterator<Triple> tripleIter) {
+ this.graph = new SimpleGraph(tripleIter);
+ }
+
+ @Override
+ public int performSize() {
+ return graph.size();
+ }
+
+ @Override
+ public Iterator<Triple> performFilter(BlankNodeOrIri subject, Iri predicate, RdfTerm object) {
+ return graph.filter(subject, predicate, object);
+ }
+}
diff --git a/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/simple/SimpleMGraph.java b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/simple/SimpleMGraph.java
new file mode 100644
index 0000000..8d0a5ce
--- /dev/null
+++ b/impl.utils/src/main/java/org/apache/commons/rdf/impl/utils/simple/SimpleMGraph.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf.impl.utils.simple;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.commons.rdf.ImmutableGraph;
+import org.apache.commons.rdf.Graph;
+import org.apache.commons.rdf.Triple;
+
+/**
+ *
+ * @deprecated Use SimpleGraph
+ * @author reto
+ */
+@Deprecated
+public class SimpleMGraph extends SimpleGraph implements Graph {
+
+ /**
+ * Creates an empty SimpleMGraph
+ */
+ public SimpleMGraph() {
+ }
+
+ public SimpleMGraph(Set<Triple> baseSet) {
+ super(baseSet);
+ }
+
+ public SimpleMGraph(Collection<Triple> baseCollection) {
+ super(baseCollection);
+ }
+
+ public SimpleMGraph(Iterator<Triple> iterator) {
+ super(iterator);
+ }
+
+}
+
+
\ No newline at end of file
diff --git a/impl.utils/src/test/java/org/apache/commons/rdf/impl/utils/simple/PlainLiteralImplTest.java b/impl.utils/src/test/java/org/apache/commons/rdf/impl/utils/simple/PlainLiteralImplTest.java
new file mode 100644
index 0000000..2782f45
--- /dev/null
+++ b/impl.utils/src/test/java/org/apache/commons/rdf/impl/utils/simple/PlainLiteralImplTest.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf.impl.utils.simple;
+
+import org.apache.commons.rdf.impl.utils.PlainLiteralImpl;
+import org.junit.Test;
+
+import org.apache.commons.rdf.Language;
+import org.apache.commons.rdf.Literal;
+import org.junit.Assert;
+/**
+ *
+ * @author reto
+ *
+ */
+
+public class PlainLiteralImplTest {
+
+
+ @Test public void plainLiteralEquality() {
+ String stringValue = "some text";
+ Literal literal1 = new PlainLiteralImpl(stringValue);
+ Literal literal2 = new PlainLiteralImpl(stringValue);
+ Assert.assertEquals(literal1, literal2);
+ Assert.assertEquals(literal1.hashCode(), literal2.hashCode());
+ Literal literal3 = new PlainLiteralImpl("something else");
+ Assert.assertFalse(literal1.equals(literal3));
+ }
+
+ @Test public void languageLiteralEquality() {
+ String stringValue = "some text";
+ Language lang = new Language("en-ca");
+ Literal literal1 = new PlainLiteralImpl(stringValue, lang);
+ Literal literal2 = new PlainLiteralImpl(stringValue, lang);
+ Assert.assertEquals(literal1, literal2);
+ Assert.assertEquals(literal1.hashCode(), literal2.hashCode());
+ Language lang2 = new Language("de");
+ Literal literal3 = new PlainLiteralImpl(stringValue, lang2);
+ Assert.assertFalse(literal1.equals(literal3));
+ Literal literal4 = new PlainLiteralImpl(stringValue, null);
+ Assert.assertFalse(literal3.equals(literal4));
+ Assert.assertFalse(literal4.equals(literal3));
+ }
+
+ /**
+ * hashCode of the lexical form plus the hashCode of the locale
+ */
+ @Test public void checkHashCode() {
+ String stringValue = "some text";
+ Language language = new Language("en");
+ Literal literal = new PlainLiteralImpl(stringValue, language);
+ Assert.assertEquals(literal.getDataType().hashCode() + stringValue.hashCode() + language.hashCode(), literal.hashCode());
+ }
+
+}
diff --git a/impl.utils/src/test/java/org/apache/commons/rdf/impl/utils/simple/SimpleGraphTest.java b/impl.utils/src/test/java/org/apache/commons/rdf/impl/utils/simple/SimpleGraphTest.java
new file mode 100644
index 0000000..a1e8d54
--- /dev/null
+++ b/impl.utils/src/test/java/org/apache/commons/rdf/impl/utils/simple/SimpleGraphTest.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf.impl.utils.simple;
+
+import org.apache.commons.rdf.impl.utils.TripleImpl;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import org.junit.Assert;
+import org.junit.Test;
+import org.apache.commons.rdf.Triple;
+import org.apache.commons.rdf.Iri;
+import org.apache.commons.rdf.impl.utils.simple.SimpleGraph;
+
+/**
+ *
+ * @author mir
+ */
+public class SimpleGraphTest {
+
+ private Iri uriRef1 = new Iri("http://example.org/foo");
+ private Iri uriRef2 = new Iri("http://example.org/bar");
+ private Iri uriRef3 = new Iri("http://example.org/test");
+ private Triple triple1 = new TripleImpl(uriRef1, uriRef2, uriRef3);
+ private Triple triple2 = new TripleImpl(uriRef2, uriRef2, uriRef1);
+ private Triple triple3 = new TripleImpl(uriRef3, uriRef1, uriRef3);
+ private Triple triple4 = new TripleImpl(uriRef1, uriRef3, uriRef2);
+ private Triple triple5 = new TripleImpl(uriRef2, uriRef3, uriRef2);
+
+ @Test
+ public void iteratorRemove() {
+ SimpleGraph stc = new SimpleGraph();
+ stc.add(triple1);
+ stc.add(triple2);
+ stc.add(triple3);
+ stc.add(triple4);
+ stc.add(triple5);
+ Iterator<Triple> iter = stc.iterator();
+ while (iter.hasNext()) {
+ Triple triple = iter.next();
+ iter.remove();
+ }
+ Assert.assertEquals(0, stc.size());
+ }
+
+ @Test
+ public void removeAll() {
+ SimpleGraph stc = new SimpleGraph();
+ stc.add(triple1);
+ stc.add(triple2);
+ stc.add(triple3);
+ stc.add(triple4);
+ stc.add(triple5);
+ SimpleGraph stc2 = new SimpleGraph();
+ stc2.add(triple1);
+ stc2.add(triple3);
+ stc2.add(triple5);
+ stc.removeAll(stc2);
+ Assert.assertEquals(2, stc.size());
+ }
+
+ @Test
+ public void filterIteratorRemove() {
+ SimpleGraph stc = new SimpleGraph();
+ stc.add(triple1);
+ stc.add(triple2);
+ stc.add(triple3);
+ stc.add(triple4);
+ stc.add(triple5);
+ Iterator<Triple> iter = stc.filter(uriRef1, null, null);
+ while (iter.hasNext()) {
+ Triple triple = iter.next();
+ iter.remove();
+ }
+ Assert.assertEquals(3, stc.size());
+ }
+
+ @Test(expected=ConcurrentModificationException.class)
+ public void remove() {
+ SimpleGraph stc = new SimpleGraph();
+ stc.setCheckConcurrency(true);
+ stc.add(triple1);
+ stc.add(triple2);
+ stc.add(triple3);
+ stc.add(triple4);
+ stc.add(triple5);
+ Iterator<Triple> iter = stc.filter(uriRef1, null, null);
+ while (iter.hasNext()) {
+ Triple triple = iter.next();
+ stc.remove(triple);
+ }
+ Assert.assertEquals(3, stc.size());
+ }
+}
diff --git a/impl.utils/src/test/java/org/apache/commons/rdf/impl/utils/simple/TripleImplTest.java b/impl.utils/src/test/java/org/apache/commons/rdf/impl/utils/simple/TripleImplTest.java
new file mode 100644
index 0000000..dd2f967
--- /dev/null
+++ b/impl.utils/src/test/java/org/apache/commons/rdf/impl/utils/simple/TripleImplTest.java
@@ -0,0 +1,57 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.apache.commons.rdf.impl.utils.simple;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ *
+*/
+
+
+import org.junit.Test;
+import junit.framework.Assert;
+
+import org.apache.commons.rdf.BlankNodeOrIri;
+import org.apache.commons.rdf.RdfTerm;
+import org.apache.commons.rdf.Triple;
+import org.apache.commons.rdf.Iri;
+import org.apache.commons.rdf.impl.utils.PlainLiteralImpl;
+import org.apache.commons.rdf.impl.utils.TripleImpl;
+/**
+ *
+ * @author reto
+ *
+ */
+
+public class TripleImplTest {
+
+
+ @Test public void tripleEquality() {
+ BlankNodeOrIri subject = new Iri("http://example.org/");
+ Iri predicate = new Iri("http://example.org/property");
+ RdfTerm object = new PlainLiteralImpl("property value");
+ Triple triple1 = new TripleImpl(subject, predicate, object);
+ Triple triple2 = new TripleImpl(subject, predicate, object);
+ Assert.assertEquals(triple1.hashCode(), triple2.hashCode());
+ Assert.assertEquals(triple1, triple2);
+ }
+
+}
diff --git a/impl.utils/src/test/java/org/apache/commons/rdf/impl/utils/simple/TypedLiteralImplTest.java b/impl.utils/src/test/java/org/apache/commons/rdf/impl/utils/simple/TypedLiteralImplTest.java
new file mode 100644
index 0000000..515cf93
--- /dev/null
+++ b/impl.utils/src/test/java/org/apache/commons/rdf/impl/utils/simple/TypedLiteralImplTest.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.rdf.impl.utils.simple;
+
+import org.apache.commons.rdf.impl.utils.TypedLiteralImpl;
+import org.junit.Test;
+import junit.framework.Assert;
+
+import org.apache.commons.rdf.Iri;
+import org.apache.commons.rdf.Literal;
+/**
+ *
+ * @author reto/**
+ *
+ * @author reto/**
+ *
+ * @author reto/**
+ *
+ * @author reto
+ *
+ */
+
+public class TypedLiteralImplTest {
+
+
+ @Test public void typedLiteralEquality() {
+ String stringValue = "some text";
+ Iri uriRef = new Iri("http://example.org/datatypes/magic");
+ Literal literal1 = new TypedLiteralImpl(stringValue, uriRef);
+ Literal literal2 = new TypedLiteralImpl(stringValue, uriRef);
+ Assert.assertEquals(literal1, literal2);
+ Assert.assertEquals(literal1.hashCode(), literal2.hashCode());
+ Literal literal3 = new TypedLiteralImpl("something else", uriRef);
+ Assert.assertFalse(literal1.equals(literal3));
+ Iri uriRef2 = new Iri("http://example.org/datatypes/other");
+ Literal literal4 = new TypedLiteralImpl(stringValue, uriRef2);
+ Assert.assertFalse(literal1.equals(literal4));
+ }
+
+
+ /**
+ * The hascode is equals to the hascode of the lexical form plus the hashcode of the dataTyp
+ */
+ @Test public void checkHashCode() {
+ String stringValue = "some text";
+ Iri uriRef = new Iri("http://example.org/datatypes/magic");
+ Literal literal = new TypedLiteralImpl(stringValue, uriRef);
+ Assert.assertEquals(stringValue.hashCode() + uriRef.hashCode(), literal.hashCode());
+ }
+
+}
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..0455274
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You 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.
+
+-->
+
+<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/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-parent</artifactId>
+ <version>36</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>commons-rdf</groupId>
+ <artifactId>commons-rdf</artifactId>
+ <packaging>pom</packaging>
+ <version>0.1-SNAPSHOT</version>
+ <name>Apache Commons RDF Reactor</name>
+ <description>
+ Apache Commons RDF provides an API modelling the RDF data model as defined by
+ http://www.w3.org/TR/rdf11-concepts/
+ </description>
+ <url>http://commons.apache.org/sandbox/commons-rdf/</url>
+ <!-- TBD
+ <issueManagement>
+ <system>jira</system>
+ <url>http://issues.apache.org/jira/browse/RDF</url>
+ </issueManagement>
+ -->
+ <inceptionYear>2014</inceptionYear>
+ <scm>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/rdf/trunk</connection>
+ <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/rdf/trunk</developerConnection>
+ <url>http://svn.apache.org/viewvc/commons/proper/rdf/trunk</url>
+ </scm>
+
+
+ <distributionManagement>
+ <site>
+ <id>apache.website</id>
+ <name>Apache Commons Site</name>
+ <url>${commons.deployment.protocol}://people.apache.org/www/commons.apache.org/${commons.componentid}</url>
+ </site>
+ </distributionManagement>
+
+ <modules>
+ <module>api</module>
+ <module>impl.utils</module>
+ <module>impl.sparql</module>
+ </modules>
+
+</project>
diff --git a/report.xml b/report.xml
new file mode 100644
index 0000000..d64d43c
--- /dev/null
+++ b/report.xml
@@ -0,0 +1,35 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<dfxml xmloutputversion='1.0'>
+ <metadata
+ xmlns='http://afflib.org/tcpflow/'
+ xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
+ xmlns:dc='http://purl.org/dc/elements/1.1/'>
+ <dc:type>Feature Extraction</dc:type>
+ </metadata>
+ <creator version='1.0'>
+ <program>TCPFLOW</program>
+ <version>1.4.4</version>
+ <build_environment>
+ <compiler>4.8.2 (4.8.2 20140110 (prerelease) [ibm/gcc-4_8-branch merged from gcc-4_8-branch, revision 205847])</compiler>
+ <CPPFLAGS>-pthread -I/usr/local/include -D_FORTIFY_SOURCE=2 -DUTC_OFFSET=+0000 </CPPFLAGS>
+ <CFLAGS>-g -pthread -g -O3 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -MD -D_FORTIFY_SOURCE=2 -Wpointer-arith -Wmissing-declarations -Wmissing-prototypes -Wshadow -Wwrite-strings -Wcast-align -Waggregate-return -Wbad-function-cast -Wcast-qual -Wundef -Wredundant-decls -Wdisabled-optimization -Wfloat-equal -Wmultichar -Wc++-compat -Wmissing-noreturn -Wall -Wstrict-prototypes</CFLAGS>
+ <CXXFLAGS>-g -pthread -g -O3 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -std=c++11 -Wall -MD -D_FORTIFY_SOURCE=2 -Wpointer-arith -Wshadow -Wwrite-strings -Wcast-align -Wredundant-decls -Wdisabled-optimization -Wfloat-equal -Wmultichar -Wmissing-noreturn -Woverloaded-virtual -Wsign-promo -funit-at-a-time -Wstrict-null-sentinel -Weffc++ </CXXFLAGS>
+ <LDFLAGS>-L/usr/local/lib -Wl,-Bsymbolic-functions -Wl,-z,relro</LDFLAGS>
+ <LIBS>-lpcap -lcairo -lfontconfig -lfreetype -lpixman-1 -lexpat -lssl -lcrypto -lz -lssl -lcrypto </LIBS>
+ <compilation_date>2014-01-13T17:14:40</compilation_date>
+ <library name="boost" version="105400"/>
+ </build_environment>
+ <execution_environment>
+ <os_sysname>Linux</os_sysname>
+ <os_release>3.13.0-45-generic</os_release>
+ <os_version>#74-Ubuntu SMP Tue Jan 13 19:36:28 UTC 2015</os_version>
+ <host>f3addd37b525</host>
+ <arch>x86_64</arch>
+ <command_line>tcpflow -i lo -c port 3333</command_line>
+ <uid>0</uid>
+ <start_time>2015-02-15T17:15:22Z</start_time>
+ </execution_environment>
+ </creator>
+ <configuration>
+ </configuration>
+ <tdelta>0</tdelta>