diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000000..d2c4fc09ca5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+target
+.classpath
+.project
+.settings
+*.iml
+*.ipr
+*.iws
+.idea
diff --git a/HEADER.txt b/HEADER.txt
deleted file mode 100644
index 1c669de7240..00000000000
--- a/HEADER.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.
- */
\ No newline at end of file
diff --git a/LICENSE.txt b/LICENSE.txt
index d6456956733..883ab098f7f 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -200,3 +200,65 @@
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.
+
+
+APACHE JACKRABBIT SUBCOMPONENTS
+
+Apache Jackrabbit includes parts with separate copyright notices and license
+terms. Your use of these subcomponents is subject to the terms and conditions
+of the following licenses:
+
+ XPath 2.0/XQuery 1.0 Parser:
+ http://www.w3.org/2002/11/xquery-xpath-applets/xgrammar.zip
+
+ Copyright (C) 2002 World Wide Web Consortium, (Massachusetts Institute of
+ Technology, European Research Consortium for Informatics and Mathematics,
+ Keio University). All Rights Reserved.
+
+ This work is distributed under the W3C(R) Software License in the hope
+ that it will be useful, but WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ W3C(R) SOFTWARE NOTICE AND LICENSE
+ http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
+
+ This work (and included software, documentation such as READMEs, or
+ other related items) is being provided by the copyright holders under
+ the following license. By obtaining, using and/or copying this work,
+ you (the licensee) agree that you have read, understood, and will comply
+ with the following terms and conditions.
+
+ Permission to copy, modify, and distribute this software and its
+ documentation, with or without modification, for any purpose and
+ without fee or royalty is hereby granted, provided that you include
+ the following on ALL copies of the software and documentation or
+ portions thereof, including modifications:
+
+ 1. The full text of this NOTICE in a location viewable to users
+ of the redistributed or derivative work.
+
+ 2. Any pre-existing intellectual property disclaimers, notices,
+ or terms and conditions. If none exist, the W3C Software Short
+ Notice should be included (hypertext is preferred, text is
+ permitted) within the body of any redistributed or derivative code.
+
+ 3. Notice of any changes or modifications to the files, including
+ the date changes were made. (We recommend you provide URIs to the
+ location from which the code is derived.)
+
+ THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT
+ HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED,
+ INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS
+ FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR
+ DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS,
+ TRADEMARKS OR OTHER RIGHTS.
+
+ COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL
+ OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR
+ DOCUMENTATION.
+
+ The name and trademarks of copyright holders may NOT be used in
+ advertising or publicity pertaining to the software without specific,
+ written prior permission. Title to copyright in this software and
+ any associated documentation will at all times remain with
+ copyright holders.
diff --git a/NOTICE.txt b/NOTICE.txt
index 1010997e172..0dc6f68c75a 100644
--- a/NOTICE.txt
+++ b/NOTICE.txt
@@ -1,15 +1,8 @@
-This product includes software developed by
+Apache Jackrabbit
+Copyright 2014 The Apache Software Foundation
+
+This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
Based on source code originally developed by
-Day Software (http://www.day.com).
-
-This product contains a preliminary implementation of the
-Content Repository for Java Technology API, as specified by
-
- http://www.jcp.org/en/jsr/detail?id=170
-
-that is not in final form and will change in the future.
-Implementations prior to final publication of JSR 170
-are not considered compliant with JSR 170 and cannot be
-advertised as such.
+Day Software (http://www.day.com/).
diff --git a/README.txt b/README.txt
index fbda05aac4f..7e5fd9ef874 100644
--- a/README.txt
+++ b/README.txt
@@ -1,110 +1,79 @@
-=======================================================================
-Welcome to Apache Jackrabbit
-=======================================================================
+=============================================================
+Welcome to Apache Jackrabbit
+=============================================================
-License (see also LICENSE.txt)
-==============================
-
-Copyright 2004-2005 The Apache Software Foundation or its licensors,
- as applicable.
-
-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.
-
-
-Getting Started
-===============
+Apache Jackrabbit is a fully conforming implementation of the
+Content Repository for Java Technology API (JCR, specified in
+JSR 170 and 283).
-Apache Jackrabbit is an effort undergoing incubation at the
-Apache Software Foundation. Incubation is required of all newly
-accepted projects until a further review indicates that the
-infrastructure, communications, and decision making process
-have stabilized in a manner consistent with other successful
-ASF projects. While incubation status is not necessarily a
-reflection of the completeness or stability of the code, it
-does indicate that the project has yet to be fully endorsed
-by the ASF. The incubation status is recorded at
+A content repository is a hierarchical content store with support
+for structured and unstructured content, full text search,
+versioning, transactions, observation, and more.
- http://incubator.apache.org/projects/jackrabbit.html
+Apache Jackrabbit is a project of the Apache Software Foundation.
-Mailing Lists
--------------
+Building Jackrabbit
+===================
-To get involved with the Jackrabbit project, start by having a
-look at our website (link at top of page) and join our mailing
-lists by sending an empty message to
+You can build Jackrabbit like this:
- jackrabbit-dev-subscribe :at: incubator.apache.org
-and
- jackrabbit-commits-subscribe :at: incubator.apache.org
+ mvn clean install
-and the dev mailing list archives can be found at
+You need Maven 3 (or higher) with Java 6 (or higher) for the
+build. For more instructions, please see the documentation at:
- http://incubator.apache.org/mail/jackrabbit-dev/
+ http://jackrabbit.apache.org/building-jackrabbit.html
+License (see also LICENSE.txt)
+==============================
-Downloading
------------
+Collective work: Copyright 2014 The Apache Software Foundation.
-The Jackrabbit source code is available via Subversion at
+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
- https://svn.apache.org/repos/asf/incubator/jackrabbit/trunk
+ http://www.apache.org/licenses/LICENSE-2.0
-and anonymous access is available at
+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.
- http://svn.apache.org/repos/asf/incubator/jackrabbit/trunk
+Mailing Lists
+=============
-or with viewcvs at
+To get involved with the Apache Jackrabbit project, start by having a
+look at our website and joining our mailing lists. For more details about
+Jackrabbit mailing lists as well as links to list archives, please see:
- http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/
+ http://jackrabbit.apache.org/mailing-lists.html
-Once you have a copy of the source code tree, you can use Apache Maven
+Latest development
+==================
- http://maven.apache.org/
+The latest Jackrabbit source code is available via Subversion at
-to build the project. After installing Maven 1.0, be sure to download the
-latest release of the Ant plugin (1.8.1 or later) using a command like
+ https://svn.apache.org/repos/asf/jackrabbit/trunk/
- maven plugin:download -DgroupId=maven \
- -DartifactId=maven-ant-plugin -Dversion=1.8.1
+or with ViewVC at
-before running one of the maven commands listed at
+ https://svn.apache.org/viewvc/jackrabbit/trunk/
- http://maven.apache.org/start/use.html
+To checkout the main Jackrabbit source tree, run
-to build the Jackrabbit project and/or documentation.
+ svn checkout https://svn.apache.org/repos/asf/jackrabbit/trunk jackrabbit
-NOTE: JDK 1.5 users need to download xalan.jar and place it in
-$MAVEN_HOME/lib/endorsed to build the Jackrabbit sources. The
-reason for this workaround is explained in
+If you use Git, you can clone Jackrabbit with
- http://issues.apache.org/jira/browse/JCR-46
+ git clone git://git.apache.org/jackrabbit.git
Credits
=======
-who what
--------------------- -----------------------------------------------
-Roy Fielding incubation
-Stefan Guggisberg core, data model, persistence, nodetypes, misc.
-David Nuescheler architecture, api
-Dominique Pfister transactions
-Peeter Piegaze api
-Tim Reilly mavenize
-Marcel Reutegger observation, query
-Tobias Strasser versioning
-
-
-Changes
-=======
-
-See
+See http://jackrabbit.apache.org/jackrabbit-team.html for the list of
+Jackrabbit committers and main contributors.
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
new file mode 100644
index 00000000000..7ec09f4f810
--- /dev/null
+++ b/RELEASE-NOTES.txt
@@ -0,0 +1,84 @@
+Release Notes -- Apache Jackrabbit -- Version 2.13.4
+
+Introduction
+------------
+
+This is Apache Jackrabbit(TM) 2.13.4, a fully compliant implementation of the
+Content Repository for Java(TM) Technology API, version 2.0 (JCR 2.0) as
+specified in the Java Specification Request 283 (JSR 283).
+
+Apache Jackrabbit 2.13.4 is an unstable release cut directly from
+Jackrabbit trunk, with a focus on new features and other
+improvements. For production use we recommend the latest stable 2.12.x
+release.
+
+Changes in Jackrabbit 2.13.4
+----------------------------
+
+Bug
+
+ [JCR-3893] - Multiple issues with standalone 2.10.1
+ [JCR-4008] - Restore TestCachingFDS.testDeleteRecord() to fix it with disabling AsyncUpload in unit tests
+ [JCR-4015] - jackrabbit-jcr-commons JcrUtils.getOrCreateByPath fails if session is not allowed to read root
+ [JCR-4022] - populate.jsp (standalone) doesn't work due to google ajax api change
+ [JCR-4031] - AbstractLocatorFactory: typo in log message
+
+Improvement
+
+ [JCR-4018] - Consistent Async Upload Executor handling in Backend implementations
+ [JCR-4032] - Add jmx EventListenerMBean.getToString() for clearer consolidated listener stats
+
+Task
+
+ [JCR-4019] - move httpclient dependency out of parent pom
+ [JCR-4025] - Enable animal sniffer plugin
+ [JCR-4030] - Allow use of Java 7 in Jackrabbit trunk
+
+In addition to the above-mentioned changes, this release contains
+all the changes included up to the Apache Jackrabbit 2.13.3 release.
+
+For more detailed information about all the changes in this and other
+Jackrabbit releases, please see the Jackrabbit issue tracker at
+
+ https://issues.apache.org/jira/browse/JCR
+
+Release Contents
+----------------
+
+This release consists of a single source archive packaged as a zip file.
+The archive can be unpacked with the jar tool from your JDK installation.
+See the README.txt file for instructions on how to build this release.
+
+The source archive is accompanied by SHA1 and MD5 checksums and a PGP
+signature that you can use to verify the authenticity of your download.
+The public key used for the PGP signature can be found at
+https://svn.apache.org/repos/asf/jackrabbit/dist/KEYS.
+
+About Apache Jackrabbit
+-----------------------
+
+Apache Jackrabbit is a fully conforming implementation of the Content
+Repository for Java Technology API (JCR). A content repository is a
+hierarchical content store with support for structured and unstructured
+content, full text search, versioning, transactions, observation, and
+more.
+
+For more information, visit http://jackrabbit.apache.org/
+
+About The Apache Software Foundation
+------------------------------------
+
+Established in 1999, The Apache Software Foundation provides organizational,
+legal, and financial support for more than 140 freely-available,
+collaboratively-developed Open Source projects. The pragmatic Apache License
+enables individual and commercial users to easily deploy Apache software;
+the Foundation's intellectual property framework limits the legal exposure
+of its 3,800+ contributors.
+
+For more information, visit http://www.apache.org/
+
+Trademarks
+----------
+
+Apache Jackrabbit, Jackrabbit, Apache, the Apache feather logo, and the Apache
+Jackrabbit project logo are trademarks of The Apache Software Foundation.
diff --git a/ToDo.txt b/ToDo.txt
deleted file mode 100644
index a305346829b..00000000000
--- a/ToDo.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-open issues, features not yet implemented, improvements, etc.
--------------------------------------------------------------
-
-the following list is not yet categorized/prioritized, neither
-is it complete :(
-
-- provide clean abstraction for persistence grouping (nodes & properties
- that should be stored/loaded together in the persistence layer);
-- HierarchyManager: cache Path objects (key: ItemId, value: Path[]);
- update cache on hierarchy changes (move, order, remove, etc)
-- inline @todo comments: resolve/implement
-- javaDoc, javaDoc, javaDoc
-- logging: use Commons Logging (JCL) or Universal and Generic Logging Interface (UGLI)
- instead of log4j (patch supplied by manoj is available pending a JCL/UGLI decision)
-- logging: remove unnecessary output, check log categories/verbosity,
- use 'debug' whenever possible
-
\ No newline at end of file
diff --git a/applications/test/jaas.config b/applications/test/jaas.config
deleted file mode 100644
index 1fc3c365871..00000000000
--- a/applications/test/jaas.config
+++ /dev/null
@@ -1,3 +0,0 @@
-Jackrabbit {
- org.apache.jackrabbit.core.security.SimpleLoginModule required anonymousId="anonymous";
-};
\ No newline at end of file
diff --git a/applications/test/log4j.properties b/applications/test/log4j.properties
deleted file mode 100644
index e03b04c00a1..00000000000
--- a/applications/test/log4j.properties
+++ /dev/null
@@ -1,21 +0,0 @@
-# Set root logger level to DEBUG and its only appender to A1.
-log4j.rootLogger=INFO, file
-#log4j.rootLogger=DEBUG, stdout, file
-#log4j.rootLogger=ERROR, stdout, file
-
-log4j.logger.org.apache.jackrabbit.test=DEBUG
-
-# 'stdout' is set to be a ConsoleAppender.
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-
-# 'stdout' uses PatternLayout
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=%d{dd.MM.yyyy HH:mm:ss} *%-5p* [%t] %c{1}: %m (%F, line %L)\n
-
-# 'file' is set to be a FileAppender.
-log4j.appender.file=org.apache.log4j.FileAppender
-log4j.appender.file.File=jcr.log
-
-# 'file' uses PatternLayout.
-log4j.appender.file.layout=org.apache.log4j.PatternLayout
-log4j.appender.file.layout.ConversionPattern=%d{dd.MM.yyyy HH:mm:ss} *%-5p* [%t] %c{1}: %m (%F, line %L)\n
diff --git a/applications/test/repository.xml b/applications/test/repository.xml
deleted file mode 100644
index cd35dc49e6d..00000000000
--- a/applications/test/repository.xml
+++ /dev/null
@@ -1,234 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-]>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/applications/test/repository/nodetypes/custom_nodetypes.xml b/applications/test/repository/nodetypes/custom_nodetypes.xml
deleted file mode 100644
index 47d610ff5c0..00000000000
--- a/applications/test/repository/nodetypes/custom_nodetypes.xml
+++ /dev/null
@@ -1,228 +0,0 @@
-
-
-
-
-
- mix:versionable
- nt:base
-
-
-
-
-
-
-
-
-
-
- nt:base
-
-
-
-
- nt:base
-
-
-
-
- nt:base
-
-
-
-
- nt:base
-
-
-
-
- nt:base
-
-
-
-
- nt:base
-
-
-
-
- nt:base
-
-
-
-
-
-
-
- mix:versionable
- nt:base
-
-
-
-
-
-
-
- nt:base
-
-
-
-
-
- abc
- def
- ghi
-
-
-
-
- abc
- def
- ghi
-
-
-
-
-
-
- (,100)
-
-
-
-
- (,100)
-
-
-
-
-
-
- (1974-02-15T00:00:00.000Z,)
-
-
-
-
- (,1974-02-15T00:00:00.000Z)
-
-
-
-
-
-
- (100,)
-
-
-
-
- (,100)
-
-
-
-
-
-
- (100,)
-
-
-
-
- (,100)
-
-
-
-
-
-
- true
-
-
-
-
- true
-
-
-
-
-
-
- abc
-
-
-
-
- abc
-
-
-
-
-
-
- /abc
-
-
-
-
- /abc
-
-
-
-
-
-
-
- nt:base
-
-
-
- nt:base
-
-
-
-
- nt:base
-
-
-
-
-
-
-
- nt:base
- mix:referenceable
-
-
-
-
-
-
-
-
-
- nt:base
-
-
-
-
- nt:base
-
-
-
-
-
-
diff --git a/applications/test/repositoryStubImpl.properties b/applications/test/repositoryStubImpl.properties
deleted file mode 100644
index 5fe7be648f9..00000000000
--- a/applications/test/repositoryStubImpl.properties
+++ /dev/null
@@ -1,395 +0,0 @@
-#
-# This is the configuration file for the jackrabbit repository test stub.
-#
-
-# Stub implementation class
-javax.jcr.tck.repository_stub_impl=org.apache.jackrabbit.core.JackrabbitRepositoryStub
-
-# repository specific configuration
-org.apache.jackrabbit.repository.config=applications/test/repository.xml
-org.apache.jackrabbit.repository.name=repo
-org.apache.jackrabbit.repository.home=applications/test
-org.apache.jackrabbit.repository.jaas.config=applications/test/jaas.config
-
-# credential configuration
-javax.jcr.tck.superuser.name=superuser
-javax.jcr.tck.superuser.pwd=
-javax.jcr.tck.readwrite.name=user
-javax.jcr.tck.readwrite.pwd=
-javax.jcr.tck.readonly.name=anonymous
-javax.jcr.tck.readonly.pwd=
-
-# global test configuration
-javax.jcr.tck.testroot=/testroot
-javax.jcr.tck.nodetype=nt:unstructured
-javax.jcr.tck.nodename1=node1
-javax.jcr.tck.nodename2=node2
-javax.jcr.tck.nodename3=node3
-javax.jcr.tck.nodename4=node4
-javax.jcr.tck.propertyname1=prop1
-javax.jcr.tck.propertyname2=prop2
-javax.jcr.tck.workspacename=test
-
-# namespace configuration
-javax.jcr.tck.namespaces=test
-javax.jcr.tck.namespaces.test=http://www.apache.org/jackrabbit/test
-
-# sample for per test case config overriding
-# Test class: AddNodeText
-# Test method: testName
-javax.jcr.tck.AddNodeTest.testName.nodename1=myname
-
-# ==============================================================================
-# JAVAX.JCR CONFIGURATION
-# ==============================================================================
-
-# Test class: ItemDefTest
-javax.jcr.tck.ItemDefTest.testroot=/testdata
-
-# Test class: ItemReadMethodsTest
-javax.jcr.tck.ItemReadMethodsTest.testroot=/testdata
-
-# Test class: NodeReadMethodsTest
-javax.jcr.tck.NodeReadMethodsTest.testroot=/testdata
-
-# Test class: PropertyTypeTest
-javax.jcr.tck.PropertyTypeTest.testroot=/testdata
-
-# Test class: BinaryPropertyTest
-javax.jcr.tck.BinaryPropertyTest.testroot=/testdata
-
-# Test class: BooleanPropertyTest
-javax.jcr.tck.BooleanPropertyTest.testroot=/testdata
-
-# Test class: DatePropertyTest
-javax.jcr.tck.DatePropertyTest.testroot=/testdata
-
-# Test class: DoublePropertyTest
-javax.jcr.tck.DoublePropertyTest.testroot=/testdata
-
-# Test class: LongPropertyTest
-javax.jcr.tck.LongPropertyTest.testroot=/testdata
-
-# Test class: NamePropertyTest
-javax.jcr.tck.NamePropertyTest.testroot=/testdata
-
-# Test class: PathPropertyTest
-javax.jcr.tck.PathPropertyTest.testroot=/testdata
-
-# Test class: ReferencePropertyTest
-javax.jcr.tck.ReferencePropertyTest.testroot=/testdata
-
-# Test class: StringPropertyTest
-javax.jcr.tck.StringPropertyTest.testroot=/testdata
-
-# Test class: UndefinedPropertyTest
-javax.jcr.tck.UndefinedPropertyTest.testroot=/testdata
-
-# Test class: PropertyReadMethodsTest
-javax.jcr.tck.PropertyReadMethodsTest.testroot=/testdata
-
-# Test class: NodeIteratorTest
-javax.jcr.tck.NodeIteratorTest.testroot=/testdata
-
-# Test class: NodeDiscoveringNodeTypesTest
-javax.jcr.tck.NodeDiscoveringNodeTypesTest.testroot=/testdata
-
-# Test class: RepositoryDescriptorTest
-javax.jcr.tck.RepositoryDescriptorTest.testroot=/testdata
-
-# Test class: WorkspaceReadMethodsTest
-javax.jcr.tck.WorkspaceReadMethodsTest.testroot=/testdata
-
-# Test class: SessionReadMethodsTest
-javax.jcr.tck.SessionReadMethodsTest.testroot=/testdata
-
-# Test class: NamespaceRegistryReadMethodsTest
-javax.jcr.tck.NamespaceRegistryReadMethodsTest.testroot=/testdata
-
-# Test class: NamespaceRemappingTest
-javax.jcr.tck.NamespaceRemappingTest.testroot=/testdata
-
-# Test class: SessionTest
-# Test method: testMoveItemExistsException
-# nodetype that does not allow same name siblings
-javax.jcr.tck.SessionTest.testMoveItemExistsException.nodetype2=nt:folder
-# valid node type that can be added as child of nodetype2
-javax.jcr.tck.SessionTest.testMoveItemExistsException.nodetype3=nt:hierarchyNode
-
-# Test class: SessionTest
-# Test method: testSaveContstraintViolationException
-# nodetype that has a property that is mandatory but not autocreated
-javax.jcr.tck.SessionTest.testSaveContstraintViolationException.nodetype2=nt:file
-
-# Test class: SessionUUIDTest
-# node type that has a property of type PropertyType.REFERENCE
-javax.jcr.tck.SessionUUIDTest.nodetype=nt:unstructured
-# name of the property that is of type PropertyType.REFERENCE
-javax.jcr.tck.SessionUUIDTest.propertyname1=foobar
-# nodetype that has nodetype mix:referenceable assigned
-javax.jcr.tck.SessionUUIDTest.nodetype2=test:refTargetNode
-
-# Test class: SessionUUIDTest
-# Test method: testSaveMovedRefNode
-# name of the property that can be modified
-javax.jcr.tck.SessionUUIDTest.testSaveMovedRefNode.propertyname1=foobar
-
-# Test class: NodeTest
-# Test method: testAddNodeItemExistsException
-# nodetype that does not allow same name siblings and allows child nodes of
-# the same type
-javax.jcr.tck.NodeTest.testAddNodeItemExistsException.nodetype=nt:folder
-
-# Test class: NodeTest
-# Test method: testRemoveMandatoryNode
-# nodetype that has a mandatory child node definition
-javax.jcr.tck.NodeTest.testRemoveMandatoryNode.nodetype2=nt:file
-# nodetype of the mandatory child
-javax.jcr.tck.NodeTest.testRemoveMandatoryNode.nodetype3=nt:base
-# name of the mandatory node
-javax.jcr.tck.NodeTest.testRemoveMandatoryNode.nodename3=jcr:content
-
-# Test class: NodeTest
-# Test method: testSaveContstraintViolationException
-# nodetype that has a property that is mandatory but not autocreated
-javax.jcr.tck.NodeTest.testSaveContstraintViolationException.nodetype2=nt:file
-
-# Test class: NodeUUIDTest
-# node type that has a property of type PropertyType.REFERENCE
-javax.jcr.tck.NodeUUIDTest.nodetype=nt:unstructured
-# name of the property that is of type PropertyType.REFERENCE
-javax.jcr.tck.NodeUUIDTest.propertyname1=ref
-# nodetype that has nodetype mix:referenceable assigned
-javax.jcr.tck.NodeUUIDTest.nodetype2=test:refTargetNode
-
-# Test class: NodeUUIDTest
-# Test method: testSaveMovedRefNode
-# name of the property that can be modified
-javax.jcr.tck.NodeUUIDTest.testSaveMovedRefNode.propertyname1=foobar
-# nodetype that has nodetype mix:referenceable assigned
-
-# Test class: NodeOrderableChildNodesTest
-# nodetype that supports orderable child nodes
-javax.jcr.tck.NodeOrderableChildNodesTest.nodetype2=nt:unstructured
-# valid node type that can be added as child of nodetype 2
-javax.jcr.tck.NodeOrderableChildNodesTest.nodetype3=nt:unstructured
-
-# Test class: NodeOrderableChildNodesTest
-# Test method: testOrderBeforeUnsupportedRepositoryOperationException
-# nodetype that does not allow ordering of child nodes
-javax.jcr.tck.NodeOrderableChildNodesTest.testOrderBeforeUnsupportedRepositoryOperationException.nodetype2=nt:folder
-# valid node type that can be added as child of nodetype 2
-javax.jcr.tck.NodeOrderableChildNodesTest.testOrderBeforeUnsupportedRepositoryOperationException.nodetype3=nt:hierarchyNode
-
-# Test class: SetPropertyNodeTest
-# nodetype which is referenceable
-javax.jcr.tck.SetPropertyNodeTest.nodetype=test:setProperty
-
-# Test class: SetPropertyValueTest
-# property that allows multiple values
-javax.jcr.tck.SetPropertyValueTest.propertyname2=test:multiProperty
-javax.jcr.tck.SetPropertyValueTest.nodetype=test:setProperty
-
-# Test class: SetPropertyStringTest
-# property that allows multiple values
-javax.jcr.tck.SetPropertyStringTest.propertyname2=test:multiProperty
-javax.jcr.tck.SetPropertyStringTest.nodetype=test:setProperty
-
-# Test class: WorkspaceCloneSameNameSibsTest
-javax.jcr.tck.WorkspaceCloneSameNameSibsTest.sameNameSibsFalseNodeType=test:sameNameSibsFalseChildNodeDef
-javax.jcr.tck.WorkspaceCloneSameNameSibsTest.sameNameSibsTrueNodeType=nt:unstructured
-
-# Test class: WorkspaceCopyBetweenWorkspacesSameNameSibsTest
-javax.jcr.tck.WorkspaceCopyBetweenWorkspacesSameNameSibsTest.sameNameSibsFalseNodeType=test:sameNameSibsFalseChildNodeDef
-javax.jcr.tck.WorkspaceCopyBetweenWorkspacesSameNameSibsTest.sameNameSibsTrueNodeType=nt:unstructured
-
-# Test class: WorkspaceCopySameNameSibsTest
-javax.jcr.tck.WorkspaceCopySameNameSibsTest.sameNameSibsFalseNodeType=test:sameNameSibsFalseChildNodeDef
-javax.jcr.tck.WorkspaceCopySameNameSibsTest.sameNameSibsTrueNodeType=nt:unstructured
-
-# Test class: WorkspaceMoveSameNameSibsTest
-javax.jcr.tck.WorkspaceMoveSameNameSibsTest.sameNameSibsFalseNodeType=test:sameNameSibsFalseChildNodeDef
-javax.jcr.tck.WorkspaceMoveSameNameSibsTest.sameNameSibsTrueNodeType=nt:unstructured
-
-# Test class: RepositoryLoginTest
-javax.jcr.tck.RepositoryLoginTest.testroot=/testdata
-
-# Test class: ReferenceableRootNodesTest
-javax.jcr.tck.ReferenceableRootNodesTest.testroot=/testdata
-
-# Test class: ExportDocViewTest
-javax.jcr.tck.ExportDocViewTest.testroot=/testdata
-
-# ------------------------------------------------------------------------------
-# observation configuration
-# ------------------------------------------------------------------------------
-
-# Test class: AddEventListenerTest
-# Test method: testNodeType
-javax.jcr.tck.AddEventListenerTest.testNodeType.nodetype2=nt:folder
-
-# Configuration settings for the serialization.
-# Note that the serialization test tries to use as many features of the repository
-# as possible, but fails silently if a feature is not available. You have to
-# specify all of the following configuration entries, even if your repository does
-# not support the feature that is associated with them.
-
-# Root node for the example tree
-javax.jcr.tck.SerializationTest.testroot=/testdata/serialization
-
-# Node type to use for the example tree. Specify a node type that allows complex trees and all property types if possible
-javax.jcr.tck.SerializationTest.nodetype=nt:unstructured
-
-# Name of the nodes for source and target tree
-javax.jcr.tck.SerializationTest.sourceFolderName=source
-javax.jcr.tck.SerializationTest.targetFolderName=target
-javax.jcr.tck.SerializationTest.rootNodeName=test
-
-# List the properties whose values may change during serialization/deserialization. For example,
-# the UUID of a node is unique in the repository, so it will have to change when you re-import
-# a tree at a different location.
-javax.jcr.tck.SerializationTest.propertyValueMayChange= jcr:created jcr:uuid jcr:versionHistory jcr:baseVersion jcr:predecessors P_Reference
-
-# The name of the test node types. For easier diagnostics, the node types have names
-# that tell you the kind of information they store
-javax.jcr.tck.SerializationTest.nodeTypesTestNode=NodeTypes
-javax.jcr.tck.SerializationTest.mixinTypeTestNode=MixinTypes
-javax.jcr.tck.SerializationTest.propertyTypesTestNode=PropertyTypes
-javax.jcr.tck.SerializationTest.sameNameChildrenTestNode=SameNameChildren
-javax.jcr.tck.SerializationTest.multiValuePropertiesTestNode=MultiValueProperties
-javax.jcr.tck.SerializationTest.referenceableNodeTestNode=ReferenceableNode
-javax.jcr.tck.SerializationTest.orderChildrenTestNode=OrderChildren
-javax.jcr.tck.SerializationTest.namespaceTestNode=Namespace
-
-# The name of the test property types.
-javax.jcr.tck.SerializationTest.stringTestProperty=P_String
-javax.jcr.tck.SerializationTest.binaryTestProperty=P_Binary
-javax.jcr.tck.SerializationTest.dateTestProperty=P_Date
-javax.jcr.tck.SerializationTest.longTestProperty=P_Long
-javax.jcr.tck.SerializationTest.doubleTestProperty=P_Double
-javax.jcr.tck.SerializationTest.booleanTestProperty=P_Boolean
-javax.jcr.tck.SerializationTest.nameTestProperty=P_Name
-javax.jcr.tck.SerializationTest.pathTestProperty=P_Path
-javax.jcr.tck.SerializationTest.referenceTestProperty=P_Reference
-javax.jcr.tck.SerializationTest.multiValueTestProperty=P_MultiValue
-
-# Test method: testVersioningExceptionSessionFileChild
-# specified nodetype must be versionable and allow child nodes of the same type.
-javax.jcr.tck.SerializationTest.testVersioningExceptionSessionFileChild.nodetype=test:versionable
-
-# Test method: testVersioningExceptionSessionFileParent
-# specified nodetype must be versionable and allow child nodes of the same type.
-javax.jcr.tck.SerializationTest.testVersioningExceptionSessionFileParent.nodetype=test:versionable
-
-# Test class: ExportSysViewTest
-javax.jcr.tck.ExportSysViewTest.testroot=/testdata
-
-# ==============================================================================
-# JAVAX.JCR.QUERY CONFIGURATION
-# ==============================================================================
-
-# Test class: SaveTest
-# Test method: testConstraintViolationException
-# Specified node type must not allow child nodes.
-javax.jcr.tck.SaveTest.testConstraintViolationException.nodetype=nt:query
-
-# Test class: XPathQueryLevel1Test
-javax.jcr.tck.XPathQueryLevel1Test.testroot=/testdata/query
-
-# Test class: XPathDocOrderTest
-javax.jcr.tck.XPathDocOrderTest.testroot=/testdata/query
-
-# Test class: XPathPosIndexTest
-javax.jcr.tck.XPathPosIndexTest.testroot=/testdata/query
-
-# Test class: XPathOrderByTest
-javax.jcr.tck.XPathOrderByTest.testroot=/testdata/query
-
-# Test class: XPathSyntaxTest
-javax.jcr.tck.XPathSyntaxTest.testroot=/testdata/query
-
-# Test class: XPathJcrPathTest
-javax.jcr.tck.XPathJcrPathTest.testroot=/testdata
-
-# Test class: SQLQueryLevel1Test
-javax.jcr.tck.SQLQueryLevel1Test.testroot=/testdata/query
-
-# Test class: SQLSyntaxTest
-javax.jcr.tck.SQLSyntaxTest.testroot=/testdata/query
-
-# Test class: SQLOrderByTest
-javax.jcr.tck.SQLOrderByTest.testroot=/testdata/query
-
-# Test class: DerefQueryLevel1Test
-javax.jcr.tck.DerefQueryLevel1Test.testroot=/testdata
-
-# Test class: GetPropertyNamesTest
-javax.jcr.tck.GetPropertyNamesTest.testroot=/testdata
-
-# Test class: SQLJcrPathTest
-javax.jcr.tck.SQLJcrPathTest.testroot=/testdata
-
-# Test class: SQLPathTest
-javax.jcr.tck.SQLPathTest.testroot=/testdata
-
-# Test class: PredicatesTest
-javax.jcr.tck.PredicatesTest.testroot=/testdata
-
-# Test class: SimpleSelectionTest
-javax.jcr.tck.SimpleSelectionTest.testroot=/testdata
-
-# ==============================================================================
-# JAVAX.JCR.VERSIONING CONFIGURATION
-# ==============================================================================
-
-# nodetye that is versionable. if it is not, an attempt is made to create versionable nodes
-# by adding a mix:versionable mixin-type.
-# NOTE: javax.jcr.tck.nodetype must define a non-versionable nodetype!
-javax.jcr.tck.version.versionableNodeType=test:versionable
-javax.jcr.tck.version.propertyValue=aPropertyValue
-
-# testroot for the version package
-# the test root must allow versionable and non-versionable nodes being created below
-javax.jcr.tck.version.testroot=/testroot
-
-# 3 nodes (nodeName1, nodeName2, nodeName3 with nt=versionableNodeType / nt=nonVersionableNodeType will be cloned to 2nd workspace
-# nodename1 > used to persistently create versionable node below testroot
-# nodename2 > used to create second versionable node below testroot (used for restore/workspace.restore with uuid-conflict)
-# nodename3 > used to persistently create non-versionable node below testroot
-javax.jcr.tck.version.nodename1=versionableNodeName1
-javax.jcr.tck.version.nodename2=versionableNodeName2
-javax.jcr.tck.version.nodename3=nonVersionableNodeName1
-
-# nodename 4: versionabel child-node of the first versionable node with nodeName1 and nodetype 'versionableNodeType'
-# used for:
-# + creation of a node in the 2nd workspace, that does not exist in the first workspace
-# + creation of a node in the 2nd workspace, in order to test uuid-conflicts with Workspace.restore.
-# + creation of a sub-node in the default workspace, in order to test uuid-conflicts with Node.restore.
-# + NOTE: the nodetype with 'versionableNodeType' must define its children nodes to either have COPY or VERSION
-# OPV behaviour in order to successfully test Node.restore and Workspace.restore with uuid conflict.
-javax.jcr.tck.version.nodename4=childNodeName
-
-# path to existing String-properties and a new value for the property, that allows to test the indicated OPV behaviour
-javax.jcr.tck.OnParentVersionAbortTest.propertyname1=test:abortOnParentVersionProp
-javax.jcr.tck.OnParentVersionComputeTest.propertyname1=test:computeOnParentVersionProp
-javax.jcr.tck.OnParentVersionCopyTest.propertyname1=test:copyOnParentVersionProp
-javax.jcr.tck.OnParentVersionIgnoreTest.propertyname1=test:ignoreOnParentVersionProp
-javax.jcr.tck.OnParentVersionInitializeTest.propertyname1=test:initializeOnParentVersionProp
-
-# Test class: RestoreTest
-# Test method: testRestoreWithUUIDConflict
-# nodename4 must be the name of a child node with a OPV definition COPY or VERSION
-javax.jcr.tck.RestoreTest.testRestoreWithUUIDConflict.nodename4=test:versionOnParentVersion
-
-# config for nodes that show the indicated OPV behaviour:
-# nodes are added in order to test the versioning behaviour indicated by the test-class name.
-# NOTE:
-# - nodename4 is uses as name for the childnode
-# - nodetype is used as nodetype name for the childnode
-# - the specified child node is created below nodename1 with versionableNodeType
-# the versionableNodeType and/or nodename1 may be overwritten with the individual
-# testclass below.
-javax.jcr.tck.OnParentVersionCopyTest.nodename4=test:copyOnParentVersion
-javax.jcr.tck.OnParentVersionCopyTest.nodetype=nt:unstructured
-javax.jcr.tck.OnParentVersionAbortTest.nodename4=test:abortOnParentVersion
-javax.jcr.tck.OnParentVersionAbortTest.nodetype=nt:unstructured
diff --git a/applications/test/workspaces/default/workspace.xml b/applications/test/workspaces/default/workspace.xml
deleted file mode 100644
index eb5cc7fedf6..00000000000
--- a/applications/test/workspaces/default/workspace.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/applications/test/workspaces/test/workspace.xml b/applications/test/workspaces/test/workspace.xml
deleted file mode 100644
index 6cd912eefc3..00000000000
--- a/applications/test/workspaces/test/workspace.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/assembly.xml b/assembly.xml
new file mode 100644
index 00000000000..3cff072e8a6
--- /dev/null
+++ b/assembly.xml
@@ -0,0 +1,32 @@
+
+
+ src
+
+ zip
+
+
+
+ ${project.basedir}
+
+
+ **/target/**
+ **/.*/**
+
+
+
+
\ No newline at end of file
diff --git a/checkstyle-suppressions.xml b/checkstyle-suppressions.xml
deleted file mode 100644
index 3876ca316f2..00000000000
--- a/checkstyle-suppressions.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/checkstyle.xml b/checkstyle.xml
deleted file mode 100644
index 9a2d4485e83..00000000000
--- a/checkstyle.xml
+++ /dev/null
@@ -1,168 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/contrib/examples/project.xml b/contrib/examples/project.xml
deleted file mode 100644
index e14d9dba8bf..00000000000
--- a/contrib/examples/project.xml
+++ /dev/null
@@ -1,67 +0,0 @@
-
-
-
-
-
- 3
- jackrabbit-examples
- Jackrabbit Examples
- 0.16.2-dev
-
- The Apache Software Foundation
- http://incubator.apache.org/projects/jackrabbit.html
- http://incubator.apache.org/images/apache-incubator-logo.png
-
- 2005
- org.apache.jackrabbit.examples*
- /images/jackrabbitlogo.gif
-
- The Jackrabbit Examples package contains example code for illustrating
- both general JCR API usage and specific Jackrabbit features.
-
- Example code for JCR and Jackrabbit
-
- scm:subversion:http://svn.apache.org/repos/asf/incubator/jackrabbit/trunk/contrib/examples
- scm:subversion:https://svn.apache.org/repos/asf/incubator/jackrabbit/trunk/contrib/examples
- http://svn.apache.org/viewcvs
-
-
-
- The Apache Software License, Version 2.0
- /LICENSE.txt
- repo
-
-
-
-
-
- jackrabbit
- 0.16.2-dev
-
-
- jsr170
- jcr
- 0.16.2
- http://www.day.com/maven/jsr170/jars/jcr-0.16.2.jar
-
-
-
-
- src/java
-
-
diff --git a/contrib/examples/src/java/org/apache/jackrabbit/examples/FirstSteps.java b/contrib/examples/src/java/org/apache/jackrabbit/examples/FirstSteps.java
deleted file mode 100644
index ff0391e07ed..00000000000
--- a/contrib/examples/src/java/org/apache/jackrabbit/examples/FirstSteps.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.examples;
-
-import org.apache.jackrabbit.core.jndi.RegistryHelper;
-
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.Property;
-import javax.jcr.PropertyIterator;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.SimpleCredentials;
-import javax.jcr.StringValue;
-import javax.jcr.Value;
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.util.Hashtable;
-
-/**
- * The First Steps example class.
- */
-public class FirstSteps {
-
- /**
- * Run the First Steps example.
- *
- * @param args command line arguments (ignored)
- */
- public static void main(String[] args) {
- try {
- Repository repository = getRepository();
- SimpleCredentials creds = new SimpleCredentials("anonymous", "".toCharArray());
- Session session = repository.login(creds);
- Node root = session.getRootNode();
-
- System.out.println(root.getPrimaryNodeType().getName());
-
- if (!root.hasNode("testnode")) {
- System.out.println("creating testnode");
- Node node = root.addNode("testnode", "nt:unstructured");
- node.setProperty("testprop", new StringValue("Hello, World."));
- session.save();
- }
-
- if (!root.hasNode("importxml")) {
- System.out.println("importing xml");
- Node node = root.addNode("importxml", "nt:unstructured");
- InputStream xml = new FileInputStream("repotest/test.xml");
- session.importXML("/importxml", xml);
- session.save();
- }
-
- dump(root);
- } catch (Exception e) {
- System.err.println(e);
- }
- }
-
- /**
- * Creates a Repository instance to be used by the example class.
- *
- * @return repository instance
- * @throws Exception on errors
- */
- private static Repository getRepository() throws Exception {
- String configFile = "repotest/repository.xml";
- String repHomeDir = "repotest";
-
- Hashtable env = new Hashtable();
- env.put(Context.INITIAL_CONTEXT_FACTORY,
- "org.apache.jackrabbit.core.jndi.provider.DummyInitialContextFactory");
- env.put(Context.PROVIDER_URL, "localhost");
- InitialContext ctx = new InitialContext(env);
-
- RegistryHelper.registerRepository(ctx, "repo", configFile, repHomeDir, true);
- return (Repository) ctx.lookup("repo");
- }
-
- /**
- * Dumps the contents of the given node to standard output.
- *
- * @param node the node to be dumped
- * @throws RepositoryException on repository errors
- */
- public static void dump(Node node) throws RepositoryException {
- System.out.println(node.getPath());
-
- PropertyIterator properties = node.getProperties();
- while (properties.hasNext()) {
- Property property = properties.nextProperty();
- System.out.print(property.getPath() + "=");
- if (property.getDefinition().isMultiple()) {
- Value[] values = property.getValues();
- for (int i = 0; i < values.length; i++) {
- if (i > 0) {
- System.out.println(",");
- }
- System.out.println(values[i].getString());
- }
- } else {
- System.out.print(property.getString());
- }
- System.out.println();
- }
-
- NodeIterator nodes = node.getNodes();
- while (nodes.hasNext()) {
- Node child = nodes.nextNode();
- dump(child);
- }
- }
-
-}
diff --git a/contrib/jcr-rmi/HEADER.txt b/contrib/jcr-rmi/HEADER.txt
deleted file mode 100644
index 1c669de7240..00000000000
--- a/contrib/jcr-rmi/HEADER.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.
- */
\ No newline at end of file
diff --git a/contrib/jcr-rmi/LICENSE.txt b/contrib/jcr-rmi/LICENSE.txt
deleted file mode 100644
index d6456956733..00000000000
--- a/contrib/jcr-rmi/LICENSE.txt
+++ /dev/null
@@ -1,202 +0,0 @@
-
- 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/contrib/jcr-rmi/checkstyle.xml b/contrib/jcr-rmi/checkstyle.xml
deleted file mode 100644
index edd0cd76c0f..00000000000
--- a/contrib/jcr-rmi/checkstyle.xml
+++ /dev/null
@@ -1,164 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/contrib/jcr-rmi/maven.xml b/contrib/jcr-rmi/maven.xml
deleted file mode 100644
index a5f045390b7..00000000000
--- a/contrib/jcr-rmi/maven.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/contrib/jcr-rmi/project.properties b/contrib/jcr-rmi/project.properties
deleted file mode 100644
index b0669b2785f..00000000000
--- a/contrib/jcr-rmi/project.properties
+++ /dev/null
@@ -1,3 +0,0 @@
-maven.javadoc.links=http://java.sun.com/j2se/1.4.2/docs/api/,http://www.day.com/maven/jsr170/javadocs/jcr-0.16.1-pfd/
-maven.repo.remote=http://www.ibiblio.org/maven/,http://www.day.com/maven/
-maven.checkstyle.properties=checkstyle.xml
diff --git a/contrib/jcr-rmi/project.xml b/contrib/jcr-rmi/project.xml
deleted file mode 100644
index 3cf765933de..00000000000
--- a/contrib/jcr-rmi/project.xml
+++ /dev/null
@@ -1,91 +0,0 @@
-
-
-
-
-
- 2
- jcr-rmi
- JCR-RMI
- 0.16.2
- 2004
- org.apache.jackrabbit.rmi.*
-
- JCR-RMI is an independent subproject of the Jackrabbit project. It
- provides a transparent Remote Method Invocation (RMI) layer for the
- Content Repository for Java Technology API (JCR). The JCR-RMI layer
- makes it possible to access JCR content repositories across virtual
- machine boundaries. Although implemented as a contribution to the
- Jackrabbit project, the JCR-RMI layer is independent of the underlying
- JCR repository implementation.
-
- Transparent RMI layer for the JCR API.
-
-
-
- Jukka Zitting
- jukkaz
- jz@yukatan.fi
- Yukatan
-
- Java Developer
-
- +2
-
-
-
-
-
- The Apache Software License, Version 2.0
- /LICENSE.txt
- repo
-
-
-
-
-
- jsr170
- jcr
- 0.16.2
- http://www.day.com/maven/jsr170/jars/jcr-0.16.2.jar
-
-
- xerces
- xercesImpl
- 2.6.2
-
-
- easymock
- 1.1
-
-
- junit
- 3.8.1
-
-
-
-
- src/java
- src/test
-
-
- **/*TestAll.java
-
-
-
-
-
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientAdapterFactory.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientAdapterFactory.java
deleted file mode 100644
index c96f8905a8d..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientAdapterFactory.java
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.client;
-
-import javax.jcr.Item;
-import javax.jcr.NamespaceRegistry;
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.Repository;
-import javax.jcr.Session;
-import javax.jcr.Workspace;
-import javax.jcr.lock.Lock;
-import javax.jcr.nodetype.ItemDef;
-import javax.jcr.nodetype.NodeDef;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.nodetype.NodeTypeManager;
-import javax.jcr.nodetype.PropertyDef;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryManager;
-import javax.jcr.query.QueryResult;
-import javax.jcr.query.Row;
-import javax.jcr.version.Version;
-import javax.jcr.version.VersionHistory;
-
-import org.apache.jackrabbit.rmi.remote.RemoteItem;
-import org.apache.jackrabbit.rmi.remote.RemoteItemDef;
-import org.apache.jackrabbit.rmi.remote.RemoteLock;
-import org.apache.jackrabbit.rmi.remote.RemoteNamespaceRegistry;
-import org.apache.jackrabbit.rmi.remote.RemoteNode;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeDef;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeType;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeTypeManager;
-import org.apache.jackrabbit.rmi.remote.RemoteProperty;
-import org.apache.jackrabbit.rmi.remote.RemotePropertyDef;
-import org.apache.jackrabbit.rmi.remote.RemoteQuery;
-import org.apache.jackrabbit.rmi.remote.RemoteQueryManager;
-import org.apache.jackrabbit.rmi.remote.RemoteQueryResult;
-import org.apache.jackrabbit.rmi.remote.RemoteRepository;
-import org.apache.jackrabbit.rmi.remote.RemoteRow;
-import org.apache.jackrabbit.rmi.remote.RemoteSession;
-import org.apache.jackrabbit.rmi.remote.RemoteVersion;
-import org.apache.jackrabbit.rmi.remote.RemoteVersionHistory;
-import org.apache.jackrabbit.rmi.remote.RemoteWorkspace;
-
-/**
- * Default implementation of the
- * {@link org.apache.jackrabbit.rmi.client.LocalAdapterFactory LocalAdapterFactory}
- * interface. This factory uses the client adapters defined in this
- * package as the default adapter implementations. Subclasses can
- * easily override or extend the default adapters by implementing the
- * corresponding factory methods.
- *
- * @author Jukka Zitting
- * @author Philipp Koch
- */
-public class ClientAdapterFactory implements LocalAdapterFactory {
-
- /**
- * Creates and returns a {@link ClientRepository ClientRepository}
- * instance.
- *
- * {@inheritDoc}
- */
- public Repository getRepository(RemoteRepository remote) {
- return new ClientRepository(remote, this);
- }
-
- /**
- * Creates and returns a {@link ClientSession ClientSession} instance.
- *
- * {@inheritDoc}
- */
- public Session getSession(Repository repository, RemoteSession remote) {
- return new ClientSession(repository, remote, this);
- }
-
- /**
- * Creates and returns a {@link ClientWorkspace ClientWorkspace} instance.
- *
- * {@inheritDoc}
- */
- public Workspace getWorkspace(Session session, RemoteWorkspace remote) {
- return new ClientWorkspace(session, remote, this);
- }
-
- /**
- * Creates and returns a
- * {@link ClientNamespaceRegistry ClientClientNamespaceRegistry} instance.
- *
- * {@inheritDoc}
- */
- public NamespaceRegistry getNamespaceRegistry(
- RemoteNamespaceRegistry remote) {
- return new ClientNamespaceRegistry(remote, this);
- }
-
- /**
- * Creates and returns a
- * {@link ClientNodeTypeManager ClienNodeTypeManager} instance.
- *
- * {@inheritDoc}
- */
- public NodeTypeManager getNodeTypeManager(RemoteNodeTypeManager remote) {
- return new ClientNodeTypeManager(remote, this);
- }
-
- /**
- * Creates and returns a {@link ClientItem ClientItem} instance.
- *
- * {@inheritDoc}
- */
- public Item getItem(Session session, RemoteItem remote) {
- return new ClientItem(session, remote, this);
- }
-
- /**
- * Creates and returns a {@link ClientProperty ClientProperty} instance.
- *
- * {@inheritDoc}
- */
- public Property getProperty(Session session, RemoteProperty remote) {
- return new ClientProperty(session, remote, this);
- }
-
- /**
- * Creates and returns a {@link ClientNode ClientNode} instance.
- *
- * {@inheritDoc}
- */
- public Node getNode(Session session, RemoteNode remote) {
- return new ClientNode(session, remote, this);
- }
-
- /**
- * Creates and returns a {@link ClientVersion ClientVersion} instance.
- *
- * {@inheritDoc}
- */
- public Version getVersion(Session session, RemoteVersion remote) {
- return new ClientVersion(session, remote, this);
- }
-
- /**
- * Creates and returns a {@link ClientVersionHistory ClientVersionHistory}
- * instance.
- *
- * {@inheritDoc}
- */
- public VersionHistory getVersionHistory(Session session, RemoteVersionHistory remote) {
- return new ClientVersionHistory(session, remote, this);
- }
-
- /**
- * Creates and returns a {@link ClientNodeType ClientNodeType} instance.
- *
- * {@inheritDoc}
- */
- public NodeType getNodeType(RemoteNodeType remote) {
- return new ClientNodeType(remote, this);
- }
-
- /**
- * Creates and returns a {@link ClientItemDef ClientItemDef} instance.
- *
- * {@inheritDoc}
- */
- public ItemDef getItemDef(RemoteItemDef remote) {
- return new ClientItemDef(remote, this);
- }
-
- /**
- * Creates and returns a {@link ClientNodeDef ClientNodeDef} instance.
- *
- * {@inheritDoc}
- */
- public NodeDef getNodeDef(RemoteNodeDef remote) {
- return new ClientNodeDef(remote, this);
- }
-
- /**
- * Creates and returns a {@link ClientPropertyDef ClientPropertyDef}
- * instance.
- *
- * {@inheritDoc}
- */
- public PropertyDef getPropertyDef(RemotePropertyDef remote) {
- return new ClientPropertyDef(remote, this);
- }
-
- /**
- * Creates and returns a {@link ClientLock ClientLock} instance.
- *
- * {@inheritDoc}
- */
- public Lock getLock(Node node, RemoteLock remote) {
- return new ClientLock(node, remote);
- }
-
- /**
- * Creates and returns a {@link ClientQueryManager ClientQueryManager} instance.
- *
- * {@inheritDoc}
- */
- public QueryManager getQueryManager(
- Session session, RemoteQueryManager remote) {
- return new ClientQueryManager(session, remote, this);
- }
-
- /**
- * Creates and returns a {@link ClientQuery ClientQuery} instance.
- *
- * {@inheritDoc}
- */
- public Query getQuery(Session session, RemoteQuery remote) {
- return new ClientQuery(session, remote, this);
- }
-
- /**
- * Creates and returns a {@link ClientQueryResult ClientQueryResult} instance.
- *
- * {@inheritDoc}
- */
- public QueryResult getQueryResult(
- Session session, RemoteQueryResult remote) {
- return new ClientQueryResult(session, remote, this);
- }
-
- /**
- * Creates and returns a {@link ClientRow ClientRow} instance.
- *
- * {@inheritDoc}
- */
- public Row getRow(RemoteRow remote) {
- return new ClientRow(remote);
- }
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientItemDef.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientItemDef.java
deleted file mode 100644
index afa90742eea..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientItemDef.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.client;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.nodetype.ItemDef;
-import javax.jcr.nodetype.NodeType;
-
-import org.apache.jackrabbit.rmi.remote.RemoteItemDef;
-
-/**
- * Local adapter for the JCR-RMI
- * {@link org.apache.jackrabbit.rmi.remote.RemoteItemDef RemoteItemDef}
- * inteface. This class makes a remote item definition locally available using
- * the JCR {@link javax.jcr.nodetype.ItemDef ItemDef} interface. Used mainly
- * as the base class for the
- * {@link org.apache.jackrabbit.rmi.client.ClientPropertyDef ClientPropertyDef}
- * and
- * {@link org.apache.jackrabbit.rmi.client.ClientNodeDef ClientNodeDef} adapters.
- *
- * @author Jukka Zitting
- * @see javax.jcr.nodetype.ItemDef
- * @see org.apache.jackrabbit.rmi.remote.RemoteItemDef
- */
-public class ClientItemDef extends ClientObject implements ItemDef {
-
- /** The adapted remote item definition. */
- private RemoteItemDef remote;
-
- /**
- * Creates a local adapter for the given remote item definition.
- *
- * @param remote remote item definition
- * @param factory local adapter factory
- */
- public ClientItemDef(RemoteItemDef remote, LocalAdapterFactory factory) {
- super(factory);
- this.remote = remote;
- }
-
- /** {@inheritDoc} */
- public NodeType getDeclaringNodeType() {
- try {
- return getFactory().getNodeType(remote.getDeclaringNodeType());
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String getName() {
- try {
- return remote.getName();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean isAutoCreate() {
- try {
- return remote.isAutoCreate();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean isMandatory() {
- try {
- return remote.isMandatory();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public int getOnParentVersion() {
- try {
- return remote.getOnParentVersion();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean isProtected() {
- try {
- return remote.isProtected();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientLock.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientLock.java
deleted file mode 100644
index 2401da66b04..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientLock.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.client;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.lock.Lock;
-
-import org.apache.jackrabbit.rmi.remote.RemoteLock;
-
-/**
- * Local adapter for the JCR-RMI
- * {@link org.apache.jackrabbit.rmi.remote.RemoteLock RemoteLock}
- * inteface. This class makes a remote lock locally available using
- * the JCR {@link javax.jcr.lock.Lock Lock} interface.
- *
- * @author Jukka Zitting
- * @see javax.jcr.lock.Lock
- * @see org.apache.jackrabbit.rmi.remote.RemoteLock
- */
-public class ClientLock implements Lock {
-
- /** The current node. */
- private Node node;
-
- /** The adapted remote lock. */
- private RemoteLock remote;
-
- /**
- * Creates a local adapter for the given remote lock.
- *
- * @param node current node
- * @param remote remote lock
- */
- public ClientLock(Node node, RemoteLock remote) {
- this.node = node;
- this.remote = remote;
- }
-
- /**
- * Returns the owning node without contacting the remote lock.
- *
- * {@inheritDoc}
- */
- public Node getNode() {
- return node;
- }
-
- /** {@inheritDoc} */
- public String getLockOwner() {
- try {
- return remote.getLockOwner();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean isDeep() {
- try {
- return remote.isDeep();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String getLockToken() {
- try {
- return remote.getLockToken();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean isLive() {
- try {
- return remote.isLive();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void refresh() throws RepositoryException {
- try {
- remote.refresh();
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientNode.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientNode.java
deleted file mode 100644
index 46652d961ce..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientNode.java
+++ /dev/null
@@ -1,595 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.client;
-
-import java.io.InputStream;
-import java.rmi.RemoteException;
-import java.util.Calendar;
-
-import javax.jcr.BinaryValue;
-import javax.jcr.BooleanValue;
-import javax.jcr.DateValue;
-import javax.jcr.DoubleValue;
-import javax.jcr.Item;
-import javax.jcr.ItemVisitor;
-import javax.jcr.LongValue;
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.Property;
-import javax.jcr.PropertyIterator;
-import javax.jcr.ReferenceValue;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.StringValue;
-import javax.jcr.Value;
-import javax.jcr.lock.Lock;
-import javax.jcr.nodetype.NodeDef;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.version.Version;
-import javax.jcr.version.VersionHistory;
-
-import org.apache.jackrabbit.rmi.remote.RemoteLock;
-import org.apache.jackrabbit.rmi.remote.RemoteNode;
-import org.apache.jackrabbit.rmi.remote.RemoteProperty;
-import org.apache.jackrabbit.rmi.remote.SerialValue;
-
-/**
- * Local adapter for the JCR-RMI
- * {@link org.apache.jackrabbit.rmi.remote.RemoteNode RemoteNode}
- * inteface. This class makes a remote node locally available using
- * the JCR {@link javax.jcr.Node Node} interface.
- *
- * @author Jukka Zitting
- * @see javax.jcr.Node
- * @see org.apache.jackrabbit.rmi.remote.RemoteNode
- */
-public class ClientNode extends ClientItem implements Node {
-
- /** The adapted remote node. */
- private RemoteNode remote;
-
- /**
- * Creates a local adapter for the given remote node.
- *
- * @param session current session
- * @param remote remote node
- * @param factory local adapter factory
- */
- public ClientNode(
- Session session, RemoteNode remote, LocalAdapterFactory factory) {
- super(session, remote, factory);
- this.remote = remote;
- }
-
- /**
- * Returns true without contacting the remote node.
- *
- * {@inheritDoc}
- */
- public boolean isNode() {
- return true;
- }
-
- /**
- * Calls the {@link ItemVisitor#visit(Node) ItemVisitor.visit(Node)}
- * method of the given visitor. Does not contact the remote node, but
- * the visitor may invoke other methods that do contact the remote node.
- *
- * {@inheritDoc}
- */
- public void accept(ItemVisitor visitor) throws RepositoryException {
- visitor.visit(this);
- }
-
- /** {@inheritDoc} */
- public Node addNode(String path) throws RepositoryException {
- try {
- return getNode(getSession(), remote.addNode(path));
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Node addNode(String path, String type) throws RepositoryException {
- try {
- RemoteNode node = remote.addNode(path, type);
- return getNode(getSession(), node);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void orderBefore(String src, String dst) throws RepositoryException {
- try {
- remote.orderBefore(src, dst);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Property setProperty(String name, Value value)
- throws RepositoryException {
- try {
- RemoteProperty property =
- remote.setProperty(name, new SerialValue(value));
- return getFactory().getProperty(getSession(), property);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Property setProperty(String name, Value[] values)
- throws RepositoryException {
- try {
- Value[] serials = SerialValue.makeSerialValueArray(values);
- RemoteProperty property = remote.setProperty(name, serials);
- return getFactory().getProperty(getSession(), property);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Property setProperty(String name, String[] strings)
- throws RepositoryException {
- Value[] values = new Value[strings.length];
- for (int i = 0; i < strings.length; i++) {
- values[i] = new StringValue(strings[i]);
- }
- return setProperty(name, values);
- }
-
- /** {@inheritDoc} */
- public Property setProperty(String name, String value)
- throws RepositoryException {
- return setProperty(name, new StringValue(value));
- }
-
- /** {@inheritDoc} */
- public Property setProperty(String name, InputStream value)
- throws RepositoryException {
- return setProperty(name, new BinaryValue(value));
- }
-
- /** {@inheritDoc} */
- public Property setProperty(String name, boolean value)
- throws RepositoryException {
- return setProperty(name, new BooleanValue(value));
- }
-
- /** {@inheritDoc} */
- public Property setProperty(String name, double value)
- throws RepositoryException {
- return setProperty(name, new DoubleValue(value));
- }
-
- /** {@inheritDoc} */
- public Property setProperty(String name, long value)
- throws RepositoryException {
- return setProperty(name, new LongValue(value));
- }
-
- /** {@inheritDoc} */
- public Property setProperty(String name, Calendar value)
- throws RepositoryException {
- return setProperty(name, new DateValue(value));
- }
-
- /** {@inheritDoc} */
- public Property setProperty(String name, Node value)
- throws RepositoryException {
- return setProperty(name, new ReferenceValue(value));
- }
-
- /** {@inheritDoc} */
- public Node getNode(String path) throws RepositoryException {
- try {
- return getNode(getSession(), remote.getNode(path));
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public NodeIterator getNodes() throws RepositoryException {
- try {
- return getNodeIterator(getSession(), remote.getNodes());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public NodeIterator getNodes(String pattern) throws RepositoryException {
- try {
- return getNodeIterator(getSession(), remote.getNodes(pattern));
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Property getProperty(String path) throws RepositoryException {
- try {
- RemoteProperty property = remote.getProperty(path);
- return getFactory().getProperty(getSession(), property);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public PropertyIterator getProperties() throws RepositoryException {
- try {
- return getPropertyIterator(getSession(), remote.getProperties());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public PropertyIterator getProperties(String pattern)
- throws RepositoryException {
- try {
- RemoteProperty[] properties = remote.getProperties(pattern);
- return getPropertyIterator(getSession(), properties);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Item getPrimaryItem() throws RepositoryException {
- try {
- return getItem(getSession(), remote.getPrimaryItem());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String getUUID() throws RepositoryException {
- try {
- return remote.getUUID();
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public PropertyIterator getReferences() throws RepositoryException {
- try {
- return getPropertyIterator(getSession(), remote.getReferences());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean hasNode(String path) throws RepositoryException {
- try {
- return remote.hasNode(path);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean hasProperty(String path) throws RepositoryException {
- try {
- return remote.hasProperty(path);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean hasNodes() throws RepositoryException {
- try {
- return remote.hasNodes();
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean hasProperties() throws RepositoryException {
- try {
- return remote.hasProperties();
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public NodeType getPrimaryNodeType() throws RepositoryException {
- try {
- return getFactory().getNodeType(remote.getPrimaryNodeType());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public NodeType[] getMixinNodeTypes() throws RepositoryException {
- try {
- return getNodeTypeArray(remote.getMixinNodeTypes());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean isNodeType(String type) throws RepositoryException {
- try {
- return remote.isNodeType(type);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void addMixin(String name) throws RepositoryException {
- try {
- remote.addMixin(name);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void removeMixin(String name) throws RepositoryException {
- try {
- remote.removeMixin(name);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean canAddMixin(String name) throws RepositoryException {
- try {
- return remote.canAddMixin(name);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public NodeDef getDefinition() throws RepositoryException {
- try {
- return getFactory().getNodeDef(remote.getDefinition());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Version checkin() throws RepositoryException {
- try {
- return getFactory().getVersion(getSession(), remote.checkin());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void checkout() throws RepositoryException {
- try {
- remote.checkout();
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void update(String workspace) throws RepositoryException {
- try {
- remote.update(workspace);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void merge(String workspace, boolean bestEffort)
- throws RepositoryException {
- try {
- remote.merge(workspace, bestEffort);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void cancelMerge(Version version) throws RepositoryException {
- try {
- remote.cancelMerge(version.getUUID());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void doneMerge(Version version) throws RepositoryException {
- try {
- remote.doneMerge(version.getUUID());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String getCorrespondingNodePath(String workspace)
- throws RepositoryException {
- try {
- return remote.getCorrespondingNodePath(workspace);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public int getIndex() throws RepositoryException {
- try {
- return remote.getIndex();
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void restore(String version, boolean removeExisting)
- throws RepositoryException {
- try {
- remote.restore(version, removeExisting);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void restore(Version version, boolean removeExisting)
- throws RepositoryException {
- try {
- remote.restoreByUUID(version.getUUID(), removeExisting);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void restore(Version version, String path, boolean removeExisting)
- throws RepositoryException {
- try {
- remote.restore(version.getUUID(), path, removeExisting);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void restoreByLabel(String label, boolean removeExisting)
- throws RepositoryException {
- try {
- remote.restoreByLabel(label, removeExisting);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Property setProperty(String name, String[] strings, int type)
- throws RepositoryException {
- Value[] values = new Value[strings.length];
- for (int i = 0; i < strings.length; i++) {
- values[i] = new StringValue(strings[i]);
- }
- return setProperty(name, values, type);
- }
-
- /** {@inheritDoc} */
- public Property setProperty(String name, Value[] values, int type)
- throws RepositoryException {
- try {
- Value[] serials = SerialValue.makeSerialValueArray(values);
- RemoteProperty property = remote.setProperty(name, serials, type);
- return getFactory().getProperty(getSession(), property);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean isCheckedOut() throws RepositoryException {
- try {
- return remote.isCheckedOut();
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public VersionHistory getVersionHistory() throws RepositoryException {
- try {
- return getFactory().getVersionHistory(getSession(), remote.getVersionHistory());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Version getBaseVersion() throws RepositoryException {
- try {
- return getFactory().getVersion(getSession(), remote.getBaseVersion());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Lock lock(boolean isDeep, boolean isSessionScoped)
- throws RepositoryException {
- try {
- RemoteLock lock = remote.lock(isDeep, isSessionScoped);
- return getFactory().getLock(this, lock);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Lock getLock() throws RepositoryException {
- try {
- return getFactory().getLock(this, remote.getLock());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void unlock() throws RepositoryException {
- try {
- remote.unlock();
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean holdsLock() throws RepositoryException {
- try {
- return remote.holdsLock();
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean isLocked() throws RepositoryException {
- try {
- return remote.isLocked();
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientNodeDef.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientNodeDef.java
deleted file mode 100644
index c4aef585db3..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientNodeDef.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.client;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.nodetype.NodeDef;
-import javax.jcr.nodetype.NodeType;
-
-import org.apache.jackrabbit.rmi.remote.RemoteNodeDef;
-
-/**
- * Local adapter for the JCR-RMI
- * {@link org.apache.jackrabbit.rmi.remote.RemoteNodeDef RemoteNodeDef}
- * inteface. This class makes a remote node definition locally available using
- * the JCR {@link javax.jcr.nodetype.NodeDef NodeDef} interface.
- *
- * @author Jukka Zitting
- * @see javax.jcr.nodetype.NodeDef
- * @see org.apache.jackrabbit.rmi.remote.RemoteNodeDef
- */
-public class ClientNodeDef extends ClientItemDef implements NodeDef {
-
- /** The adapted remote node definition. */
- private RemoteNodeDef remote;
-
- /**
- * Creates a local adapter for the given remote node definition.
- *
- * @param remote remote node definition
- * @param factory local adapter factory
- */
- public ClientNodeDef(RemoteNodeDef remote, LocalAdapterFactory factory) {
- super(remote, factory);
- this.remote = remote;
- }
-
- /** {@inheritDoc} */
- public NodeType[] getRequiredPrimaryTypes() {
- try {
- return getNodeTypeArray(remote.getRequiredPrimaryTypes());
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public NodeType getDefaultPrimaryType() {
- try {
- return getFactory().getNodeType(remote.getDefaultPrimaryType());
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean allowSameNameSibs() {
- try {
- return remote.allowSameNameSibs();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientNodeType.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientNodeType.java
deleted file mode 100644
index 7b8f07fb8c3..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientNodeType.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.client;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.Value;
-import javax.jcr.nodetype.NodeDef;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.nodetype.PropertyDef;
-
-import org.apache.jackrabbit.rmi.remote.RemoteNodeDef;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeType;
-import org.apache.jackrabbit.rmi.remote.SerialValue;
-
-/**
- * Local adapter for the JCR-RMI
- * {@link org.apache.jackrabbit.rmi.remote.RemoteNodeType RemoteNodeType}
- * inteface. This class makes a remote node type locally available using
- * the JCR {@link javax.jcr.nodetype.NodeType NodeType} interface.
- *
- * @author Jukka Zitting
- * @see javax.jcr.nodetype.NodeType
- * @see org.apache.jackrabbit.rmi.remote.RemoteNodeType
- */
-public class ClientNodeType extends ClientObject implements NodeType {
-
- /** The adapted remote node type. */
- private RemoteNodeType remote;
-
- /**
- * Creates a local adapter for the given remote node type.
- *
- * @param remote remote node type
- * @param factory local adapter factory
- */
- public ClientNodeType(RemoteNodeType remote, LocalAdapterFactory factory) {
- super(factory);
- this.remote = remote;
- }
-
- /** {@inheritDoc} */
- public String getName() {
- try {
- return remote.getName();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean isMixin() {
- try {
- return remote.isMixin();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean hasOrderableChildNodes() {
- try {
- return remote.hasOrderableChildNodes();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public NodeType[] getSupertypes() {
- try {
- return getNodeTypeArray(remote.getSupertypes());
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public NodeType[] getDeclaredSupertypes() {
- try {
- return getNodeTypeArray(remote.getDeclaredSupertypes());
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean isNodeType(String type) {
- try {
- return remote.isNodeType(type);
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public PropertyDef[] getPropertyDefs() {
- try {
- return getPropertyDefArray(remote.getPropertyDefs());
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public PropertyDef[] getDeclaredPropertyDefs() {
- try {
- return getPropertyDefArray(remote.getDeclaredPropertyDefs());
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public NodeDef[] getChildNodeDefs() {
- try {
- RemoteNodeDef[] defs = remote.getChildNodeDefs();
- return getNodeDefArray(defs);
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public NodeDef[] getDeclaredChildNodeDefs() {
- try {
- RemoteNodeDef[] defs = remote.getDeclaredChildNodeDefs();
- return getNodeDefArray(defs);
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean canSetProperty(String name, Value value) {
- try {
- return remote.canSetProperty(name, new SerialValue(value));
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean canSetProperty(String name, Value[] values) {
- try {
- Value[] serials = SerialValue.makeSerialValueArray(values);
- return remote.canSetProperty(name, serials);
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean canAddChildNode(String name) {
- try {
- return remote.canAddChildNode(name);
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean canAddChildNode(String name, String type) {
- try {
- return remote.canAddChildNode(name, type);
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean canRemoveItem(String name) {
- try {
- return remote.canRemoveItem(name);
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String getPrimaryItemName() {
- try {
- return remote.getPrimaryItemName();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientNodeTypeManager.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientNodeTypeManager.java
deleted file mode 100644
index 5604f4d442a..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientNodeTypeManager.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.client;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.nodetype.NodeTypeIterator;
-import javax.jcr.nodetype.NodeTypeManager;
-
-import org.apache.jackrabbit.rmi.remote.RemoteNodeTypeManager;
-
-/**
- * Local adapter for the JCR-RMI
- * {@link org.apache.jackrabbit.rmi.remote.RemoteNodeTypeManager RemoteNodeTypeManager}
- * inteface. This class makes a remote node type manager locally available
- * using the JCR {@link javax.jcr.nodetype.NodeTypeManager NodeTypeManager}
- * interface.
- *
- * @author Jukka Zitting
- * @see javax.jcr.nodetype.NodeTypeManager
- * @see org.apache.jackrabbit.rmi.remote.RemoteNodeTypeManager
- */
-public class ClientNodeTypeManager extends ClientObject
- implements NodeTypeManager {
-
- /** The adapted remote node type manager. */
- private RemoteNodeTypeManager remote;
-
- /**
- * Creates a local adapter for the given remote node type manager.
- *
- * @param remote remote node type manager
- * @param factory local adapter factory
- */
- public ClientNodeTypeManager(
- RemoteNodeTypeManager remote, LocalAdapterFactory factory) {
- super(factory);
- this.remote = remote;
- }
-
- /** {@inheritDoc} */
- public NodeType getNodeType(String name) throws RepositoryException {
- try {
- return getFactory().getNodeType(remote.getNodeType(name));
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public NodeTypeIterator getAllNodeTypes() throws RepositoryException {
- try {
- return getNodeTypeIterator(remote.getAllNodeTypes());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public NodeTypeIterator getPrimaryNodeTypes() throws RepositoryException {
- try {
- return getNodeTypeIterator(remote.getPrimaryNodeTypes());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public NodeTypeIterator getMixinNodeTypes() throws RepositoryException {
- try {
- return getNodeTypeIterator(remote.getMixinNodeTypes());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientObject.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientObject.java
deleted file mode 100644
index 1cbe0b0429a..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientObject.java
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.client;
-
-import javax.jcr.Item;
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.Property;
-import javax.jcr.PropertyIterator;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeDef;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.nodetype.NodeTypeIterator;
-import javax.jcr.nodetype.PropertyDef;
-import javax.jcr.version.Version;
-import javax.jcr.version.VersionIterator;
-
-import org.apache.jackrabbit.rmi.iterator.ArrayNodeIterator;
-import org.apache.jackrabbit.rmi.iterator.ArrayNodeTypeIterator;
-import org.apache.jackrabbit.rmi.iterator.ArrayPropertyIterator;
-import org.apache.jackrabbit.rmi.iterator.ArrayVersionIterator;
-import org.apache.jackrabbit.rmi.remote.RemoteItem;
-import org.apache.jackrabbit.rmi.remote.RemoteNode;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeDef;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeType;
-import org.apache.jackrabbit.rmi.remote.RemoteProperty;
-import org.apache.jackrabbit.rmi.remote.RemotePropertyDef;
-import org.apache.jackrabbit.rmi.remote.RemoteVersion;
-import org.apache.jackrabbit.rmi.remote.RemoteVersionHistory;
-
-/**
- * Base class for client adapter objects. The only purpose of
- * this class is to centralize the handling of the
- * local adapter factory used by the client adapters to
- * instantiate new adapters.
- *
- * @author Jukka Zitting
- */
-public class ClientObject {
-
- /** Local adapter factory. */
- private LocalAdapterFactory factory;
-
- /**
- * Creates a basic client adapter that uses the given factory
- * to create new adapters.
- *
- * @param factory local adapter factory
- */
- protected ClientObject(LocalAdapterFactory factory) {
- this.factory = factory;
- }
-
- /**
- * Returns the local adapter factory used to create new adapters.
- *
- * @return local adapter factory
- */
- protected LocalAdapterFactory getFactory() {
- return factory;
- }
-
- /**
- * Utility method to create a local adapter for a remote item.
- * This method introspects the remote reference to determine
- * whether to instantiate a {@link Property Property},
- * a {@link Node Node}, or an {@link Item Item} adapter using
- * the local adapter factory.
- *
- * If the remote item is a {@link RemoteNode}, this method delegates
- * to {@link #getNode(Session, RemoteNode)}.
- *
- * @param session current session
- * @param remote remote item
- * @return local property, node, or item adapter
- */
- protected Item getItem(Session session, RemoteItem remote) {
- if (remote instanceof RemoteProperty) {
- return factory.getProperty(session, (RemoteProperty) remote);
- } else if (remote instanceof RemoteNode) {
- return getNode(session, (RemoteNode) remote);
- } else {
- return factory.getItem(session, remote);
- }
- }
-
- /**
- * Utility method to create a local adapter for a remote node.
- * This method introspects the remote reference to determine
- * whether to instantiate a {@link Node Node},
- * a {@link javax.jcr.version.VersionHistory VersionHistory}, or a
- * {@link Version Version} adapter using
- * the local adapter factory.
- *
- * @param session current session
- * @param remote remote node
- * @return local node, version, or version history adapter
- */
- protected Node getNode(Session session, RemoteNode remote) {
- if (remote instanceof RemoteVersion) {
- return factory.getVersion(session, (RemoteVersion) remote);
- } else if (remote instanceof RemoteVersionHistory) {
- return factory.getVersionHistory(session, (RemoteVersionHistory) remote);
- } else {
- return factory.getNode(session, (RemoteNode) remote);
- }
- }
-
- /**
- * Utility method for creating a property iterator for an array
- * of remote properties. The properties in the returned iterator
- * are created using the local adapter factory.
- *
- * A null input is treated as an empty array.
- *
- * @param session current session
- * @param remotes remote properties
- * @return local property iterator
- */
- protected PropertyIterator getPropertyIterator(
- Session session, RemoteProperty[] remotes) {
- if (remotes != null) {
- Property[] properties = new Property[remotes.length];
- for (int i = 0; i < remotes.length; i++) {
- properties[i] = factory.getProperty(session, remotes[i]);
- }
- return new ArrayPropertyIterator(properties);
- } else {
- return new ArrayPropertyIterator(new Property[0]); // for safety
- }
- }
-
- /**
- * Utility method for creating a node iterator for an array
- * of remote nodes. The nodes in the returned iterator
- * are created using the local adapter factory.
- *
- * A null input is treated as an empty array.
- *
- * @param session current session
- * @param remotes remote nodes
- * @return local node iterator
- */
- protected NodeIterator getNodeIterator(
- Session session, RemoteNode[] remotes) {
- if (remotes != null) {
- Node[] nodes = new Node[remotes.length];
- for (int i = 0; i < remotes.length; i++) {
- nodes[i] = getNode(session, remotes[i]);
- }
- return new ArrayNodeIterator(nodes);
- } else {
- return new ArrayNodeIterator(new Node[0]); // for safety
- }
- }
-
- /**
- * Utility method for creating a version array for an array
- * of remote versions. The versions in the returned array
- * are created using the local adapter factory.
- *
- * A null input is treated as an empty array.
- *
- * @param session current session
- * @param remotes remote versions
- * @return local version array
- */
- protected Version[] getVersionArray(
- Session session, RemoteVersion[] remotes) {
- if (remotes != null) {
- Version[] versions = new Version[remotes.length];
- for (int i = 0; i < remotes.length; i++) {
- versions[i] = factory.getVersion(session, remotes[i]);
- }
- return versions;
- } else {
- return new Version[0]; // for safety
- }
- }
-
- /**
- * Utility method for creating a version iterator for an array
- * of remote versions. The versions in the returned iterator
- * are created using the local adapter factory.
- *
- * A null input is treated as an empty array.
- *
- * @param session current session
- * @param remotes remote versions
- * @return local version iterator
- */
- protected VersionIterator getVersionIterator(
- Session session, RemoteVersion[] remotes) {
- return new ArrayVersionIterator(getVersionArray(session, remotes));
- }
-
- /**
- * Utility method for creating an array of local node type adapters
- * for an array of remote node types. The node type adapters are created
- * using the local adapter factory.
- *
- * A null input is treated as an empty array.
- *
- * @param remotes remote node types
- * @return local node type array
- */
- protected NodeType[] getNodeTypeArray(RemoteNodeType[] remotes) {
- if (remotes != null) {
- NodeType[] types = new NodeType[remotes.length];
- for (int i = 0; i < remotes.length; i++) {
- types[i] = factory.getNodeType(remotes[i]);
- }
- return types;
- } else {
- return new NodeType[0]; // for safety
- }
- }
-
- /**
- * Utility method for creating an iterator of local node type adapters
- * for an array of remote node types. The node type adapters are created
- * using the local adapter factory.
- *
- * A null input is treated as an empty array.
- *
- * @param remotes remote node types
- * @return local node type iterator
- */
- protected NodeTypeIterator getNodeTypeIterator(RemoteNodeType[] remotes) {
- return new ArrayNodeTypeIterator(getNodeTypeArray(remotes));
- }
-
- /**
- * Utility method for creating an array of local node definition
- * adapters for an array of remote node definitions. The node
- * definition adapters are created using the local adapter factory.
- *
- * A null input is treated as an empty array.
- *
- * @param remotes remote node definitions
- * @return local node definition array
- */
- protected NodeDef[] getNodeDefArray(RemoteNodeDef[] remotes) {
- if (remotes != null) {
- NodeDef[] defs = new NodeDef[remotes.length];
- for (int i = 0; i < remotes.length; i++) {
- defs[i] = factory.getNodeDef(remotes[i]);
- }
- return defs;
- } else {
- return new NodeDef[0]; // for safety
- }
- }
-
- /**
- * Utility method for creating an array of local property definition
- * adapters for an array of remote property definitions. The property
- * definition adapters are created using the local adapter factory.
- *
- * A null input is treated as an empty array.
- *
- * @param remotes remote property definitions
- * @return local property definition array
- */
- protected PropertyDef[] getPropertyDefArray(RemotePropertyDef[] remotes) {
- if (remotes != null) {
- PropertyDef[] defs = new PropertyDef[remotes.length];
- for (int i = 0; i < remotes.length; i++) {
- defs[i] = factory.getPropertyDef(remotes[i]);
- }
- return defs;
- } else {
- return new PropertyDef[0]; // for safety
- }
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientProperty.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientProperty.java
deleted file mode 100644
index 127d97351cc..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientProperty.java
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.client;
-
-import java.io.InputStream;
-import java.rmi.RemoteException;
-import java.util.Calendar;
-
-import javax.jcr.BinaryValue;
-import javax.jcr.BooleanValue;
-import javax.jcr.DateValue;
-import javax.jcr.DoubleValue;
-import javax.jcr.ItemVisitor;
-import javax.jcr.LongValue;
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.ReferenceValue;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.StringValue;
-import javax.jcr.Value;
-import javax.jcr.nodetype.PropertyDef;
-
-import org.apache.jackrabbit.rmi.remote.RemoteProperty;
-import org.apache.jackrabbit.rmi.remote.SerialValue;
-
-/**
- * Local adapter for the JCR-RMI
- * {@link org.apache.jackrabbit.rmi.remote.RemoteProperty RemoteProperty}
- * inteface. This class makes a remote property locally available using
- * the JCR {@link javax.jcr.Property Property} interface.
- *
- * @author Jukka Zitting
- * @see javax.jcr.Property
- * @see org.apache.jackrabbit.rmi.remote.RemoteProperty
- */
-public class ClientProperty extends ClientItem implements Property {
-
- /** The adapted remote property. */
- private RemoteProperty remote;
-
- /**
- * Creates a local adapter for the given remote property.
- *
- * @param session current session
- * @param remote remote property
- * @param factory local adapter factory
- */
- public ClientProperty(
- Session session, RemoteProperty remote,
- LocalAdapterFactory factory) {
- super(session, remote, factory);
- this.remote = remote;
- }
-
- /**
- * Calls the {@link ItemVisitor#visit(Property) ItemVisitor.visit(Property}
- * method of the given visitor. Does not contact the remote property, but
- * the visitor may invoke other methods that do contact the remote property.
- *
- * {@inheritDoc}
- */
- public void accept(ItemVisitor visitor) throws RepositoryException {
- visitor.visit(this);
- }
-
- /**
- * Returns the boolean value of this property. Implemented as
- * getValue().getBoolean().
- *
- * {@inheritDoc}
- */
- public boolean getBoolean() throws RepositoryException {
- return getValue().getBoolean();
- }
-
- /**
- * Returns the date value of this property. Implemented as
- * getValue().getDate().
- *
- * {@inheritDoc}
- */
- public Calendar getDate() throws RepositoryException {
- return getValue().getDate();
- }
-
- /**
- * Returns the double value of this property. Implemented as
- * getValue().getDouble().
- *
- * {@inheritDoc}
- */
- public double getDouble() throws RepositoryException {
- return getValue().getDouble();
- }
-
- /**
- * Returns the long value of this property. Implemented as
- * getValue().getLong().
- *
- * {@inheritDoc}
- */
- public long getLong() throws RepositoryException {
- return getValue().getLong();
- }
-
- /**
- * Returns the binary value of this property. Implemented as
- * getValue().getStream().
- *
- * {@inheritDoc}
- */
- public InputStream getStream() throws RepositoryException {
- return getValue().getStream();
- }
-
- /**
- * Returns the string value of this property. Implemented as
- * getValue().getString().
- *
- * {@inheritDoc}
- */
- public String getString() throws RepositoryException {
- return getValue().getString();
- }
-
- /** {@inheritDoc} */
- public Value getValue() throws RepositoryException {
- try {
- return remote.getValue();
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Value[] getValues() throws RepositoryException {
- try {
- return remote.getValues();
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /**
- * Sets the boolean value of this property. Implemented as
- * setValue(new BooleanValue(value)).
- *
- * {@inheritDoc}
- */
- public void setValue(boolean value) throws RepositoryException {
- setValue(new BooleanValue(value));
- }
-
- /**
- * Sets the date value of this property. Implemented as
- * setValue(new DateValue(value)).
- *
- * {@inheritDoc}
- */
- public void setValue(Calendar value) throws RepositoryException {
- setValue(new DateValue(value));
- }
-
- /**
- * Sets the double value of this property. Implemented as
- * setValue(new DoubleValue(value)).
- *
- * {@inheritDoc}
- */
- public void setValue(double value) throws RepositoryException {
- setValue(new DoubleValue(value));
- }
-
- /**
- * Sets the binary value of this property. Implemented as
- * setValue(new BinaryValue(value)).
- *
- * {@inheritDoc}
- */
- public void setValue(InputStream value) throws RepositoryException {
- setValue(new BinaryValue(value));
- }
-
- /**
- * Sets the long value of this property. Implemented as
- * setValue(new LongValue(value)).
- *
- * {@inheritDoc}
- */
- public void setValue(long value) throws RepositoryException {
- setValue(new LongValue(value));
- }
-
- /**
- * Sets the reference value of this property. Implemented as
- * setValue(new ReferenceValue(value)).
- *
- * {@inheritDoc}
- */
- public void setValue(Node value) throws RepositoryException {
- setValue(new ReferenceValue(value));
- }
-
- /**
- * Sets the string value of this property. Implemented as
- * setValue(new StringValue(value)).
- *
- * {@inheritDoc}
- */
- public void setValue(String value) throws RepositoryException {
- setValue(new StringValue(value));
- }
-
- /**
- * Sets the string values of this property. Implemented as
- * setValue(new Value[] { new StringValue(strings[0]), ... }).
- *
- * {@inheritDoc}
- */
- public void setValue(String[] strings) throws RepositoryException {
- Value[] values = new Value[strings.length];
- for (int i = 0; i < strings.length; i++) {
- values[i] = new StringValue(strings[i]);
- }
- setValue(values);
- }
-
- /** {@inheritDoc} */
- public void setValue(Value value) throws RepositoryException {
- try {
- remote.setValue(new SerialValue(value));
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void setValue(Value[] values) throws RepositoryException {
- try {
- remote.setValue(SerialValue.makeSerialValueArray(values));
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /**
- * Returns the reference value of this property. Implemented by
- * converting the reference value to an UUID string and using the
- * current session to look up the referenced node.
- *
- * {@inheritDoc}
- */
- public Node getNode() throws RepositoryException {
- return getSession().getNodeByUUID(getString());
- }
-
- /** {@inheritDoc} */
- public long getLength() throws RepositoryException {
- try {
- return remote.getLength();
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public long[] getLengths() throws RepositoryException {
- try {
- return remote.getLengths();
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public PropertyDef getDefinition() throws RepositoryException {
- try {
- return getFactory().getPropertyDef(remote.getDefinition());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public int getType() throws RepositoryException {
- try {
- return remote.getType();
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientPropertyDef.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientPropertyDef.java
deleted file mode 100644
index 1af1b91477a..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientPropertyDef.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.client;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.Value;
-import javax.jcr.nodetype.PropertyDef;
-
-import org.apache.jackrabbit.rmi.remote.RemotePropertyDef;
-
-/**
- * Local adapter for the JCR-RMI
- * {@link org.apache.jackrabbit.rmi.remote.RemotePropertyDef RemotePropertyDef}
- * inteface. This class makes a remote property definition locally available
- * using the JCR {@link javax.jcr.nodetype.PropertyDef PropertyDef} interface.
- *
- * @author Jukka Zitting
- * @see javax.jcr.nodetype.PropertyDef
- * @see org.apache.jackrabbit.rmi.remote.RemotePropertyDef
- */
-public class ClientPropertyDef extends ClientItemDef implements PropertyDef {
-
- /** The adapted remote property. */
- private RemotePropertyDef remote;
-
- /**
- * Creates a local adapter for the given remote property definition.
- *
- * @param remote remote property definition
- * @param factory local adapter factory
- */
- public ClientPropertyDef(
- RemotePropertyDef remote, LocalAdapterFactory factory) {
- super(remote, factory);
- this.remote = remote;
- }
-
- /** {@inheritDoc} */
- public int getRequiredType() {
- try {
- return remote.getRequiredType();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String[] getValueConstraints() {
- try {
- return remote.getValueConstraints();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Value[] getDefaultValues() {
- try {
- return remote.getDefaultValues();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean isMultiple() {
- try {
- return remote.isMultiple();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientQuery.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientQuery.java
deleted file mode 100644
index d698f85706f..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientQuery.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.client;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryResult;
-
-import org.apache.jackrabbit.rmi.remote.RemoteQuery;
-
-/**
- * Local adapter for the JCR-RMI
- * {@link RemoteQuery RemoteQuery}
- * inteface. This class makes a remote query locally available using
- * the JCR {@link Query Query} interface.
- *
- * @author Philipp Koch
- * @see javax.jcr.query.Query Query
- * @see org.apache.jackrabbit.rmi.remote.RemoteQuery
- */
-public class ClientQuery extends ClientObject implements Query {
-
- /** The current session */
- private Session session;
-
- /** The adapted remote query manager. */
- private RemoteQuery remote;
-
- /**
- * Creates a client adapter for the given query.
- *
- * @param session current session
- * @param remote remote query
- * @param factory adapter factory
- */
- public ClientQuery(
- Session session, RemoteQuery remote, LocalAdapterFactory factory) {
- super(factory);
- this.session = session;
- this.remote = remote;
- }
-
- /** {@inheritDoc} */
- public QueryResult execute() throws RepositoryException {
- try {
- return getFactory().getQueryResult(session, remote.execute());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String getStatement() {
- try {
- return remote.getStatement();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String getLanguage() {
- try {
- return remote.getLanguage();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String getPersistentQueryPath() throws RepositoryException {
- try {
- return remote.getPersistentQueryPath();
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void save(String absPath) throws RepositoryException {
- try {
- remote.save(absPath);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientQueryResult.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientQueryResult.java
deleted file mode 100644
index f9b3f618fbf..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientQueryResult.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.client;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.query.QueryResult;
-import javax.jcr.query.Row;
-import javax.jcr.query.RowIterator;
-
-import org.apache.jackrabbit.rmi.iterator.ArrayNodeIterator;
-import org.apache.jackrabbit.rmi.iterator.ArrayRowIterator;
-import org.apache.jackrabbit.rmi.remote.RemoteNode;
-import org.apache.jackrabbit.rmi.remote.RemoteQueryResult;
-import org.apache.jackrabbit.rmi.remote.RemoteRow;
-
-/**
- * Local adapter for the JCR-RMI
- * {@link RemoteQueryResult RemoteQueryResult}
- * inteface. This class makes a remote query result locally available using
- * the JCR {@link QueryResult QueryResult} interface.
- *
- * @author Philipp Koch
- * @see javax.jcr.query.QueryResult QueryResult
- * @see org.apache.jackrabbit.rmi.remote.RemoteQueryResult
- */
-public class ClientQueryResult extends ClientObject implements QueryResult {
-
- /** The current session */
- private Session session;
-
- /** The adapted remote query result. */
- private RemoteQueryResult remote;
-
- /**
- * Creates a client adapter for the given remote query result.
- *
- * @param session current session
- * @param remote remote query result
- * @param factory adapter factory
- */
- public ClientQueryResult(
- Session session, RemoteQueryResult remote,
- LocalAdapterFactory factory) {
- super(factory);
- this.session = session;
- this.remote = remote;
- }
-
- /** {@inheritDoc} */
- public String[] getPropertyNames() throws RepositoryException {
- try {
- return remote.getPropertyNames();
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RowIterator getRows() throws RepositoryException {
- try {
- RemoteRow[] remotes = remote.getRows();
- if (remotes != null) {
- Row[] rows = new Row[remotes.length];
- for (int i = 0; i < rows.length; i++) {
- rows[i] = getFactory().getRow(remotes[i]);
- }
- return new ArrayRowIterator(rows);
- } else {
- return new ArrayRowIterator(new Row[0]);
- }
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public NodeIterator getNodes() throws RepositoryException {
- try {
- RemoteNode[] remotes = remote.getNodes();
- if (remotes != null) {
- Node[] nodes = new Node[remotes.length];
- for (int i = 0; i < nodes.length; i++) {
- nodes[i] = getNode(session, remotes[i]);
- }
- return new ArrayNodeIterator(nodes);
- } else {
- return new ArrayNodeIterator(new Node[0]);
- }
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientRepository.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientRepository.java
deleted file mode 100644
index 1ce012cb145..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientRepository.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.client;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.Credentials;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.apache.jackrabbit.rmi.remote.RemoteRepository;
-import org.apache.jackrabbit.rmi.remote.RemoteSession;
-
-/**
- * Local adapter for the JCR-RMI
- * {@link org.apache.jackrabbit.rmi.remote.RemoteRepository RemoteRepository}
- * inteface. This class makes a remote repository locally available using
- * the JCR {@link javax.jcr.Repository Repository} interface.
- *
- * @author Jukka Zitting
- * @see javax.jcr.Repository
- * @see org.apache.jackrabbit.rmi.remote.RemoteRepository
- */
-public class ClientRepository extends ClientObject implements Repository {
-
- /** The adapted remote repository. */
- private RemoteRepository remote;
-
- /**
- * Creates a client adapter for the given remote repository.
- *
- * @param remote remote repository
- * @param factory local adapter factory
- */
- public ClientRepository(
- RemoteRepository remote, LocalAdapterFactory factory) {
- super(factory);
- this.remote = remote;
- }
-
- /** {@inheritDoc} */
- public String getDescriptor(String name) {
- try {
- return remote.getDescriptor(name);
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String[] getDescriptorKeys() {
- try {
- return remote.getDescriptorKeys();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Session login() throws RepositoryException {
- try {
- RemoteSession session = remote.login();
- return getFactory().getSession(this, session);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Session login(String workspace) throws RepositoryException {
- try {
- RemoteSession session = remote.login(workspace);
- return getFactory().getSession(this, session);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Session login(Credentials credentials) throws RepositoryException {
- try {
- RemoteSession session = remote.login(credentials);
- return getFactory().getSession(this, session);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Session login(Credentials credentials, String workspace)
- throws RepositoryException {
- try {
- RemoteSession session = remote.login(credentials, workspace);
- return getFactory().getSession(this, session);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientRepositoryFactory.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientRepositoryFactory.java
deleted file mode 100644
index 6b920e48a46..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientRepositoryFactory.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.client;
-
-import java.net.MalformedURLException;
-import java.rmi.Naming;
-import java.rmi.NotBoundException;
-import java.rmi.RemoteException;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.Map;
-
-import javax.jcr.Repository;
-import javax.naming.Context;
-import javax.naming.Name;
-import javax.naming.NamingException;
-import javax.naming.RefAddr;
-import javax.naming.Reference;
-import javax.naming.spi.ObjectFactory;
-
-import org.apache.jackrabbit.rmi.remote.RemoteRepository;
-
-/**
- * Object factory for JCR-RMI clients. This factory can be used either
- * directly or as a JNDI object factory.
- *
- * @author Jukka Zitting
- * @see ClientRepository
- */
-public class ClientRepositoryFactory implements ObjectFactory {
-
- /**
- * The JNDI parameter name for configuring the RMI URL of
- * a remote repository.
- */
- public static final String URL_PARAMETER = "url";
-
- /**
- * Cache for repository references.
- */
- private Map repositories;
-
- /**
- * Local adapter factory.
- */
- private LocalAdapterFactory factory;
-
- /**
- * Creates a JCR-RMI client factory with the default adapter factory.
- */
- public ClientRepositoryFactory() {
- this(new ClientAdapterFactory());
- }
-
- /**
- * Creates a JCR-RMI client factory with the given adapter factory.
- *
- * @param factory local adapter factory
- */
- public ClientRepositoryFactory(LocalAdapterFactory factory) {
- this.repositories = new HashMap();
- this.factory = factory;
- }
-
- /**
- * Returns a client wrapper for a remote content repository. The remote
- * repository is looked up from the RMI registry using the given URL and
- * wrapped into a {@link ClientRepository ClientRepository} adapter.
- *
- * The repository references are cached so that only one client instance
- * (per factory) exists for each remote repository.
- *
- * @param url the RMI URL of the remote repository
- * @return repository client
- * @throws ClassCastException if the URL points to an unknown object
- * @throws MalformedURLException if the URL is malformed
- * @throws NotBoundException if the URL points to nowhere
- * @throws RemoteException on RMI errors
- */
- public synchronized Repository getRepository(String url) throws
- ClassCastException, MalformedURLException,
- NotBoundException, RemoteException {
- Repository repository = (Repository) repositories.get(url);
- if (repository == null) {
- RemoteRepository remote = (RemoteRepository) Naming.lookup(url);
- repository = factory.getRepository(remote);
- repositories.put(url, repository);
- }
- return repository;
- }
-
- /**
- * Utility method for looking up the URL within the given RefAddr object.
- * Feeds the content of the RefAddr object to
- * {@link #getRepository(String) getRepository(String)} and wraps all
- * errors to {@link NamingException NamingExceptions}.
- *
- * Used by {@link #getObjectInstance(Object, Name, Context, Hashtable) getObjectInstance()}.
- *
- * @param url the URL reference
- * @return repository client
- * @throws NamingException on all errors
- */
- private Repository getRepository(RefAddr url) throws NamingException {
- try {
- return getRepository((String) url.getContent());
- } catch (Exception ex) {
- throw new NamingException(ex.getMessage());
- }
- }
-
- /**
- * JNDI factory method for creating JCR-RMI clients. Looks up a
- * remote repository using the reference parameter "url" as the RMI URL
- * and returns a client wrapper for the remote repository.
- *
- * @param object reference parameters
- * @param name unused
- * @param context unused
- * @param environment unused
- * @return repository client
- * @throws NamingException on all errors
- */
- public Object getObjectInstance(
- Object object, Name name, Context context, Hashtable environment)
- throws NamingException {
- if (object instanceof Reference) {
- Reference reference = (Reference) object;
- if (Repository.class.getName().equals(reference.getClassName())) {
- RefAddr url = reference.get(URL_PARAMETER);
- if (url != null) {
- return getRepository(url);
- }
- }
- }
- return null;
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientRow.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientRow.java
deleted file mode 100644
index 212e395f7a0..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientRow.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.client;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.Value;
-import javax.jcr.query.Row;
-
-import org.apache.jackrabbit.rmi.remote.RemoteRow;
-
-/**
- * Local adapter for the JCR-RMI {@link RemoteRow RemoteRow}
- * inteface. This class makes a remote query row locally available using
- * the JCR {@link Row Row} interface.
- *
- * @author Philipp Koch
- * @see javax.jcr.query.Row Row
- * @see org.apache.jackrabbit.rmi.remote.RemoteRow
- */
-public class ClientRow implements Row {
-
- /** The remote query row. */
- private RemoteRow remote;
-
- /**
- * Creates a client adapter for the given remote query row.
- *
- * @param remote remote query row
- */
- public ClientRow(RemoteRow remote) {
- this.remote = remote;
- }
-
- /** {@inheritDoc} */
- public Value[] getValues() throws RepositoryException {
- try {
- return remote.getValues();
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Value getValue(String s) throws RepositoryException {
- try {
- return remote.getValue(s);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientSession.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientSession.java
deleted file mode 100644
index c8ce8258ee7..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientSession.java
+++ /dev/null
@@ -1,417 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.client;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.rmi.RemoteException;
-import java.security.AccessControlException;
-
-import javax.jcr.Credentials;
-import javax.jcr.Item;
-import javax.jcr.Node;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.Workspace;
-import javax.xml.transform.Result;
-import javax.xml.transform.Source;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.sax.SAXResult;
-import javax.xml.transform.stream.StreamSource;
-
-import org.apache.jackrabbit.rmi.remote.RemoteSession;
-import org.apache.jackrabbit.rmi.xml.SessionImportContentHandler;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.SAXException;
-
-/**
- * Local adapter for the JCR-RMI
- * {@link org.apache.jackrabbit.rmi.remote.RemoteSession RemoteSession}
- * inteface. This class makes a remote session locally available using
- * the JCR {@link javax.jcr.Session Session} interface.
- *
- * @author Jukka Zitting
- * @see javax.jcr.Session
- * @see org.apache.jackrabbit.rmi.remote.RemoteSession
- */
-public class ClientSession extends ClientObject implements Session {
-
- /** The current repository. */
- private Repository repository;
-
- /** The adapted remote session. */
- private RemoteSession remote;
-
- /**
- * Creates a client adapter for the given remote session.
- *
- * @param repository current repository
- * @param remote remote repository
- * @param factory local adapter factory
- */
- public ClientSession(Repository repository, RemoteSession remote,
- LocalAdapterFactory factory) {
- super(factory);
- this.repository = repository;
- this.remote = remote;
- }
-
- /**
- * Returns the current repository without contacting the remote session.
- *
- * {@inheritDoc}
- */
- public Repository getRepository() {
- return repository;
- }
-
- /** {@inheritDoc} */
- public String getUserId() {
- try {
- return remote.getUserId();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Object getAttribute(String name) {
- try {
- return remote.getAttribute(name);
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String[] getAttributeNames() {
- try {
- return remote.getAttributeNames();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Workspace getWorkspace() {
- try {
- return getFactory().getWorkspace(this, remote.getWorkspace());
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Session impersonate(Credentials credentials)
- throws RepositoryException {
- try {
- RemoteSession session = remote.impersonate(credentials);
- return getFactory().getSession(repository, session);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Node getRootNode() throws RepositoryException {
- try {
- return getNode(this, remote.getRootNode());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Node getNodeByUUID(String uuid) throws RepositoryException {
- try {
- return getNode(this, remote.getNodeByUUID(uuid));
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Item getItem(String path) throws RepositoryException {
- try {
- return getItem(this, remote.getItem(path));
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean itemExists(String path) {
- try {
- return remote.itemExists(path);
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void move(String from, String to) throws RepositoryException {
- try {
- remote.move(from, to);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void save() throws RepositoryException {
- try {
- remote.save();
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void refresh(boolean keepChanges) throws RepositoryException {
- try {
- remote.refresh(keepChanges);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean hasPendingChanges() throws RepositoryException {
- try {
- return remote.hasPendingChanges();
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void checkPermission(String path, String actions)
- throws AccessControlException {
- try {
- remote.checkPermission(path, actions);
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void importXML(String path, InputStream xml)
- throws IOException, RepositoryException {
- try {
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- byte[] bytes = new byte[4096];
- for (int n = xml.read(bytes); n != -1; n = xml.read(bytes)) {
- buffer.write(bytes, 0, n);
- }
- remote.importXML(path, buffer.toByteArray());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public ContentHandler getImportContentHandler(String path)
- throws RepositoryException {
- return new SessionImportContentHandler(this, path);
- }
-
- /** {@inheritDoc} */
- public void setNamespacePrefix(String prefix, String uri)
- throws RepositoryException {
- try {
- remote.setNamespacePrefix(prefix, uri);
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String[] getNamespacePrefixes() throws RepositoryException {
- try {
- return remote.getNamespacePrefixes();
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String getNamespaceURI(String prefix) throws RepositoryException {
- try {
- return remote.getNamespaceURI(prefix);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String getNamespacePrefix(String uri) throws RepositoryException {
- try {
- return remote.getNamespacePrefix(uri);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void logout() {
- try {
- remote.logout();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void addLockToken(String name) {
- try {
- remote.addLockToken(name);
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String[] getLockTokens() {
- try {
- return remote.getLockTokens();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void removeLockToken(String name) {
- try {
- remote.removeLockToken(name);
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /**
- * Exports the XML system view of the specified repository location
- * to the given XML content handler. This method first requests the
- * raw XML data from the remote session, and then uses an identity
- * transformation to feed the data to the given XML content handler.
- * Possible IO and transformer exceptions are thrown as SAXExceptions.
- *
- * {@inheritDoc}
- */
- public void exportSysView(
- String path, ContentHandler handler,
- boolean binaryAsLink, boolean noRecurse)
- throws SAXException, RepositoryException {
- try {
- byte[] xml = remote.exportSysView(path, binaryAsLink, noRecurse);
-
- Source source = new StreamSource(new ByteArrayInputStream(xml));
- Result result = new SAXResult(handler);
-
- TransformerFactory factory = TransformerFactory.newInstance();
- Transformer transformer = factory.newTransformer();
- transformer.transform(source, result);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- } catch (IOException ex) {
- throw new SAXException(ex);
- } catch (TransformerConfigurationException ex) {
- throw new SAXException(ex);
- } catch (TransformerException ex) {
- throw new SAXException(ex);
- }
- }
-
- /**
- * Exports the XML system view of the specified repository location
- * to the given output stream. This method first requests the
- * raw XML data from the remote session, and then writes the data to
- * the output stream.
- *
- * {@inheritDoc}
- */
- public void exportSysView(
- String path, OutputStream output,
- boolean binaryAsLink, boolean noRecurse)
- throws IOException, RepositoryException {
- try {
- byte[] xml = remote.exportSysView(path, binaryAsLink, noRecurse);
- output.write(xml);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /**
- * Exports the XML document view of the specified repository location
- * to the given XML content handler. This method first requests the
- * raw XML data from the remote session, and then uses an identity
- * transformation to feed the data to the given XML content handler.
- * Possible IO and transformer exceptions are thrown as SAXExceptions.
- *
- * {@inheritDoc}
- */
- public void exportDocView(
- String path, ContentHandler handler,
- boolean binaryAsLink, boolean noRecurse)
- throws SAXException, RepositoryException {
- try {
- byte[] xml = remote.exportDocView(path, binaryAsLink, noRecurse);
-
- Source source = new StreamSource(new ByteArrayInputStream(xml));
- Result result = new SAXResult(handler);
-
- TransformerFactory factory = TransformerFactory.newInstance();
- Transformer transformer = factory.newTransformer();
- transformer.transform(source, result);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- } catch (IOException ex) {
- throw new SAXException(ex);
- } catch (TransformerConfigurationException ex) {
- throw new SAXException(ex);
- } catch (TransformerException ex) {
- throw new SAXException(ex);
- }
- }
-
- /**
- * Exports the XML document view of the specified repository location
- * to the given output stream. This method first requests the
- * raw XML data from the remote session, and then writes the data to
- * the output stream.
- *
- * {@inheritDoc}
- */
- public void exportDocView(
- String path, OutputStream output,
- boolean binaryAsLink, boolean noRecurse)
- throws IOException, RepositoryException {
- try {
- byte[] xml = remote.exportDocView(path, binaryAsLink, noRecurse);
- output.write(xml);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientVersion.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientVersion.java
deleted file mode 100644
index b5bed4e9254..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientVersion.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.client;
-
-import java.rmi.RemoteException;
-import java.util.Calendar;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.version.Version;
-
-import org.apache.jackrabbit.rmi.remote.RemoteVersion;
-
-/**
- * Local adapter for the JCR-RMI
- * {@link org.apache.jackrabbit.rmi.remote.RemoteVersion RemoteVersion}
- * interface. This class makes a remote version locally available using
- * the JCR {@link javax.jcr.version.Version Version} interface.
- *
- * @author Felix Meschberger
- * @see javax.jcr.version.Version
- * @see org.apache.jackrabbit.rmi.remote.RemoteVersion
- */
-public class ClientVersion extends ClientNode implements Version {
-
- /** The adapted remote version. */
- private RemoteVersion remote;
-
- /**
- * Creates a local adapter for the given remote version.
- *
- * @param session current session
- * @param remote remote version
- * @param factory local adapter factory
- */
- public ClientVersion(Session session, RemoteVersion remote,
- LocalAdapterFactory factory) {
- super(session, remote, factory);
- this.remote = remote;
- }
-
- /** {@inheritDoc} */
- public Calendar getCreated() throws RepositoryException {
- try {
- return remote.getCreated();
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Version[] getSuccessors() throws RepositoryException {
- try {
- return getVersionArray(getSession(), remote.getSuccessors());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Version[] getPredecessors() throws RepositoryException {
- try {
- return getVersionArray(getSession(), remote.getPredecessors());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientVersionHistory.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientVersionHistory.java
deleted file mode 100644
index dea6927ee0a..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientVersionHistory.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.client;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.UnsupportedRepositoryOperationException;
-import javax.jcr.version.Version;
-import javax.jcr.version.VersionException;
-import javax.jcr.version.VersionHistory;
-import javax.jcr.version.VersionIterator;
-
-import org.apache.jackrabbit.rmi.remote.RemoteVersionHistory;
-
-/**
- * Local adapter for the JCR-RMI
- * {@link org.apache.jackrabbit.rmi.remote.RemoteVersionHistory RemoteVersionHistory}
- * interface. This class makes a remote version history locally available using
- * the JCR {@link javax.jcr.version.VersionHistory VersionHistory} interface.
- *
- * @author Felix Meschberger
- * @see javax.jcr.version.VersionHistory
- * @see org.apache.jackrabbit.rmi.remote.RemoteVersionHistory
- */
-public class ClientVersionHistory extends ClientNode implements VersionHistory {
-
- /** The adapted remote version history. */
- private RemoteVersionHistory remote;
-
- /**
- * Creates a local adapter for the given remote version history.
- *
- * @param session current session
- * @param remote remote version history
- * @param factory local adapter factory
- */
- public ClientVersionHistory(Session session, RemoteVersionHistory remote,
- LocalAdapterFactory factory) {
- super(session, remote, factory);
- this.remote = remote;
- }
-
- /** {@inheritDoc} */
- public Version getRootVersion() throws RepositoryException {
- try {
- return getFactory().getVersion(getSession(), remote.getRootVersion());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public VersionIterator getAllVersions() throws RepositoryException {
- try {
- return getVersionIterator(getSession(), remote.getAllVersions());
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Version getVersion(String versionName) throws VersionException,
- RepositoryException {
- try {
- return getFactory().getVersion(getSession(), remote.getVersion(versionName));
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public Version getVersionByLabel(String label) throws RepositoryException {
- try {
- return getFactory().getVersion(getSession(), remote.getVersionByLabel(label));
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void addVersionLabel(String versionName, String label,
- boolean moveLabel) throws VersionException, RepositoryException {
- try {
- remote.addVersionLabel(versionName, label, moveLabel);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void removeVersionLabel(String label)
- throws VersionException, RepositoryException {
- try {
- remote.removeVersionLabel(label);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean hasVersionLabel(String label) {
- try {
- return remote.hasVersionLabel(label);
- } catch (RemoteException ex) {
- // grok the exception and assume label is missing
- return false;
- }
- }
-
- /** {@inheritDoc} */
- public boolean hasVersionLabel(Version version, String label)
- throws VersionException, RepositoryException {
- try {
- String versionUUID = version.getUUID();
- return remote.hasVersionLabel(versionUUID, label);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String[] getVersionLabels() {
- try {
- return remote.getVersionLabels();
- } catch (RemoteException ex) {
- // grok the exception and return an empty array
- return new String[0];
- }
- }
-
- /** {@inheritDoc} */
- public String[] getVersionLabels(Version version)
- throws VersionException, RepositoryException {
- try {
- String versionUUID = version.getUUID();
- return remote.getVersionLabels(versionUUID);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void removeVersion(String versionName)
- throws UnsupportedRepositoryOperationException, VersionException,
- RepositoryException {
- try {
- remote.removeVersion(versionName);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientWorkspace.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientWorkspace.java
deleted file mode 100644
index d6085677963..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/ClientWorkspace.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.client;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.rmi.RemoteException;
-
-import javax.jcr.NamespaceRegistry;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.UnsupportedRepositoryOperationException;
-import javax.jcr.Workspace;
-import javax.jcr.nodetype.NodeTypeManager;
-import javax.jcr.observation.ObservationManager;
-import javax.jcr.query.QueryManager;
-import javax.jcr.version.Version;
-
-import org.apache.jackrabbit.rmi.remote.RemoteNamespaceRegistry;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeTypeManager;
-import org.apache.jackrabbit.rmi.remote.RemoteQueryManager;
-import org.apache.jackrabbit.rmi.remote.RemoteWorkspace;
-import org.apache.jackrabbit.rmi.xml.WorkspaceImportContentHandler;
-import org.xml.sax.ContentHandler;
-
-/**
- * Local adapter for the JCR-RMI {@link RemoteWorkspace RemoteWorkspace}
- * interface. This class makes a remote workspace locally available using
- * the JCR {@link Workspace Workspace} interface.
- *
- * @author Jukka Zitting
- * @author Philipp Koch
- * @see javax.jcr.Workspace
- * @see org.apache.jackrabbit.rmi.remote.RemoteWorkspace
- */
-public class ClientWorkspace extends ClientObject implements Workspace {
-
- /** The current session. */
- private Session session;
-
- /** The adapted remote workspace. */
- private RemoteWorkspace remote;
-
- /**
- * Creates a client adapter for the given remote workspace.
- *
- * @param session current session
- * @param remote remote workspace
- * @param factory local adapter factory
- */
- public ClientWorkspace(
- Session session, RemoteWorkspace remote,
- LocalAdapterFactory factory) {
- super(factory);
- this.session = session;
- this.remote = remote;
- }
-
- /**
- * Returns the current session without contacting the remote workspace.
- *
- * {@inheritDoc}
- */
- public Session getSession() {
- return session;
- }
-
- /** {@inheritDoc} */
- public String getName() {
- try {
- return remote.getName();
- } catch (RemoteException ex) {
- throw new RemoteRuntimeException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void copy(String from, String to) throws RepositoryException {
- try {
- remote.copy(from, to);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void copy(String workspace, String to, String from)
- throws RepositoryException {
- try {
- remote.copy(workspace, from, to);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void move(String from, String to) throws RepositoryException {
- try {
- remote.move(from, to);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public QueryManager getQueryManager() throws RepositoryException {
- try {
- RemoteQueryManager manager = remote.getQueryManager();
- return getFactory().getQueryManager(session, manager);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public NamespaceRegistry getNamespaceRegistry() throws RepositoryException {
- try {
- RemoteNamespaceRegistry registry = remote.getNamespaceRegistry();
- return getFactory().getNamespaceRegistry(registry);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public NodeTypeManager getNodeTypeManager() throws RepositoryException {
- try {
- RemoteNodeTypeManager manager = remote.getNodeTypeManager();
- return getFactory().getNodeTypeManager(manager);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public ObservationManager getObservationManager()
- throws RepositoryException {
- // TODO Auto-generated method stub
- // return null;
- throw new UnsupportedRepositoryOperationException();
- }
-
- /** {@inheritDoc} */
- public void clone(
- String workspace, String src, String dst, boolean removeExisting)
- throws RepositoryException {
- try {
- remote.clone(workspace, src, dst, removeExisting);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String[] getAccessibleWorkspaceNames() throws RepositoryException {
- try {
- return remote.getAccessibleWorkspaceNames();
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public ContentHandler getImportContentHandler(
- String path, int uuidBehaviour)
- throws RepositoryException {
- return new WorkspaceImportContentHandler(this, path, uuidBehaviour);
- }
-
- /** {@inheritDoc} */
- public void importXML(String path, InputStream xml, int uuidBehaviour)
- throws IOException, RepositoryException {
- try {
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- byte[] bytes = new byte[4096];
- for (int n = xml.read(bytes); n != -1; n = xml.read(bytes)) {
- buffer.write(bytes, 0, n);
- }
- remote.importXML(path, buffer.toByteArray(), uuidBehaviour);
- } catch (RemoteException ex) {
- throw new RemoteRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void restore(Version[] versions, boolean removeExisting)
- throws RepositoryException {
- // TODO Auto-generated method stub
- throw new UnsupportedRepositoryOperationException();
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/LocalAdapterFactory.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/LocalAdapterFactory.java
deleted file mode 100644
index 98c8abadfe5..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/LocalAdapterFactory.java
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.client;
-
-import javax.jcr.Item;
-import javax.jcr.NamespaceRegistry;
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.Repository;
-import javax.jcr.Session;
-import javax.jcr.Workspace;
-import javax.jcr.lock.Lock;
-import javax.jcr.nodetype.ItemDef;
-import javax.jcr.nodetype.NodeDef;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.nodetype.NodeTypeManager;
-import javax.jcr.nodetype.PropertyDef;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryManager;
-import javax.jcr.query.QueryResult;
-import javax.jcr.query.Row;
-import javax.jcr.version.Version;
-import javax.jcr.version.VersionHistory;
-
-import org.apache.jackrabbit.rmi.remote.RemoteItem;
-import org.apache.jackrabbit.rmi.remote.RemoteItemDef;
-import org.apache.jackrabbit.rmi.remote.RemoteLock;
-import org.apache.jackrabbit.rmi.remote.RemoteNamespaceRegistry;
-import org.apache.jackrabbit.rmi.remote.RemoteNode;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeDef;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeType;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeTypeManager;
-import org.apache.jackrabbit.rmi.remote.RemoteProperty;
-import org.apache.jackrabbit.rmi.remote.RemotePropertyDef;
-import org.apache.jackrabbit.rmi.remote.RemoteQuery;
-import org.apache.jackrabbit.rmi.remote.RemoteQueryManager;
-import org.apache.jackrabbit.rmi.remote.RemoteQueryResult;
-import org.apache.jackrabbit.rmi.remote.RemoteRepository;
-import org.apache.jackrabbit.rmi.remote.RemoteRow;
-import org.apache.jackrabbit.rmi.remote.RemoteSession;
-import org.apache.jackrabbit.rmi.remote.RemoteVersion;
-import org.apache.jackrabbit.rmi.remote.RemoteVersionHistory;
-import org.apache.jackrabbit.rmi.remote.RemoteWorkspace;
-
-/**
- * Factory interface for creating local adapters for remote references.
- * This interface defines how remote JCR-RMI references are adapted
- * back to the normal JCR interfaces. The adaption mechanism can be
- * modified (for example to add extra features) by changing the
- * local adapter factory used by the repository client.
- *
- * Note that the
- * {@link org.apache.jackrabbit.rmi.client.ClientObject ClientObject}
- * base class provides a number of utility methods designed to work with
- * a local adapter factory. Adapter implementations may want to inherit
- * that functionality by subclassing from ClientObject.
- *
- * @author Jukka Zitting
- * @author Philipp Koch
- * @see org.apache.jackrabbit.rmi.server.RemoteAdapterFactory
- * @see org.apache.jackrabbit.rmi.client.ClientAdapterFactory
- * @see org.apache.jackrabbit.rmi.client.ClientObject
- */
-public interface LocalAdapterFactory {
-
- /**
- * Factory method for creating a local adapter for a remote repository.
- *
- * @param remote remote repository
- * @return local repository adapter
- */
- Repository getRepository(RemoteRepository remote);
-
- /**
- * Factory method for creating a local adapter for a remote session.
- *
- * @param repository current repository
- * @param remote remote session
- * @return local session adapter
- */
- Session getSession(Repository repository, RemoteSession remote);
-
- /**
- * Factory method for creating a local adapter for a remote workspace.
- *
- * @param session current session
- * @param remote remote workspace
- * @return local workspace adapter
- */
- Workspace getWorkspace(Session session, RemoteWorkspace remote);
-
- /**
- * Factory method for creating a local adapter for a remote namespace
- * registry.
- *
- * @param remote remote namespace registry
- * @return local namespace registry adapter
- */
- NamespaceRegistry getNamespaceRegistry(RemoteNamespaceRegistry remote);
-
- /**
- * Factory method for creating a local adapter for a remote node type
- * manager.
- *
- * @param remote remote node type manager
- * @return local node type manager adapter
- */
- NodeTypeManager getNodeTypeManager(RemoteNodeTypeManager remote);
-
- /**
- * Factory method for creating a local adapter for a remote item.
- * Note that before calling this method, the client may want to
- * introspect the remote item reference to determine whether to use the
- * {@link #getNode(Session, RemoteNode) getNode} or
- * {@link #getProperty(Session, RemoteProperty) getProperty} method
- * instead, as the adapter returned by this method will only cover
- * the basic {@link Item Item} interface.
- *
- * @param session current session
- * @param remote remote item
- * @return local item adapter
- */
- Item getItem(Session session, RemoteItem remote);
-
- /**
- * Factory method for creating a local adapter for a remote property.
- *
- * @param session current session
- * @param remote remote property
- * @return local property adapter
- */
- Property getProperty(Session session, RemoteProperty remote);
-
- /**
- * Factory method for creating a local adapter for a remote node.
- *
- * @param session current session
- * @param remote remote node
- * @return local node adapter
- */
- Node getNode(Session session, RemoteNode remote);
-
- /**
- * Factory method for creating a local adapter for a remote version.
- *
- * @param session current session
- * @param remote remote version
- * @return local version adapter
- */
- Version getVersion(Session session, RemoteVersion remote);
-
- /**
- * Factory method for creating a local adapter for a remote version history.
- *
- * @param session current session
- * @param remote remote version history
- * @return local version history adapter
- */
- VersionHistory getVersionHistory(Session session, RemoteVersionHistory remote);
-
- /**
- * Factory method for creating a local adapter for a remote node type.
- *
- * @param remote remote node type
- * @return local node type adapter
- */
- NodeType getNodeType(RemoteNodeType remote);
-
- /**
- * Factory method for creating a local adapter for a remote item
- * definition. Note that before calling this method, the client may want to
- * introspect the remote item definition to determine whether to use the
- * {@link #getNodeDef(RemoteNodeDef) getNodeDef} or
- * {@link #getPropertyDef(RemotePropertyDef) getPropertyDef} method
- * instead, as the adapter returned by this method will only cover
- * the {@link ItemDef ItemDef} base interface.
- *
- * @param remote remote item definition
- * @return local item definition adapter
- */
- ItemDef getItemDef(RemoteItemDef remote);
-
- /**
- * Factory method for creating a local adapter for a remote node
- * definition.
- *
- * @param remote remote node definition
- * @return local node definition adapter
- */
- NodeDef getNodeDef(RemoteNodeDef remote);
-
- /**
- * Factory method for creating a local adapter for a remote property
- * definition.
- *
- * @param remote remote property definition
- * @return local property definition adapter
- */
- PropertyDef getPropertyDef(RemotePropertyDef remote);
-
- /**
- * Factory method for creating a local adapter for a remote lock.
- *
- * @param node current node
- * @param remote remote lock
- * @return local lock adapter
- */
- Lock getLock(Node node, RemoteLock remote);
-
- /**
- * Factory method for creating a local adapter for a remote query manager.
- *
- * @param session current session
- * @param remote remote query manager
- * @return local query manager adapter
- */
- QueryManager getQueryManager(Session session, RemoteQueryManager remote);
-
- /**
- * Factory method for creating a local adapter for a remote query.
- *
- * @param session current session
- * @param remote remote query
- * @return local query adapter
- */
- Query getQuery(Session session, RemoteQuery remote);
-
- /**
- * Factory method for creating a local adapter for a remote query result.
- *
- * @param session current session
- * @param remote remote query result
- * @return local query result adapter
- */
- QueryResult getQueryResult(Session session, RemoteQueryResult remote);
-
- /**
- * Factory method for creating a local adapter for a remote query row.
- *
- * @param remote remote query row
- * @return local query row adapter
- */
- Row getRow(RemoteRow remote);
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/RemoteRepositoryException.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/RemoteRepositoryException.java
deleted file mode 100644
index 0f7d2f32267..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/RemoteRepositoryException.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.client;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.RepositoryException;
-
-/**
- * JCR-RMI remote exception. Used by the JCR-RMI client to wrap RMI errors
- * into RepositoryExceptions to avoid breaking the JCR interfaces.
- *
- * Note that if a RemoteException is received by call with no declared
- * exceptions, then the RemoteException is wrapped into a
- * RemoteRuntimeException.
- *
- * @author Jukka Zitting
- */
-public class RemoteRepositoryException extends RepositoryException {
-
- /**
- * Creates a RemoteRepositoryException based on the given RemoteException.
- *
- * @param ex the remote exception
- */
- public RemoteRepositoryException(RemoteException ex) {
- super(ex);
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/RemoteRuntimeException.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/RemoteRuntimeException.java
deleted file mode 100644
index 80fbf3a011e..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/RemoteRuntimeException.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.client;
-
-import java.rmi.RemoteException;
-
-/**
- * JCR-RMI remote runtime exception. Used by the JCR-RMI client to wrap
- * RMI errors into RuntimeExceptions to avoid breaking the JCR interfaces.
- *
- * Note that if a RemoteException is received by call that declares to
- * throw RepositoryExceptions, then the RemoteException is wrapped into
- * a RemoteRepositoryException.
- *
- * @author Jukka Zitting
- */
-public class RemoteRuntimeException extends RuntimeException {
-
- /**
- * Creates a RemoteRuntimeException based on the given RemoteException.
- *
- * @param ex the remote exception
- */
- public RemoteRuntimeException(RemoteException ex) {
- super(ex);
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/package.html b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/package.html
deleted file mode 100644
index b343705eb0e..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/client/package.html
+++ /dev/null
@@ -1,60 +0,0 @@
-
-Client implementation of the transparent JCR-RMI layer.
-
-This package contains the default client implementation of the
-transparent JCR-RMI layer. The classes in this package can be used
-to make a remote JCR-RMI service seem like a local JCR repository.
-
-The contents of this package is designed using two design patterns,
-Factory and Adapter. All the ClientObject subclasses implement the
-Adapter pattern to adapt a remote JCR-RMI reference to the corresponding
-local JCR interface. The Factory pattern is used to centralize the
-creation and configuration of all adapter instances.
-
-
Looking up a JCR-RMI client
-
-The ClientRepositoryFactory class provides a convenient mechanism for
-looking up a remote JCR-RMI repository. The factory can be used either
-directly or as a JNDI object factory.
-
-The following example shows how to use the ClientRepositoryFactory
-directly:
-
-
- String name = ...; // The RMI URL of the repository
-
- ClientRepositoryFactory factory = new ClientRepositoryFactory();
- Repository repository = factory.getRepository(name);
-
-
-
-The ClientRepositoryFactory can also be used via JNDI. The following
-example settings and code demonstrate how to configure and use the
-transparent JCR-RMI layer in a Tomcat 5.5 web application:
-
-
-Note that in the example above only the context.xml configuration file
-contains a direct references to the JCR-RMI layer. All other parts of the
-web application can be implemented using the standard JCR interfaces.
-
-
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/iterator/ArrayIterator.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/iterator/ArrayIterator.java
deleted file mode 100644
index c956ce6862e..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/iterator/ArrayIterator.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.iterator;
-
-import javax.jcr.RangeIterator;
-
-/**
- * Array implementation of the JCR
- * {@link javax.jcr.RangeIterator RangeIterator} interface. This class
- * implements the RangeIterator functionality for an underlying array
- * of objects. Used as the base class for the type-specific iterator
- * classes defined in this package.
- *
- * @author Jukka Zitting
- */
-public class ArrayIterator implements RangeIterator {
-
- /** The current iterator position. */
- private int position;
-
- /** The underlying array of objects. */
- private Object[] array;
-
- /**
- * Creates an iterator for the given array of objects.
- *
- * @param array the objects to iterate
- */
- public ArrayIterator(Object[] array) {
- this.position = 0;
- this.array = array;
- }
-
- /** {@inheritDoc} */
- public boolean hasNext() {
- return (position < array.length);
- }
-
- /** {@inheritDoc} */
- public Object next() {
- return array[position++];
- }
-
- /** {@inheritDoc} */
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- /** {@inheritDoc} */
- public void skip(long items) {
- position += items;
- }
-
- /** {@inheritDoc} */
- public long getSize() {
- return array.length;
- }
-
- /** {@inheritDoc} */
- public long getPos() {
- return position;
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/iterator/ArrayNodeIterator.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/iterator/ArrayNodeIterator.java
deleted file mode 100644
index 233bd860029..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/iterator/ArrayNodeIterator.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.iterator;
-
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-
-/**
- * Array implementation of the JCR
- * {@link javax.jcr.NodeIterator NodeIterator} interface.
- * This class is used by the JCR-RMI client adapters to convert
- * node arrays to iterators.
- *
- * @author Jukka Zitting
- */
-public class ArrayNodeIterator extends ArrayIterator implements NodeIterator {
-
- /**
- * Creates an iterator for the given array of nodes.
- *
- * @param nodes the nodes to iterate
- */
- public ArrayNodeIterator(Node[] nodes) {
- super(nodes);
- }
-
- /** {@inheritDoc} */
- public Node nextNode() {
- return (Node) next();
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/iterator/ArrayNodeTypeIterator.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/iterator/ArrayNodeTypeIterator.java
deleted file mode 100644
index f41eea5cae3..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/iterator/ArrayNodeTypeIterator.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.iterator;
-
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.nodetype.NodeTypeIterator;
-
-/**
- * Array implementation of the JCR
- * {@link javax.jcr.NodeTypeIterator NodeTypeIterator} interface.
- * This class is used by the JCR-RMI client adapters to convert
- * node type arrays to iterators.
- *
- * @author Jukka Zitting
- */
-public class ArrayNodeTypeIterator extends ArrayIterator implements
- NodeTypeIterator {
-
- /**
- * Creates an iterator for the given array of node types.
- *
- * @param types the node types to iterate
- */
- public ArrayNodeTypeIterator(NodeType[] types) {
- super(types);
- }
-
- /** {@inheritDoc} */
- public NodeType nextNodeType() {
- return (NodeType) next();
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/iterator/ArrayPropertyIterator.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/iterator/ArrayPropertyIterator.java
deleted file mode 100644
index f53e79dbde5..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/iterator/ArrayPropertyIterator.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.iterator;
-
-import javax.jcr.Property;
-import javax.jcr.PropertyIterator;
-
-/**
- * Array implementation of the JCR
- * {@link javax.jcr.PropertyIterator PropertyIterator} interface.
- * This class is used by the JCR-RMI client adapters to convert
- * property arrays to iterators.
- *
- * @author Jukka Zitting
- */
-public class ArrayPropertyIterator extends ArrayIterator
- implements PropertyIterator {
-
- /**
- * Creates an iterator for the given array of properties.
- *
- * @param properties the properties to iterate
- */
- public ArrayPropertyIterator(Property[] properties) {
- super(properties);
- }
-
- /** {@inheritDoc} */
- public Property nextProperty() {
- return (Property) next();
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/iterator/ArrayRowIterator.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/iterator/ArrayRowIterator.java
deleted file mode 100644
index d04d7ae0a94..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/iterator/ArrayRowIterator.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.iterator;
-
-import javax.jcr.query.Row;
-import javax.jcr.query.RowIterator;
-
-/**
- * Array implementation of the JCR
- * {@link javax.jcr.query.RowIterator RowIterator} interface.
- * This class is used by the JCR-RMI client adapters to convert
- * node arrays to iterators.
- *
- * @author Philipp Koch
- */
-public class ArrayRowIterator extends ArrayIterator implements RowIterator {
-
- /**
- * Creates an iterator for the given array of rows.
- *
- * @param rows the rows to iterate
- */
- public ArrayRowIterator(Row[] rows) {
- super(rows);
- }
-
- /** {@inheritDoc} */
- public Row nextRow() {
- return (Row) next();
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/iterator/ArrayVersionIterator.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/iterator/ArrayVersionIterator.java
deleted file mode 100644
index f81cb989b08..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/iterator/ArrayVersionIterator.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.iterator;
-
-import javax.jcr.version.Version;
-import javax.jcr.version.VersionIterator;
-
-/**
- * Array implementation of the JCR
- * {@link javax.jcr.version.VersionIterator VersionIterator} interface.
- * This class is used by the JCR-RMI client adapters to convert
- * version arrays to iterators.
- *
- * @author Felix Meschberger
- */
-public class ArrayVersionIterator extends ArrayIterator implements VersionIterator {
-
- /**
- * Creates an iterator for the given array of nodes.
- *
- * @param versions the versions to iterate
- */
- public ArrayVersionIterator(Version[] versions) {
- super(versions);
- }
-
- /** {@inheritDoc} */
- public Version nextVersion() {
- return (Version) next();
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/iterator/package.html b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/iterator/package.html
deleted file mode 100644
index fc702d1ed1e..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/iterator/package.html
+++ /dev/null
@@ -1,10 +0,0 @@
-
-Utility classes for implementing JCR iterators based on static arrays.
-
-This package contains array-based implementations of the JCR
-{@link javax.jcr.RangeIterator RangeIterator} interfaces.
-
-These utility classes were designed for the transparent JCR-RMI layer,
-but can easily be used as a part of any JCR repository implementation.
-This package depends only on the standard JCR and J2SE APIs.
-
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteItemDef.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteItemDef.java
deleted file mode 100644
index 0e9da275211..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteItemDef.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.remote;
-
-import java.rmi.Remote;
-import java.rmi.RemoteException;
-
-/**
- * Remote version of the JCR {@link javax.jcr.nodetype.ItemDef ItemDef}
- * interface. Used by the
- * {@link org.apache.jackrabbit.rmi.server.ServerItemDef ServerItemDef} and
- * {@link org.apache.jackrabbit.rmi.client.ClientItemDef ClientItemDef}
- * adapter base classes to provide transparent RMI access to remote item
- * definitions.
- *
- * The methods in this interface are documented only with a reference
- * to a corresponding ItemDef method. The remote object will simply forward
- * the method call to the underlying ItemDef instance. Argument and return
- * values, as well as possible exceptions, are copied over the network.
- * Compex {@link javax.jcr.nodetype.NodeType NodeType} return values
- * are returned as remote references to the
- * {@link org.apache.jackrabbit.rmi.remote.RemoteNodeType RemoteNodeType}
- * interface. RMI errors are signalled with RemoteExceptions.
- *
- * @author Jukka Zitting
- * @see javax.jcr.nodetype.ItemDef
- * @see org.apache.jackrabbit.rmi.client.ClientItemDef
- * @see org.apache.jackrabbit.rmi.server.ServerItemDef
- */
-public interface RemoteItemDef extends Remote {
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.ItemDef#getDeclaringNodeType() ItemDef.getDeclaringNodeType()}
- * method.
- *
- * @return declaring node type
- * @throws RemoteException on RMI errors
- */
- RemoteNodeType getDeclaringNodeType() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.ItemDef#getName() ItemDef.getName()} method.
- *
- * @return item name
- * @throws RemoteException on RMI errors
- */
- String getName() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.ItemDef#isAutoCreate() ItemDef.isAutoCreate()}
- * method.
- *
- * @return true if the item is automatically created,
- * false otherwise
- * @throws RemoteException on RMI errors
- */
- boolean isAutoCreate() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.ItemDef#isMandatory() ItemDef.isMandatory()}
- * method.
- *
- * @return true if the item is mandatory,
- * false otherwise
- * @throws RemoteException on RMI errors
- */
- boolean isMandatory() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.ItemDef#getOnParentVersion() ItemDef.getOnParentVersion()}
- * method.
- *
- * @return parent version behaviour
- * @throws RemoteException on RMI errors
- */
- int getOnParentVersion() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.ItemDef#isProtected() ItemDef.isProtected()}
- * method.
- *
- * @return true if the item is protected,
- * false otherwise
- * @throws RemoteException on RMI errors
- */
- boolean isProtected() throws RemoteException;
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteLock.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteLock.java
deleted file mode 100644
index 015ffc3d630..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteLock.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.remote;
-
-import java.rmi.Remote;
-import java.rmi.RemoteException;
-
-import javax.jcr.RepositoryException;
-
-/**
- * Remote version of the JCR {@link javax.jcr.lock.Lock} interface.
- * Used by the {@link org.apache.jackrabbit.rmi.server.ServerLock ServerLock}
- * and {@link org.apache.jackrabbit.rmi.client.ClientLock ClientLock}
- * adapter classes to provide transparent RMI access to remote locks.
- *
- * The methods in this interface are documented only with a reference
- * to a corresponding Lock method. The remote object will simply forward
- * the method call to the underlying Lock instance. Return values and
- * possible exceptions are copied over the network. RMI errors are signalled
- * with RemoteExceptions.
- *
- * @author Jukka Zitting
- * @see javax.jcr.lock.Lock
- * @see org.apache.jackrabbit.rmi.client.ClientLock
- * @see org.apache.jackrabbit.rmi.server.ServerLock
- */
-public interface RemoteLock extends Remote {
-
- /**
- * Remote version of the
- * {@link javax.jcr.lock.Lock#getLockOwner() Lock.getLockOwner()} method.
- *
- * @return lock owner
- * @throws RemoteException on RMI errors
- */
- String getLockOwner() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.lock.Lock#isDeep() Lock.isDeep()} method.
- *
- * @return true if the lock is deep,
- * false otherwise
- * @throws RemoteException on RMI errors
- */
- boolean isDeep() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.lock.Lock#getLockToken() Lock.getLockToken()} method.
- *
- * @return lock token
- * @throws RemoteException on RMI errors
- */
- String getLockToken() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.lock.Lock#isLive() Lock.isLive()} method.
- *
- * @return true if the lock is live,
- * false otherwise
- * @throws RemoteException on RMI errors
- */
- boolean isLive() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.lock.Lock#refresh() Lock.refresh()} method.
- *
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- void refresh() throws RepositoryException, RemoteException;
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteNodeDef.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteNodeDef.java
deleted file mode 100644
index f774a0180f9..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteNodeDef.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.remote;
-
-import java.rmi.RemoteException;
-
-/**
- * Remote version of the JCR {@link javax.jcr.nodetype.NodeDef NodeDef}
- * interface. Used by the
- * {@link org.apache.jackrabbit.rmi.server.ServerNodeDef ServerNodeDef} and
- * {@link org.apache.jackrabbit.rmi.client.ClientNodeDef ClientNodeDef}
- * adapters to provide transparent RMI access to remote node definitions.
- *
- * The methods in this interface are documented only with a reference
- * to a corresponding NodeDef method. The remote object will simply forward
- * the method call to the underlying NodeDef instance. Return values
- * and possible exceptions are copied over the network. Complex
- * {@link javax.jcr.nodetype.NodeType NodeType} return values
- * are returned as remote references to the
- * {@link org.apache.jackrabbit.rmi.remote.RemoteNodeType RemoteNodeType}
- * interface. RMI errors are signalled with RemoteExceptions.
- *
- * @author Jukka Zitting
- * @see javax.jcr.nodetype.NodeDef
- * @see org.apache.jackrabbit.rmi.client.ClientNodeDef
- * @see org.apache.jackrabbit.rmi.server.ServerNodeDef
- */
-public interface RemoteNodeDef extends RemoteItemDef {
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.NodeDef#getRequiredPrimaryTypes() NodeDef.getRequiredPrimaryTypes()}
- * method.
- *
- * @return required primary node types
- * @throws RemoteException on RMI errors
- */
- RemoteNodeType[] getRequiredPrimaryTypes() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.NodeDef#getDefaultPrimaryType() NodeDef.getDefaultPrimaryType()}
- * method.
- *
- * @return default primary node type
- * @throws RemoteException on RMI errors
- */
- RemoteNodeType getDefaultPrimaryType() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.NodeDef#allowSameNameSibs() NodeDef.allowSameNameSibs()}
- * method.
- *
- * @return true if same name siblings are allowed,
- * false otherwise
- * @throws RemoteException on RMI errors
- */
- boolean allowSameNameSibs() throws RemoteException;
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteNodeType.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteNodeType.java
deleted file mode 100644
index 0fa861d5873..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteNodeType.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.remote;
-
-import java.rmi.Remote;
-import java.rmi.RemoteException;
-
-import javax.jcr.Value;
-
-/**
- * Remote version of the JCR {@link javax.jcr.nodetype.NodeType NodeType}
- * interface. Used by the
- * {@link org.apache.jackrabbit.rmi.server.ServerNodeType ServerNodeType} and
- * {@link org.apache.jackrabbit.rmi.client.ClientNodeType ClientNodeType}
- * adapters to provide transparent RMI access to remote node types.
- *
- * The methods in this interface are documented only with a reference
- * to a corresponding NodeType method. The remote object will simply forward
- * the method call to the underlying NodeType instance. Return values
- * and possible exceptions are copied over the network. Complex return
- * values (like NodeTypes and PropertyDefs) are retunred as remote
- * references to the corresponding remote interfaces. RMI errors are
- * signalled with RemoteExceptions.
- *
- * @author Jukka Zitting
- * @see javax.jcr.nodetype.NodeType
- * @see org.apache.jackrabbit.rmi.client.ClientNodeType
- * @see org.apache.jackrabbit.rmi.server.ServerNodeType
- */
-public interface RemoteNodeType extends Remote {
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.NodeType#getName() NodeType.getName()} method.
- *
- * @return node type name
- * @throws RemoteException on RMI errors
- */
- String getName() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.NodeType#isMixin() NodeType.isMixin()} method.
- *
- * @return true if this is a mixin type,
- * false otherwise
- * @throws RemoteException on RMI errors
- */
- boolean isMixin() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.NodeType#hasOrderableChildNodes() NodeType.hasOrderableChildNodes()}
- * method.
- *
- * @return true if nodes of this type has orderable
- * child nodes, false otherwise
- * @throws RemoteException on RMI errors
- */
- boolean hasOrderableChildNodes() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.NodeType#getSupertypes() NodeType.getSupertypes()}
- * method.
- *
- * @return supertypes
- * @throws RemoteException on RMI errors
- */
- RemoteNodeType[] getSupertypes() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.NodeType#getDeclaredSupertypes() NodeType.getDeclaredSupertypes()}
- * method.
- *
- * @return declared supertypes
- * @throws RemoteException on RMI errors
- */
- RemoteNodeType[] getDeclaredSupertypes() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.NodeType#isNodeType(String) NodeType.isNodeType(String)}
- * method.
- *
- * @param type node type name
- * @return true if this node type is or extends the
- * given node type, false otherwise
- * @throws RemoteException on RMI errors
- */
- boolean isNodeType(String type) throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.NodeType#getPropertyDefs() NodeType.getPropertyDefs()}
- * method.
- *
- * @return property definitions
- * @throws RemoteException on RMI errors
- */
- RemotePropertyDef[] getPropertyDefs() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.NodeType#getDeclaredPropertyDefs() NodeType.getDeclaredPropertyDefs()}
- * method.
- *
- * @return declared property definitions
- * @throws RemoteException on RMI errors
- */
- RemotePropertyDef[] getDeclaredPropertyDefs() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.NodeType#getChildNodeDefs() NodeType.getChildNodeDefs()}
- * method.
- *
- * @return child node definitions
- * @throws RemoteException on RMI errors
- */
- RemoteNodeDef[] getChildNodeDefs() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.NodeType#getDeclaredChildNodeDefs() NodeType.getDeclaredChildNodeDefs()}
- * method.
- *
- * @return declared child node definitions
- * @throws RemoteException on RMI errors
- */
- RemoteNodeDef[] getDeclaredChildNodeDefs() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.NodeType#canSetProperty(String,Value) NodeType.canSetProperty(String,Value)}
- * method.
- *
- * @param name property name
- * @param value property value
- * @return true if the property can be set,
- * false otherwise
- * @throws RemoteException on RMI errors
- */
- boolean canSetProperty(String name, Value value) throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.NodeType#canSetProperty(String,Value[]) NodeType.canSetProperty(String,Value[])}
- * method.
- *
- * @param name property name
- * @param values property values
- * @return true if the property can be set,
- * false otherwise
- * @throws RemoteException on RMI errors
- */
- boolean canSetProperty(String name, Value[] values) throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.NodeType#canAddChildNode(String) NodeType.canAddChildNode(String)}
- * method.
- *
- * @param name child node name
- * @return true if the child node can be added,
- * false otherwise
- * @throws RemoteException on RMI errors
- */
- boolean canAddChildNode(String name) throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.NodeType#canAddChildNode(String,String) NodeType.canAddChildNode(String,String)}
- * method.
- *
- * @param name child node name
- * @param type child node type
- * @return true if the child node can be added,
- * false otherwise
- * @throws RemoteException on RMI errors
- */
- boolean canAddChildNode(String name, String type) throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.NodeType#canRemoveItem(String) NodeType.canRemoveItem(String)}
- * method.
- *
- * @param name item name
- * @return true if the item can be removed,
- * false otherwise
- * @throws RemoteException on RMI errors
- */
- boolean canRemoveItem(String name) throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.NodeType#getPrimaryItemName() NodeType.getPrimaryItemName()}
- * method.
- *
- * @return primary item name
- * @throws RemoteException on RMI errors
- */
- String getPrimaryItemName() throws RemoteException;
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemotePropertyDef.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemotePropertyDef.java
deleted file mode 100644
index 8bb133a5fa1..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemotePropertyDef.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.remote;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.Value;
-
-/**
- * Remote version of the JCR {@link javax.jcr.nodetype.PropertyDef PropertyDef}
- * interface. Used by the
- * {@link org.apache.jackrabbit.rmi.server.ServerPropertyDef ServerPropertyDef}
- * and
- * {@link org.apache.jackrabbit.rmi.client.ClientPropertyDef ClientPropertyDef}
- * adapters to provide transparent RMI access to remote property definitions.
- *
- * The methods in this interface are documented only with a reference
- * to a corresponding PropertyDef method. The remote object will simply
- * forward the method call to the underlying PropertyDef instance. Return
- * values and possible exceptions are copied over the network. RMI errors
- * are signalled with RemoteExceptions.
- *
- * Note that returned Value objects must be serializable and implemented
- * using classes available on both the client and server side. The
- * {@link org.apache.jackrabbit.rmi.remote.SerialValue SerialValue}
- * decorator utility provides a convenient way to satisfy these
- * requirements.
- *
- * @author Jukka Zitting
- * @see javax.jcr.nodetype.PropertyDef
- * @see org.apache.jackrabbit.rmi.client.ClientPropertyDef
- * @see org.apache.jackrabbit.rmi.server.ServerPropertyDef
- */
-public interface RemotePropertyDef extends RemoteItemDef {
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.PropertyDef#getRequiredType() PropertyDef.getRequiredType()}
- * method.
- *
- * @return required type
- * @throws RemoteException on RMI errors
- */
- int getRequiredType() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.PropertyDef#getValueConstraints() PropertyDef.getValueConstraints()}
- * method.
- *
- * @return value constraints
- * @throws RemoteException on RMI errors
- */
- String[] getValueConstraints() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.PropertyDef#getDefaultValues() PropertyDef.getDefaultValues()}
- * method.
- *
- * @return default values
- * @throws RemoteException on RMI errors
- */
- Value[] getDefaultValues() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.nodetype.PropertyDef#isMultiple() PropertyDef.isMultiple()}
- * method.
- *
- * @return true if the property is multi-valued,
- * false otherwise
- * @throws RemoteException on RMI errors
- */
- boolean isMultiple() throws RemoteException;
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteQuery.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteQuery.java
deleted file mode 100644
index dc0a61991ee..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteQuery.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.remote;
-
-import java.rmi.Remote;
-import java.rmi.RemoteException;
-
-import javax.jcr.RepositoryException;
-
-/**
- * Remote version of the JCR {@link javax.jcr.query.Query Query} interface.
- * Used by the {@link org.apache.jackrabbit.rmi.server.ServerQuery ServerQuery}
- * and {@link org.apache.jackrabbit.rmi.client.ClientQuery ClientQuery}
- * adapter base classes to provide transparent RMI access to remote items.
- *
- * RMI errors are signalled with RemoteExceptions.
- *
- * @author Philipp Koch
- * @see javax.jcr.query.Query
- * @see org.apache.jackrabbit.rmi.client.ClientQuery
- * @see org.apache.jackrabbit.rmi.server.ServerQuery
- */
-public interface RemoteQuery extends Remote {
-
- /**
- * @see javax.jcr.query.Query#execute()
- *
- * @return a QueryResult
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- RemoteQueryResult execute() throws RepositoryException, RemoteException;
-
- /**
- * @see javax.jcr.query.Query#getStatement()
- *
- * @return the query statement.
- * @throws RemoteException on RMI errors
- */
- String getStatement() throws RemoteException;
-
- /**
- * @see javax.jcr.query.Query#getLanguage()
- *
- * @return the query language.
- * @throws RemoteException on RMI errors
- */
- String getLanguage() throws RemoteException;
-
- /**
- * @see javax.jcr.query.Query#getPersistentQueryPath()
- *
- * @return path of the node representing this query.
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- String getPersistentQueryPath() throws RepositoryException, RemoteException;
-
- /**
- * @see javax.jcr.query.Query#save(String)
- *
- * @param absPath path at which to persist this query.
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- void save(String absPath) throws RepositoryException, RemoteException;
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteQueryResult.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteQueryResult.java
deleted file mode 100644
index c3bd4f2ce54..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteQueryResult.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.remote;
-
-import java.rmi.Remote;
-import java.rmi.RemoteException;
-
-import javax.jcr.RepositoryException;
-
-/**
- * Remote version of the JCR {@link javax.jcr.query.QueryResult QueryResult} interface.
- * Used by the {@link org.apache.jackrabbit.rmi.server.ServerQueryResult ServerQueryResult}
- * and {@link org.apache.jackrabbit.rmi.client.ClientQueryResult ClientQueryResult}
- * adapter base classes to provide transparent RMI access to remote items.
- *
- * RMI errors are signalled with RemoteExceptions.
- *
- * @author Philipp Koch
- * @see javax.jcr.query.QueryResult
- * @see org.apache.jackrabbit.rmi.client.ClientQueryResult
- * @see org.apache.jackrabbit.rmi.server.ServerQueryResult
- */
-public interface RemoteQueryResult extends Remote {
- /**
- * @see javax.jcr.query.QueryResult#getPropertyNames()
- *
- * @return a PropertyIterator
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- String[] getPropertyNames() throws RepositoryException, RemoteException;
-
- /**
- * @see javax.jcr.query.QueryResult#getRows()
- *
- * @return a RowIterator
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- RemoteRow[] getRows() throws RepositoryException, RemoteException;
-
- /**
- * @see javax.jcr.query.QueryResult#getNodes()
- *
- * @return a NodeIterator
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- RemoteNode[] getNodes() throws RepositoryException, RemoteException;
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteRepository.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteRepository.java
deleted file mode 100644
index e8efeac0168..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteRepository.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.remote;
-
-import java.rmi.Remote;
-import java.rmi.RemoteException;
-
-import javax.jcr.Credentials;
-import javax.jcr.RepositoryException;
-
-/**
- * Remote version of the JCR {@link javax.jcr.Repository Repository} interface.
- * Used by the
- * {@link org.apache.jackrabbit.rmi.server.ServerRepository ServerRepository}
- * and
- * {@link org.apache.jackrabbit.rmi.client.ClientRepository ClientRepository}
- * adapters to provide transparent RMI access to remote repositories.
-*
- * The methods in this interface are documented only with a reference
- * to a corresponding Repository method. The remote object will simply
- * forward the method call to the underlying Repository instance.
- * {@link javax.jcr.Session Session} objects are returned as remote references
- * to the {@link RemoteSession RemoteSession} interface. Simple return
- * values and possible exceptions are copied over the network to the client.
- * RMI errors are signalled with RemoteExceptions.
- *
- * @author Jukka Zitting
- * @see javax.jcr.Repository
- * @see org.apache.jackrabbit.rmi.client.ClientRepository
- * @see org.apache.jackrabbit.rmi.server.ServerRepository
- */
-public interface RemoteRepository extends Remote {
-
- /**
- * Remote version of the
- * {@link javax.jcr.Repository#getDescriptor(String) Repository.getDescriptor(String)}
- * method.
- *
- * @param key descriptor key
- * @return descriptor value
- * @throws RemoteException on RMI errors
- */
- String getDescriptor(String key) throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Repository#getDescriptorKeys() Repository.getDescriptorKeys()}
- * method.
- *
- * @return descriptor keys
- * @throws RemoteException on RMI errors
- */
- String[] getDescriptorKeys() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Repository#login() Repository.login(}} method.
- *
- * @return remote session
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- RemoteSession login() throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Repository#login(String) Repository.login(String}}
- * method.
- *
- * @param workspace workspace name
- * @return remote session
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- RemoteSession login(String workspace)
- throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Repository#login(Credentials) Repository.login(Credentials}}
- * method.
- *
- * @param credentials client credentials
- * @return remote session
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- RemoteSession login(Credentials credentials)
- throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Repository#login(Credentials,String) Repository.login(Credentials,String}}
- * method.
- *
- * @param credentials client credentials
- * @param workspace workspace name
- * @return remote session
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- RemoteSession login(Credentials credentials, String workspace)
- throws RepositoryException, RemoteException;
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteRow.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteRow.java
deleted file mode 100644
index 6c82e4a8fcb..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteRow.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.remote;
-
-import java.rmi.Remote;
-import java.rmi.RemoteException;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.Value;
-
-/**
- * Remote version of the JCR {@link javax.jcr.query.Row Row} interface.
- * Used by the {@link org.apache.jackrabbit.rmi.server.ServerRow ServerRow}
- * and {@link org.apache.jackrabbit.rmi.client.ClientRow ClientRow}
- * adapter base classes to provide transparent RMI access to remote items.
- *
- * RMI errors are signalled with RemoteExceptions.
- *
- * @author Philipp Koch
- * @see javax.jcr.query.Row
- * @see org.apache.jackrabbit.rmi.client.ClientRow
- * @see org.apache.jackrabbit.rmi.server.ServerRow
- */
-public interface RemoteRow extends Remote {
-
- /**
- * @see javax.jcr.query.Row#getValues()
- *
- * @return row values
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- Value[] getValues() throws RepositoryException, RemoteException;
-
- /**
- * @see javax.jcr.query.Row#getValue(String)
- *
- * @param propertyName property name
- * @return identified value
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- Value getValue(String propertyName)
- throws RepositoryException, RemoteException;
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteSession.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteSession.java
deleted file mode 100644
index 8d133c214fb..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteSession.java
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.remote;
-
-import java.io.IOException;
-import java.rmi.Remote;
-import java.rmi.RemoteException;
-import java.security.AccessControlException;
-
-import javax.jcr.Credentials;
-import javax.jcr.RepositoryException;
-
-/**
- * Remote version of the JCR {@link javax.jcr.Session Session} interface.
- * Used by the
- * {@link org.apache.jackrabbit.rmi.server.ServerSession ServerSession}
- * and
- * {@link org.apache.jackrabbit.rmi.client.ClientSession ClientSession}
- * adapters to provide transparent RMI access to remote sessions.
- *
- * Most of the methods in this interface are documented only with a reference
- * to a corresponding Session method. In these cases the remote object
- * will simply forward the method call to the underlying Session instance.
- * Complex return values like workspaces and other objects are returned
- * as remote references to the corresponding remote interface. Simple
- * return values and possible exceptions are simply copied over the network
- * to the client. RMI errors are signalled with RemoteExceptions.
- *
- * @author Jukka Zitting
- * @see javax.jcr.Session
- * @see org.apache.jackrabbit.rmi.client.ClientSession
- * @see org.apache.jackrabbit.rmi.server.ServerSession
- */
-public interface RemoteSession extends Remote {
-
- /**
- * Remote version of the
- * {@link javax.jcr.Session#getUserId() Session.getUserId()} method.
- *
- * @return user id
- * @throws RemoteException on RMI errors
- * @see javax.jcr.Session#getUserId()
- */
- String getUserId() throws RemoteException;
-
- /**
- * Returns the named attribute. Note that only serializable
- * attribute values can be transmitted over the network and that
- * the client should have (or be able to fetch) the object class
- * to access the returned value. Failures to meet these conditions
- * are signalled with RemoteExceptions.
- *
- * @param name attribute name
- * @return attribute value
- * @throws RemoteException on RMI errors
- * @see javax.jcr.Session#getAttribute(java.lang.String)
- */
- Object getAttribute(String name) throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Session#getAttributeNames() Session.getAttributeNames()}
- * method.
- *
- * @return attribute names
- * @throws RemoteException on RMI errors
- */
- String[] getAttributeNames() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Session#getWorkspace() Session.getWorkspace()} method.
- *
- * @return workspace
- * @see javax.jcr.Session#getWorkspace()
- * @throws RemoteException on RMI errors
- */
- RemoteWorkspace getWorkspace() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Session#impersonate(Credentials) Session.impersonate(Credentials)}
- * method.
- *
- * @param credentials credentials for the new session
- * @return new session
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- RemoteSession impersonate(Credentials credentials)
- throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Session#getNodeByUUID(String) Session.getNodeByUUID(String)}
- * method.
- *
- * @param uuid node uuid
- * @return node
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- RemoteNode getNodeByUUID(String uuid)
- throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Session#getItem(String) Session.getItem(String)}
- * method.
- *
- * @param path item path
- * @return item
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- RemoteItem getItem(String path) throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Session#itemExists(String) Session.itemExists(String)}
- * method.
- *
- * @param path item path
- * @return true if the item exists,
- * false otherwise
- * @throws RemoteException on RMI errors
- */
- boolean itemExists(String path) throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Session#move(String,String) Session.move(String,String)}
- * method.
- *
- * @param from source path
- * @param to destination path
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- void move(String from, String to)
- throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Session#save() Session.save()} method.
- *
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- void save() throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Session#refresh(boolean) Session.refresh(boolean)}
- * method.
- *
- * @param keepChanges flag to keep transient changes
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- void refresh(boolean keepChanges)
- throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Session#logout() Session.logout()}
- * method.
- *
- * @throws RemoteException on RMI errors
- */
- void logout() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Session#getRootNode() Session.getRootNode()} method.
- *
- * @return root node
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- RemoteNode getRootNode() throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Session#hasPendingChanges() Session.hasPendingChanges()}
- * method.
- *
- * @return true if the session has pending changes,
- * false otherwise
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- boolean hasPendingChanges() throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Session#checkPermission(String,String) Session.checkPermission(String,String)}
- * method.
- *
- * @param path item path
- * @param actions actions
- * @throws AccessControlException if permission is denied
- * @throws RemoteException on RMI errors
- */
- void checkPermission(String path, String actions)
- throws AccessControlException, RemoteException;
-
- /**
- * Imports the system or document view XML data into a subtree of
- * the identified node. Note that the entire XML stream is transferred
- * as a single byte array over the network. This may cause problems with
- * large XML streams. The remote server will wrap the XML data into
- * a {@link java.io.ByteArrayInputStream ByteArrayInputStream} and feed
- * it to the normal importXML method.
- *
- * @param path node path
- * @param xml imported XML document
- * @throws IOException on IO errors
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- * @see javax.jcr.Session#importXML(java.lang.String, java.io.InputStream)
- */
- void importXML(String path, byte[] xml)
- throws IOException, RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Session#setNamespacePrefix(String,String) Session.setNamespacePrefix(String,String)}
- * method.
- *
- * @param prefix namespace prefix
- * @param uri namespace uri
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- void setNamespacePrefix(String prefix, String uri)
- throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Session#getNamespacePrefixes() Session.getNamespacePrefixes()}
- * method.
- *
- * @return namespace prefixes
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- String[] getNamespacePrefixes() throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Session#getNamespaceURI(String) Session.getNamespaceURI(String)}
- * method.
- *
- * @param prefix namespace prefix
- * @return namespace uri
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- String getNamespaceURI(String prefix)
- throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Session#getNamespacePrefix(String) Session.getNamespacePrefix(String)}
- * method.
- *
- * @param uri namespace uri
- * @return namespace prefix
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- String getNamespacePrefix(String uri)
- throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Session#addLockToken(String) Session.addLockToken(String)}
- * method.
- *
- * @param name lock token
- * @throws RemoteException on RMI errors
- */
- void addLockToken(String name) throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Session#getLockTokens() Session.getLockTokens()}
- * method.
- *
- * @return lock tokens
- * @throws RemoteException on RMI errors
- */
- String[] getLockTokens() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.Session#removeLockToken(String) Session.removeLockToken(String)}
- * method.
- *
- * @param name lock token
- * @throws RemoteException on RMI errors
- */
- void removeLockToken(String name) throws RemoteException;
-
- /**
- * Exports the identified repository subtree as a system view XML
- * stream. Note that the entire XML stream is transferred as a
- * single byte array over the network. This may cause problems with
- * large exports. The remote server uses a
- * {@link java.io.ByteArrayOutputStream ByteArrayOutputStream} to capture
- * the XML data written by the normal exportSysView method.
- *
- * @param path node path
- * @param binaryAsLink TODO
- * @param noRecurse TODO
- * @return exported XML document
- * @throws IOException on IO errors
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- * @see javax.jcr.Workspace#exportSysView(java.lang.String, java.io.OutputStream, boolean, boolean)
- */
- byte[] exportSysView(String path, boolean binaryAsLink, boolean noRecurse)
- throws IOException, RepositoryException, RemoteException;
-
- /**
- * Exports the identified repository subtree as a document view XML
- * stream. Note that the entire XML stream is transferred as a
- * single byte array over the network. This may cause problems with
- * large exports. The remote server uses a
- * {@link java.io.ByteArrayOutputStream ByteArrayOutputStream} to capture
- * the XML data written by the normal exportDocView method.
- *
- * @param path node path
- * @param binaryAsLink TODO
- * @param noRecurse TODO
- * @return exported XML document
- * @throws IOException on IO errors
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- * @see javax.jcr.Workspace#exportDocView(java.lang.String, java.io.OutputStream, boolean, boolean)
- */
- byte[] exportDocView(String path, boolean binaryAsLink, boolean noRecurse)
- throws IOException, RepositoryException, RemoteException;
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteVersion.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteVersion.java
deleted file mode 100644
index d7acdd303c9..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteVersion.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.remote;
-
-import java.rmi.RemoteException;
-import java.util.Calendar;
-
-import javax.jcr.RepositoryException;
-
-
-/**
- * Remote version of the JCR {@link javax.jcr.version.Version Version} interface.
- * Used by the {@link org.apache.jackrabbit.rmi.server.ServerVersion ServerVersion}
- * and {@link org.apache.jackrabbit.rmi.client.ClientVersion ClientVersion}
- * adapters to provide transparent RMI access to remote versions.
- *
- * The methods in this interface are documented only with a reference
- * to a corresponding Version method. The remote object will simply forward
- * the method call to the underlying Version instance. Argument and return
- * values, as well as possible exceptions, are copied over the network.
- * Complex return values (like Versions) are returned as remote
- * references to the corresponding remote interfaces. Iterator values
- * are transmitted as object arrays. RMI errors are signalled with
- * RemoteExceptions.
- *
- * @author Felix Meschberger
- * @see javax.jcr.version.Version
- * @see org.apache.jackrabbit.rmi.client.ClientVersion
- * @see org.apache.jackrabbit.rmi.server.ServerVersion
- */
-public interface RemoteVersion extends RemoteNode {
-
- /**
- * Remote version of the
- * {@link javax.jcr.version.Version#getContainingHistory() Version.getContainingHistory()} method.
- *
- * @return a RemoteVersionHistory object.
- *
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
-// RemoteVersionHistory getContainingHistory() throws RepositoryException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.version.Version#getCreated() Version.getCreated()} method.
- *
- * @return a Calendar object.
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- Calendar getCreated() throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.version.Version#getSuccessors() Version.getSuccessors()} method.
- *
- * @return a RemoteVersion array.
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- RemoteVersion[] getSuccessors() throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.version.Version#getPredecessors() Version.getPredecessors()} method.
- *
- * @return a RemoteVersion array.
- * @throws RepositoryException on repository errors
- * @throws RemoteException on RMI errors
- */
- RemoteVersion[] getPredecessors() throws RepositoryException, RemoteException;
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteVersionHistory.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteVersionHistory.java
deleted file mode 100644
index 839647c2b4c..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/RemoteVersionHistory.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.remote;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.RepositoryException;
-
-/**
- * Remote version of the JC
- * {@link javax.jcr.version.VersionHistory VersionHistory} interface. Used by
- * the
- * {@link org.apache.jackrabbit.rmi.server.ServerVersionHistory ServerVersionHistory}
- * and
- * {@link org.apache.jackrabbit.rmi.client.ClientVersionHistory ClientVersionHistory}
- * adapters to provide transparent RMI access to remote version histories.
- *
- * The methods in this interface are documented only with a reference
- * to a corresponding VersionHistory method. The remote object will simply
- * forward the method call to the underlying VersionHistory instance. Argument
- * and return values, as well as possible exceptions, are copied over the
- * network. Complex return values (like Versions) are returned as remote
- * references to the corresponding remote interfaces. Iterator values
- * are transmitted as object arrays. RMI errors are signalled with
- * RemoteExceptions.
- *
- * @author Felix Meschberger
- * @see javax.jcr.version.Version
- * @see org.apache.jackrabbit.rmi.client.ClientVersionHistory
- * @see org.apache.jackrabbit.rmi.server.ServerVersionHistory
- */
-public interface RemoteVersionHistory extends RemoteNode {
-
- /**
- * Remote version of the
- * {@link javax.jcr.version.VersionHistory#getVersionableUUID() VersionHistory.getVersionableUUID()}
- * method.
- *
- * @return the UUID of the versionable node for which this is the version history.
- * @throws RepositoryException if an error occurs.
- * @throws RemoteException on RMI errors
- */
-// String getVersionableUUID() throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.version.VersionHistory#getRootVersion() VersionHistory.getRootVersion()}
- * method.
- *
- * @return a Version object.
- * @throws RepositoryException if an error occurs.
- * @throws RemoteException on RMI errors
- */
- RemoteVersion getRootVersion() throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.version.VersionHistory#getAllVersions() VersionHistory.getAllVersions()}
- * method.
- *
- * @return a VersionIterator object.
- * @throws RepositoryException if an error occurs.
- * @throws RemoteException on RMI errors
- */
- RemoteVersion[] getAllVersions()
- throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.version.VersionHistory#getVersion(String) VersionHistory.getVersion(String)}
- * method.
- *
- * @param versionName a version name
- * @return a Version object.
- * @throws RepositoryException if an error occurs.
- * @throws RemoteException on RMI errors
- */
- RemoteVersion getVersion(String versionName)
- throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.version.VersionHistory#getVersionByLabel(String) VersionHistory.getVersionByLabel(String)}
- * method.
- *
- * @param label a version label
- * @return a Version object.
- * @throws RepositoryException if an error occurs.
- * @throws RemoteException on RMI errors
- */
- RemoteVersion getVersionByLabel(String label)
- throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.version.VersionHistory#addVersionLabel(String, String, boolean)
- * VersionHistory.addVersionLabel(String, String, boolean)}
- * method.
- *
- * @param versionName the name of the version to which the label is to be added.
- * @param label the label to be added.
- * @param moveLabel if true, then if label is already assigned to a version in
- * this version history, it is moved to the new version specified; if false, then attempting
- * to assign an already used label will throw a VersionException.
- *
- * @throws RepositoryException if another error occurs.
- * @throws RemoteException on RMI errors
- */
- void addVersionLabel(String versionName, String label, boolean moveLabel)
- throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.version.VersionHistory#removeVersionLabel(String) VersionHistory.removeVersionLabel(String)}
- * method.
- *
- * @param label a version label
- * @throws RepositoryException if another error occurs.
- * @throws RemoteException on RMI errors
- */
- void removeVersionLabel(String label)
- throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.version.VersionHistory#hasVersionLabel(String) VersionHistory.hasVersionLabel(String)}
- * method.
- *
- * @param label a version label
- * @return a boolean
- * @throws RemoteException on RMI errors
- */
- boolean hasVersionLabel(String label) throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.version.VersionHistory#hasVersionLabel(RemoteVersion, String) hasVersionLabel(RemoteVersion, String)}
- * method.
- *
- * @param versionUUID The UUID of the version whose labels are to be returned.
- * @param label a version label
- * @return a boolean.
- * @throws RepositoryException if another error occurs.
- * @throws RemoteException on RMI errors
- */
- boolean hasVersionLabel(String versionUUID, String label)
- throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.version.VersionHistory#getVersionLabels() VersionHistory.getVersionLabels()}
- * method.
- *
- * @return a String array containing all the labels of the version history
- * @throws RemoteException on RMI errors
- */
- String[] getVersionLabels() throws RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.version.VersionHistory#getVersionLabels(RemoteVersion) VersionHistory.getVersionLabels(RemoteVersion)}
- * method.
- *
- * @param versionUUID The UUID of the version whose labels are to be returned.
- * @return a String array containing all the labels of the given version
- * @throws RepositoryException if another error occurs.
- * @throws RemoteException on RMI errors
- */
- String[] getVersionLabels(String versionUUID)
- throws RepositoryException, RemoteException;
-
- /**
- * Remote version of the
- * {@link javax.jcr.version.VersionHistory#removeVersion(String) VersionHistory.removeVersion(String)}
- * method.
- *
- * @param versionName the name of a version in this version history.
- * @throws RepositoryException if another error occurs.
- * @throws RemoteException on RMI errors
- */
- void removeVersion(String versionName)
- throws RepositoryException, RemoteException;
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/SerialValue.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/SerialValue.java
deleted file mode 100644
index 2b78989e886..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/SerialValue.java
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.remote;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.Serializable;
-import java.util.Calendar;
-
-import javax.jcr.BinaryValue;
-import javax.jcr.BooleanValue;
-import javax.jcr.DateValue;
-import javax.jcr.DoubleValue;
-import javax.jcr.LongValue;
-import javax.jcr.NameValue;
-import javax.jcr.PathValue;
-import javax.jcr.PropertyType;
-import javax.jcr.ReferenceValue;
-import javax.jcr.RepositoryException;
-import javax.jcr.StringValue;
-import javax.jcr.Value;
-import javax.jcr.ValueFormatException;
-
-/**
- * Serializable {@link Value Value} decorator. A SerialValue decorator
- * makes it possible to serialize the contents of a Value object even
- * if the object itself is not serializable. For example the standard
- * JCR Value classes are not serializable.
- *
- * Serialization is achieved by extracting and serializing the type and
- * underlying data of the Value object. On deserialization the type and
- * data information is used to create a standard JCR Value object as
- * a copy of the original value. This makes it possible to copy even
- * system-specific Value instances to a remote JVM that might not contain
- * the implementation class of the original Value object.
- *
- * The SerialValue decorator adds no other functionality to the Value
- * interface. Normal method calls are simply forwarded to the decorated
- * Value object.
- *
- * Note that a decorator object keeps a reference to the underlying value
- * object and uses the standard value access methods to perform serialization.
- * Serialization therefore affects the internal state of the underlying value!
- * On the other hand, the internal state of a value might interfere with the
- * serialization decorator. The safest course of action is to only decorate
- * and serialize fresh value objects and to discard them after serialization.
- *
- * @author Jukka Zitting
- * @see javax.jcr.Value
- * @see java.io.Serializable
- */
-public class SerialValue implements Value, Serializable {
-
- /** Static serial version UID. */
- static final long serialVersionUID = 8070492457339121953L;
-
- /** The decorated value. */
- private Value value;
-
- /**
- * Creates a serialization decorator for the given value.
- *
- * @param value the value to be decorated
- */
- public SerialValue(Value value) {
- this.value = value;
- }
-
- /**
- * Utility method for decorating an array of values. The
- * returned array will contain SerialValue decorators for
- * all the given values. Note that the contents of the
- * original values will only be copied when the decorators
- * are serialized.
- *
- * If the given array is null, then an empty
- * array is returned.
- *
- * @param values the values to be decorated
- * @return array of decorated values
- */
- public static Value[] makeSerialValueArray(Value[] values) {
- if (values != null) {
- Value[] serials = new Value[values.length];
- for (int i = 0; i < values.length; i++) {
- serials[i] = new SerialValue(values[i]);
- }
- return serials;
- } else {
- return new Value[0];
- }
- }
-
- /**
- * Serializes the underlying Value object. Instead of using
- * the normal serialization mechanism, the essential state
- * of the Value object is extracted and written to the serialization
- * stream as a type-value pair.
- *
- * @param out the serialization stream
- * @throws IOException on IO errors
- */
- private void writeObject(ObjectOutputStream out) throws IOException {
- try {
- int type = value.getType();
- out.writeInt(type);
- switch (type) {
- case PropertyType.BINARY:
- InputStream data = value.getStream();
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- byte[] bytes = new byte[4096];
- for (int n = data.read(bytes); n != -1; n = data.read(bytes)) {
- buffer.write(bytes, 0, n);
- }
- out.writeInt(buffer.size());
- buffer.writeTo(out);
- break;
- case PropertyType.BOOLEAN:
- out.writeBoolean(value.getBoolean());
- break;
- case PropertyType.DATE:
- out.writeObject(value.getDate());
- break;
- case PropertyType.DOUBLE:
- out.writeDouble(value.getDouble());
- break;
- case PropertyType.LONG:
- out.writeLong(value.getLong());
- break;
- case PropertyType.NAME:
- case PropertyType.PATH:
- case PropertyType.REFERENCE:
- case PropertyType.STRING:
- out.writeUTF(value.getString());
- break;
- default:
- throw new IOException("Unknown value type");
- }
- } catch (RepositoryException ex) {
- throw new IOException(ex.getMessage());
- }
- }
-
- /**
- * Deserializes the underlying Value object. A new Value object
- * is created based on the type and state data read fro the
- * serialization stream.
- *
- * @param in the serialization stream
- * @throws IOException on IO errors
- */
- private void readObject(ObjectInputStream in) throws IOException {
- try {
- int type = in.readInt();
- switch (type) {
- case PropertyType.BINARY:
- byte[] bytes = new byte[in.readInt()];
- in.readFully(bytes);
- value = new BinaryValue(bytes);
- break;
- case PropertyType.BOOLEAN:
- value = new BooleanValue(in.readBoolean());
- break;
- case PropertyType.DATE:
- value = new DateValue((Calendar) in.readObject());
- break;
- case PropertyType.DOUBLE:
- value = new DoubleValue(in.readDouble());
- break;
- case PropertyType.LONG:
- value = new LongValue(in.readLong());
- break;
- case PropertyType.NAME:
- value = NameValue.valueOf(in.readUTF());
- break;
- case PropertyType.PATH:
- value = PathValue.valueOf(in.readUTF());
- break;
- case PropertyType.REFERENCE:
- value = ReferenceValue.valueOf(in.readUTF());
- break;
- case PropertyType.STRING:
- value = new StringValue(in.readUTF());
- break;
- default:
- throw new IllegalStateException("Illegal serial value type");
- }
- } catch (ValueFormatException ex) {
- throw new IOException(ex.getMessage());
- } catch (ClassNotFoundException ex) {
- throw new IOException(ex.getMessage());
- }
- }
-
- /**
- * Forwards the method call to the decorated value.
- * {@inheritDoc}
- */
- public boolean getBoolean() throws ValueFormatException,
- IllegalStateException, RepositoryException {
- return value.getBoolean();
- }
-
- /**
- * Forwards the method call to the decorated value.
- * {@inheritDoc}
- */
- public Calendar getDate() throws ValueFormatException,
- IllegalStateException, RepositoryException {
- return value.getDate();
- }
-
- /**
- * Forwards the method call to the decorated value.
- * {@inheritDoc}
- */
- public double getDouble() throws ValueFormatException,
- IllegalStateException, RepositoryException {
- return value.getDouble();
- }
-
- /**
- * Forwards the method call to the decorated value.
- * {@inheritDoc}
- */
- public long getLong() throws ValueFormatException, IllegalStateException,
- RepositoryException {
- return value.getLong();
- }
-
- /**
- * Forwards the method call to the decorated value.
- * {@inheritDoc}
- */
- public InputStream getStream() throws ValueFormatException,
- IllegalStateException, RepositoryException {
- return value.getStream();
- }
-
- /**
- * Forwards the method call to the decorated value.
- * {@inheritDoc}
- */
- public String getString() throws ValueFormatException,
- IllegalStateException, RepositoryException {
- return value.getString();
- }
-
- /**
- * Forwards the method call to the decorated value.
- * {@inheritDoc}
- */
- public int getType() {
- return value.getType();
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/package.html b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/package.html
deleted file mode 100644
index 53883a550fc..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/remote/package.html
+++ /dev/null
@@ -1,19 +0,0 @@
-
-Remote interfaces of the transparent JCR-RMI layer.
-
-This package contains all the interfaces and classes used by both
-the client and server sides of the transparent JCR-RMI layer.
-The compiled contents of this package should thus be included
-in both client and server installations. Note also that RMI stubs and
-skeletons need to be generated for all the remote interfaces when using
-old JDK versions (stubs for JDK < 1.5, skeletons for JDK < 1.2).
-
-The interfaces in this package are remote versions of the
-corresponding interfaces in the javax.jcr packages. They are used by
-the adapter classes in the .rmi.client and .rmi.server packages. The server
-classes adapt local JCR objects to the remote interfaces, and the client
-classes adapt the resulting remote references back to the JCR interfaces.
-
-The SerialValue class is a decorator utility used by both the client and
-server classes to safely pass Value objects over the network.
-
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/RemoteAdapterFactory.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/RemoteAdapterFactory.java
deleted file mode 100644
index 6dd5923e355..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/RemoteAdapterFactory.java
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.server;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.Item;
-import javax.jcr.NamespaceRegistry;
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.Repository;
-import javax.jcr.Session;
-import javax.jcr.Workspace;
-import javax.jcr.lock.Lock;
-import javax.jcr.nodetype.ItemDef;
-import javax.jcr.nodetype.NodeDef;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.nodetype.NodeTypeManager;
-import javax.jcr.nodetype.PropertyDef;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryManager;
-import javax.jcr.query.QueryResult;
-import javax.jcr.query.Row;
-import javax.jcr.version.Version;
-import javax.jcr.version.VersionHistory;
-
-import org.apache.jackrabbit.rmi.remote.RemoteItem;
-import org.apache.jackrabbit.rmi.remote.RemoteItemDef;
-import org.apache.jackrabbit.rmi.remote.RemoteLock;
-import org.apache.jackrabbit.rmi.remote.RemoteNamespaceRegistry;
-import org.apache.jackrabbit.rmi.remote.RemoteNode;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeDef;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeType;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeTypeManager;
-import org.apache.jackrabbit.rmi.remote.RemoteProperty;
-import org.apache.jackrabbit.rmi.remote.RemotePropertyDef;
-import org.apache.jackrabbit.rmi.remote.RemoteQuery;
-import org.apache.jackrabbit.rmi.remote.RemoteQueryManager;
-import org.apache.jackrabbit.rmi.remote.RemoteQueryResult;
-import org.apache.jackrabbit.rmi.remote.RemoteRepository;
-import org.apache.jackrabbit.rmi.remote.RemoteRow;
-import org.apache.jackrabbit.rmi.remote.RemoteSession;
-import org.apache.jackrabbit.rmi.remote.RemoteVersion;
-import org.apache.jackrabbit.rmi.remote.RemoteVersionHistory;
-import org.apache.jackrabbit.rmi.remote.RemoteWorkspace;
-
-/**
- * Factory interface for creating remote adapters for local resources.
- * This interface defines how the local JCR interfaces are adapted to
- * remote JCR-RMI references. The adaption mechanism can be
- * modified (for example to add extra features) by changing the
- * remote adapter factory used by the repository server.
- *
- * Note that the {@link ServerObject ServerObject} base class provides
- * a number of utility methods designed to work with a remote adapter
- * factory. Adapter implementations may want to inherit that functionality
- * by subclassing from ServerObject.
- *
- * @author Jukka Zitting
- * @author Philipp Koch
- * @see org.apache.jackrabbit.rmi.client.LocalAdapterFactory
- * @see org.apache.jackrabbit.rmi.server.ServerAdapterFactory
- * @see org.apache.jackrabbit.rmi.server.ServerObject
- */
-public interface RemoteAdapterFactory {
-
- /**
- * Returns a remote adapter for the given local repository.
- *
- * @param repository local repository
- * @return remote repository adapter
- * @throws RemoteException on RMI errors
- */
- RemoteRepository getRemoteRepository(Repository repository)
- throws RemoteException;
-
- /**
- * Returns a remote adapter for the given local session.
- *
- * @param session local session
- * @return remote session adapter
- * @throws RemoteException on RMI errors
- */
- RemoteSession getRemoteSession(Session session) throws RemoteException;
-
- /**
- * Returns a remote adapter for the given local workspace.
- *
- * @param workspace local workspace
- * @return remote workspace adapter
- * @throws RemoteException on RMI errors
- */
- RemoteWorkspace getRemoteWorkspace(Workspace workspace)
- throws RemoteException;
-
- /**
- * Returns a remote adapter for the given local namespace registry.
- *
- * @param registry local namespace registry
- * @return remote namespace registry adapter
- * @throws RemoteException on RMI errors
- */
- RemoteNamespaceRegistry getRemoteNamespaceRegistry(
- NamespaceRegistry registry) throws RemoteException;
-
- /**
- * Returns a remote adapter for the given local node type manager.
- *
- * @param manager local node type manager
- * @return remote node type manager adapter
- * @throws RemoteException on RMI errors
- */
- RemoteNodeTypeManager getRemoteNodeTypeManager(NodeTypeManager manager)
- throws RemoteException;
-
- /**
- * Returns a remote adapter for the given local item. This method
- * will return an adapter that implements only the
- * {@link Item Item} interface. The caller may want to introspect
- * the local item to determine whether to use either the
- * {@link #getRemoteNode(Node) getRemoteNode} or the
- * {@link #getRemoteProperty(Property) getRemoteProperty} method instead.
- *
- * @param item local item
- * @return remote item adapter
- * @throws RemoteException on RMI errors
- */
- RemoteItem getRemoteItem(Item item) throws RemoteException;
-
- /**
- * Returns a remote adapter for the given local property.
- *
- * @param property local property
- * @return remote property adapter
- * @throws RemoteException on RMI errors
- */
- RemoteProperty getRemoteProperty(Property property) throws RemoteException;
-
- /**
- * Returns a remote adapter for the given local node.
- *
- * @param node local node
- * @return remote node adapter
- * @throws RemoteException on RMI errors
- */
- RemoteNode getRemoteNode(Node node) throws RemoteException;
-
- /**
- * Returns a remote adapter for the given local version.
- *
- * @param version local version
- * @return remote version adapter
- * @throws RemoteException on RMI errors
- */
- RemoteVersion getRemoteVersion(Version version) throws RemoteException;
-
- /**
- * Returns a remote adapter for the given local version history.
- *
- * @param versionHistory local version history
- * @return remote version history adapter
- * @throws RemoteException on RMI errors
- */
- RemoteVersionHistory getRemoteVersionHistory(VersionHistory versionHistory)
- throws RemoteException;
-
- /**
- * Returns a remote adapter for the given local node type.
- *
- * @param type local node type
- * @return remote node type adapter
- * @throws RemoteException on RMI errors
- */
- RemoteNodeType getRemoteNodeType(NodeType type) throws RemoteException;
-
- /**
- * Returns a remote adapter for the given local item definition.
- * This method will return an adapter that implements only the
- * {@link ItemDef ItemDef} interface. The caller may want to introspect
- * the local item definition to determine whether to use either the
- * {@link #getRemoteNodeDef(NodeDef) getRemoteNodeDef} or the
- * {@link #getRemotePropertyDef(PropertyDef) getRemotePropertyDef}
- * method instead.
- *
- * @param def local item definition
- * @return remote item definition adapter
- * @throws RemoteException on RMI errors
- */
- RemoteItemDef getRemoteItemDef(ItemDef def) throws RemoteException;
-
- /**
- * Returns a remote adapter for the given local node definition.
- *
- * @param def local node definition
- * @return remote node definition adapter
- * @throws RemoteException on RMI errors
- */
- RemoteNodeDef getRemoteNodeDef(NodeDef def) throws RemoteException;
-
- /**
- * Returns a remote adapter for the given local property definition.
- *
- * @param def local property definition
- * @return remote property definition adapter
- * @throws RemoteException on RMI errors
- */
- RemotePropertyDef getRemotePropertyDef(PropertyDef def)
- throws RemoteException;
-
- /**
- * Returns a remote adapter for the given local lock.
- *
- * @param lock local lock
- * @return remote lock adapter
- * @throws RemoteException on RMI errors
- */
- RemoteLock getRemoteLock(Lock lock) throws RemoteException;
-
- /**
- * Returns a remote adapter for the given local query manager.
- *
- * @param manager local query manager
- * @return remote query manager adapter
- * @throws RemoteException on RMI errors
- */
- RemoteQueryManager getRemoteQueryManager(QueryManager manager)
- throws RemoteException;
-
- /**
- * Returns a remote adapter for the given local query.
- *
- * @param query local query
- * @return remote query adapter
- * @throws RemoteException on RMI errors
- */
- RemoteQuery getRemoteQuery(Query query) throws RemoteException;
-
- /**
- * Returns a remote adapter for the given local query result.
- *
- * @param result local query result
- * @return remote query result adapter
- * @throws RemoteException on RMI errors
- */
- RemoteQueryResult getRemoteQueryResult(QueryResult result)
- throws RemoteException;
-
- /**
- * Returns a remote adapter for the given local query row.
- *
- * @param row local query row
- * @return remote query row adapter
- * @throws RemoteException on RMI errors
- */
- RemoteRow getRemoteRow(Row row) throws RemoteException;
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerAdapterFactory.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerAdapterFactory.java
deleted file mode 100644
index 5a62804bf52..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerAdapterFactory.java
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.server;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.Item;
-import javax.jcr.NamespaceRegistry;
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.Repository;
-import javax.jcr.Session;
-import javax.jcr.Workspace;
-import javax.jcr.lock.Lock;
-import javax.jcr.nodetype.ItemDef;
-import javax.jcr.nodetype.NodeDef;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.nodetype.NodeTypeManager;
-import javax.jcr.nodetype.PropertyDef;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryManager;
-import javax.jcr.query.QueryResult;
-import javax.jcr.query.Row;
-import javax.jcr.version.Version;
-import javax.jcr.version.VersionHistory;
-
-import org.apache.jackrabbit.rmi.remote.RemoteItem;
-import org.apache.jackrabbit.rmi.remote.RemoteItemDef;
-import org.apache.jackrabbit.rmi.remote.RemoteLock;
-import org.apache.jackrabbit.rmi.remote.RemoteNamespaceRegistry;
-import org.apache.jackrabbit.rmi.remote.RemoteNode;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeDef;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeType;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeTypeManager;
-import org.apache.jackrabbit.rmi.remote.RemoteProperty;
-import org.apache.jackrabbit.rmi.remote.RemotePropertyDef;
-import org.apache.jackrabbit.rmi.remote.RemoteQuery;
-import org.apache.jackrabbit.rmi.remote.RemoteQueryManager;
-import org.apache.jackrabbit.rmi.remote.RemoteQueryResult;
-import org.apache.jackrabbit.rmi.remote.RemoteRepository;
-import org.apache.jackrabbit.rmi.remote.RemoteRow;
-import org.apache.jackrabbit.rmi.remote.RemoteSession;
-import org.apache.jackrabbit.rmi.remote.RemoteVersion;
-import org.apache.jackrabbit.rmi.remote.RemoteVersionHistory;
-import org.apache.jackrabbit.rmi.remote.RemoteWorkspace;
-
-/**
- * Default implementation of the
- * {@link RemoteAdapterFactory RemoteAdapterFactory} interface.
- * This factory uses the server adapters defined in this package as
- * the default adapter implementations. Subclasses can override or extend
- * the default adapters by implementing the corresponding factory methods.
- *
- * @author Jukka Zitting
- * @author Philipp Koch
- */
-public class ServerAdapterFactory implements RemoteAdapterFactory {
-
- /**
- * Creates a {@link ServerRepository ServerRepository} instance.
- * {@inheritDoc}
- */
- public RemoteRepository getRemoteRepository(Repository repository)
- throws RemoteException {
- return new ServerRepository(repository, this);
- }
-
- /**
- * Creates a {@link ServerSession ServerSession} instance.
- * {@inheritDoc}
- */
- public RemoteSession getRemoteSession(Session session)
- throws RemoteException {
- return new ServerSession(session, this);
- }
-
- /**
- * Creates a {@link ServerWorkspace ServerWorkspace} instance.
- * {@inheritDoc}
- */
- public RemoteWorkspace getRemoteWorkspace(Workspace workspace)
- throws RemoteException {
- return new ServerWorkspace(workspace, this);
- }
-
- /**
- * Creates a {@link ServerNamespaceRegistry ServerNamespaceRegistry}
- * instance.
- * {@inheritDoc}
- */
- public RemoteNamespaceRegistry getRemoteNamespaceRegistry(
- NamespaceRegistry registry)
- throws RemoteException {
- return new ServerNamespaceRegistry(registry, this);
- }
-
- /**
- * Creates a {@link ServerNodeTypeManager ServerNodeTypeManager} instance.
- * {@inheritDoc}
- */
- public RemoteNodeTypeManager getRemoteNodeTypeManager(
- NodeTypeManager manager)
- throws RemoteException {
- return new ServerNodeTypeManager(manager, this);
- }
-
- /**
- * Creates a {@link ServerItem ServerItem} instance.
- * {@inheritDoc}
- */
- public RemoteItem getRemoteItem(Item item) throws RemoteException {
- return new ServerItem(item, this);
- }
-
- /**
- * Creates a {@link ServerProperty ServerProperty} instance.
- * {@inheritDoc}
- */
- public RemoteProperty getRemoteProperty(Property property)
- throws RemoteException {
- return new ServerProperty(property, this);
- }
-
- /**
- * Creates a {@link ServerNode ServerNode} instance.
- * {@inheritDoc}
- */
- public RemoteNode getRemoteNode(Node node) throws RemoteException {
- return new ServerNode(node, this);
- }
-
- /**
- * Creates a {@link ServerVersion ServerVersion} instance.
- * {@inheritDoc}
- */
- public RemoteVersion getRemoteVersion(Version version) throws RemoteException {
- return new ServerVersion(version, this);
- }
-
- /**
- * Creates a {@link ServerVersionHistory ServerVersionHistory} instance.
- * {@inheritDoc}
- */
- public RemoteVersionHistory getRemoteVersionHistory(VersionHistory versionHistory)
- throws RemoteException {
- return new ServerVersionHistory(versionHistory, this);
- }
-
- /**
- * Creates a {@link ServerNodeType ServerNodeType} instance.
- * {@inheritDoc}
- */
- public RemoteNodeType getRemoteNodeType(NodeType type)
- throws RemoteException {
- return new ServerNodeType(type, this);
- }
-
- /**
- * Creates a {@link ServerItemDef ServerItemDef} instance.
- * {@inheritDoc}
- */
- public RemoteItemDef getRemoteItemDef(ItemDef def)
- throws RemoteException {
- return new ServerItemDef(def, this);
- }
-
- /**
- * Creates a {@link ServerNodeDef ServerNodeDef} instance.
- * {@inheritDoc}
- */
- public RemoteNodeDef getRemoteNodeDef(NodeDef def)
- throws RemoteException {
- return new ServerNodeDef(def, this);
- }
-
- /**
- * Creates a {@link ServerPropertyDef ServerPropertyDef} instance.
- * {@inheritDoc}
- */
- public RemotePropertyDef getRemotePropertyDef(PropertyDef def)
- throws RemoteException {
- return new ServerPropertyDef(def, this);
- }
-
- /**
- * Creates a {@link ServerLock ServerLock} instance.
- * {@inheritDoc}
- */
- public RemoteLock getRemoteLock(Lock lock) throws RemoteException {
- return new ServerLock(lock);
- }
-
- /**
- * Creates a {@link ServerQueryManager ServerQueryManager} instance.
- * {@inheritDoc}
- */
- public RemoteQueryManager getRemoteQueryManager(QueryManager manager)
- throws RemoteException {
- return new ServerQueryManager(manager, this);
- }
-
- /**
- * Creates a {@link ServerQuery ServerQuery} instance.
- * {@inheritDoc}
- */
- public RemoteQuery getRemoteQuery(Query query) throws RemoteException {
- return new ServerQuery(query, this);
- }
-
- /**
- * Creates a {@link ServerQueryResult ServerQueryResult} instance.
- * {@inheritDoc}
- */
- public RemoteQueryResult getRemoteQueryResult(QueryResult result)
- throws RemoteException {
- return new ServerQueryResult(result, this);
- }
-
- /**
- * Creates a {@link ServerQueryResult ServerQueryResult} instance.
- * {@inheritDoc}
- */
- public RemoteRow getRemoteRow(Row row) throws RemoteException {
- return new ServerRow(row, this);
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerItemDef.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerItemDef.java
deleted file mode 100644
index b5a4d9f6447..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerItemDef.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.server;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.nodetype.ItemDef;
-
-import org.apache.jackrabbit.rmi.remote.RemoteItemDef;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeType;
-
-/**
- * Remote adapter for the JCR {@link javax.jcr.nodetype.ItemDef ItemDef}
- * interface. This class makes a local item definition available as an
- * RMI service using the
- * {@link org.apache.jackrabbit.rmi.remote.RemoteItemDef RemoteItemDef}
- * interface. Used mainly as the base class for the
- * {@link org.apache.jackrabbit.rmi.server.ServerPropertyDef ServerPropertyDef}
- * and
- * {@link org.apache.jackrabbit.rmi.server.ServerNodeDef ServerNodeDef}
- * adapters.
- *
- * @author Jukka Zitting
- * @see javax.jcr.nodetype.ItemDef
- * @see org.apache.jackrabbit.rmi.remote.RemoteItemDef
- */
-public class ServerItemDef extends ServerObject implements RemoteItemDef {
-
- /** The adapted local item definition. */
- private ItemDef def;
-
- /**
- * Creates a remote adapter for the given local item definition.
- *
- * @param def local item definition
- * @param factory remote adapter factory
- * @throws RemoteException on RMI errors
- */
- public ServerItemDef(ItemDef def, RemoteAdapterFactory factory)
- throws RemoteException {
- super(factory);
- this.def = def;
- }
-
- /** {@inheritDoc} */
- public RemoteNodeType getDeclaringNodeType() throws RemoteException {
- return getFactory().getRemoteNodeType(def.getDeclaringNodeType());
- }
-
- /** {@inheritDoc} */
- public String getName() throws RemoteException {
- return def.getName();
- }
-
- /** {@inheritDoc} */
- public boolean isAutoCreate() throws RemoteException {
- return def.isAutoCreate();
- }
-
- /** {@inheritDoc} */
- public boolean isMandatory() throws RemoteException {
- return def.isMandatory();
- }
-
- /** {@inheritDoc} */
- public int getOnParentVersion() throws RemoteException {
- return def.getOnParentVersion();
- }
-
- /** {@inheritDoc} */
- public boolean isProtected() throws RemoteException {
- return def.isProtected();
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerLock.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerLock.java
deleted file mode 100644
index ede86cb751b..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerLock.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.server;
-
-import java.rmi.RemoteException;
-import java.rmi.server.UnicastRemoteObject;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.lock.Lock;
-
-import org.apache.jackrabbit.rmi.remote.RemoteLock;
-
-/**
- * Remote adapter for the JCR {@link javax.jcr.lock.Lock Lock} interface.
- * This class makes a local lock available as an RMI service using
- * the {@link org.apache.jackrabbit.rmi.remote.RemoteLock RemoteLock}
- * interface.
- *
- * @author Jukka Zitting
- * @see javax.jcr.lock.Lock
- * @see org.apache.jackrabbit.rmi.remote.RemoteLock
- */
-public class ServerLock extends UnicastRemoteObject implements RemoteLock {
-
- /** The adapted local lock. */
- private Lock lock;
-
- /**
- * Creates a remote adapter for the given local lock.
- *
- * @param lock local lock
- * @throws RemoteException on RMI errors
- */
- public ServerLock(Lock lock) throws RemoteException {
- this.lock = lock;
- }
-
- /** {@inheritDoc} */
- public String getLockOwner() throws RemoteException {
- return lock.getLockOwner();
- }
-
- /** {@inheritDoc} */
- public boolean isDeep() throws RemoteException {
- return lock.isDeep();
- }
-
- /** {@inheritDoc} */
- public String getLockToken() throws RemoteException {
- return lock.getLockToken();
- }
-
- /** {@inheritDoc} */
- public boolean isLive() throws RemoteException {
- return lock.isLive();
- }
-
- /** {@inheritDoc} */
- public void refresh() throws RepositoryException, RemoteException {
- lock.refresh();
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerNode.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerNode.java
deleted file mode 100644
index 57bc6577451..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerNode.java
+++ /dev/null
@@ -1,546 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.server;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.Value;
-import javax.jcr.lock.Lock;
-import javax.jcr.version.Version;
-
-import org.apache.jackrabbit.rmi.remote.RemoteItem;
-import org.apache.jackrabbit.rmi.remote.RemoteLock;
-import org.apache.jackrabbit.rmi.remote.RemoteNode;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeDef;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeType;
-import org.apache.jackrabbit.rmi.remote.RemoteProperty;
-import org.apache.jackrabbit.rmi.remote.RemoteVersion;
-import org.apache.jackrabbit.rmi.remote.RemoteVersionHistory;
-
-/**
- * Remote adapter for the JCR {@link javax.jcr.Node Node} interface.
- * This class makes a local node available as an RMI service using
- * the {@link org.apache.jackrabbit.rmi.remote.RemoteNode RemoteNode}
- * interface.
- *
- * @author Jukka Zitting
- * @see javax.jcr.Node
- * @see org.apache.jackrabbit.rmi.remote.RemoteNode
- */
-public class ServerNode extends ServerItem implements RemoteNode {
-
- /** The adapted local node. */
- private Node node;
-
- /**
- * Creates a remote adapter for the given local node.
- *
- * @param node local node
- * @param factory remote adapter factory
- * @throws RemoteException on RMI errors
- */
- public ServerNode(Node node, RemoteAdapterFactory factory)
- throws RemoteException {
- super(node, factory);
- this.node = node;
- }
-
- /** {@inheritDoc} */
- public RemoteNode addNode(String path)
- throws RepositoryException, RemoteException {
- try {
- return getRemoteNode(node.addNode(path));
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteNode addNode(String path, String type)
- throws RepositoryException, RemoteException {
- try {
- return getRemoteNode(node.addNode(path, type));
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteProperty getProperty(String path)
- throws RepositoryException, RemoteException {
- try {
- return getFactory().getRemoteProperty(node.getProperty(path));
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteProperty[] getProperties()
- throws RepositoryException, RemoteException {
- try {
- return getRemotePropertyArray(node.getProperties());
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteItem getPrimaryItem()
- throws RepositoryException, RemoteException {
- try {
- return getRemoteItem(node.getPrimaryItem());
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteProperty[] getProperties(String pattern)
- throws RepositoryException, RemoteException {
- try {
- return getRemotePropertyArray(node.getProperties(pattern));
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteProperty[] getReferences()
- throws RepositoryException, RemoteException {
- try {
- return getRemotePropertyArray(node.getReferences());
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String getUUID() throws RepositoryException, RemoteException {
- try {
- return node.getUUID();
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean hasNodes() throws RepositoryException, RemoteException {
- try {
- return node.hasNodes();
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean hasProperties() throws RepositoryException, RemoteException {
- try {
- return node.hasProperties();
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean hasProperty(String path)
- throws RepositoryException, RemoteException {
- try {
- return node.hasProperty(path);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteNodeType[] getMixinNodeTypes()
- throws RepositoryException, RemoteException {
- try {
- return getRemoteNodeTypeArray(node.getMixinNodeTypes());
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteNodeType getPrimaryNodeType()
- throws RepositoryException, RemoteException {
- try {
- return getFactory().getRemoteNodeType(node.getPrimaryNodeType());
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean isNodeType(String type)
- throws RepositoryException, RemoteException {
- try {
- return node.isNodeType(type);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteNode[] getNodes() throws RepositoryException, RemoteException {
- try {
- return getRemoteNodeArray(node.getNodes());
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteNode[] getNodes(String pattern)
- throws RepositoryException, RemoteException {
- try {
- return getRemoteNodeArray(node.getNodes(pattern));
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteNode getNode(String path)
- throws RepositoryException, RemoteException {
- try {
- return getRemoteNode(node.getNode(path));
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean hasNode(String path)
- throws RepositoryException, RemoteException {
- try {
- return node.hasNode(path);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteProperty setProperty(String name, Value value)
- throws RepositoryException, RemoteException {
- try {
- return getFactory().getRemoteProperty(node.setProperty(name, value));
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void addMixin(String name)
- throws RepositoryException, RemoteException {
- try {
- node.addMixin(name);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean canAddMixin(String name)
- throws RepositoryException, RemoteException {
- try {
- return node.canAddMixin(name);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void removeMixin(String name)
- throws RepositoryException, RemoteException {
- try {
- node.removeMixin(name);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void orderBefore(String src, String dst)
- throws RepositoryException, RemoteException {
- try {
- node.orderBefore(src, dst);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteProperty setProperty(String name, Value[] values)
- throws RepositoryException, RemoteException {
- try {
- Property property = node.setProperty(name, values);
- return getFactory().getRemoteProperty(property);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteNodeDef getDefinition()
- throws RepositoryException, RemoteException {
- try {
- return getFactory().getRemoteNodeDef(node.getDefinition());
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteVersion checkin() throws RepositoryException, RemoteException {
- try {
- return getFactory().getRemoteVersion(node.checkin());
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void checkout() throws RepositoryException, RemoteException {
- try {
- node.checkout();
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String getCorrespondingNodePath(String workspace)
- throws RepositoryException, RemoteException {
- try {
- return node.getCorrespondingNodePath(workspace);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public int getIndex() throws RepositoryException, RemoteException {
- try {
- return node.getIndex();
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void merge(String workspace, boolean bestEffort)
- throws RepositoryException, RemoteException {
- try {
- node.merge(workspace, bestEffort);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void cancelMerge(String versionUUID)
- throws RepositoryException, RemoteException {
- try {
- node.cancelMerge(getVersionByUUID(versionUUID));
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void doneMerge(String versionUUID)
- throws RepositoryException, RemoteException {
- try {
- node.doneMerge(getVersionByUUID(versionUUID));
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void restore(String version, boolean removeExisting)
- throws RepositoryException, RemoteException {
- try {
- node.restore(version, removeExisting);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void restoreByUUID(String versionUUID, boolean removeExisting)
- throws RepositoryException, RemoteException {
- try {
- node.restore(getVersionByUUID(versionUUID), removeExisting);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void restore(String versionUUID, String path, boolean removeExisting)
- throws RepositoryException, RemoteException {
- try {
- node.restore(getVersionByUUID(versionUUID), path, removeExisting);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void restoreByLabel(String label, boolean removeExisting)
- throws RepositoryException, RemoteException {
- try {
- node.restoreByLabel(label, removeExisting);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void update(String workspace)
- throws RepositoryException, RemoteException {
- try {
- node.update(workspace);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean holdsLock() throws RepositoryException, RemoteException {
- try {
- return node.holdsLock();
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean isCheckedOut() throws RepositoryException, RemoteException {
- try {
- return node.isCheckedOut();
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteVersionHistory getVersionHistory()
- throws RepositoryException, RemoteException {
- try {
- return getFactory().getRemoteVersionHistory(node.getVersionHistory());
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteVersion getBaseVersion()
- throws RepositoryException, RemoteException {
- try {
- return getFactory().getRemoteVersion(node.getBaseVersion());
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean isLocked() throws RepositoryException, RemoteException {
- try {
- return node.isLocked();
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteProperty setProperty(String name, Value[] values, int type)
- throws RepositoryException, RemoteException {
- try {
- Property property = node.setProperty(name, values, type);
- return getFactory().getRemoteProperty(property);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void unlock() throws RepositoryException, RemoteException {
- try {
- node.unlock();
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteLock getLock() throws RepositoryException, RemoteException {
- try {
- return getFactory().getRemoteLock(node.getLock());
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteLock lock(boolean isDeep, boolean isSessionScoped)
- throws RepositoryException, RemoteException {
- try {
- Lock lock = node.lock(isDeep, isSessionScoped);
- return getFactory().getRemoteLock(lock);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- //---------- Implementation helper -----------------------------------------
-
- /**
- * Returns the {@link Version} instance for the given UUID.
- *
- * @param versionUUID The UUID of the version.
- *
- * @return The version node.
- *
- * @throws RepositoryException if an error occurrs accessing the version
- * node or if the UUID does not denote a version.
- */
- protected Version getVersionByUUID(String versionUUID)
- throws RepositoryException {
-
- // get the version node by its UUID from the version history's session
- Session session = node.getSession();
- Node versionNode = session.getNodeByUUID(versionUUID);
-
- // check whether the node is a session, which it should be according
- // to the spec (methods returning nodes should automatically return
- // the correct type).
- if (versionNode instanceof Version) {
- return (Version) versionNode;
- }
-
- // otherwise fail
- throw new RepositoryException("Cannot find version " + versionUUID);
- }
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerNodeDef.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerNodeDef.java
deleted file mode 100644
index 389f721d9b1..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerNodeDef.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.server;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.nodetype.NodeDef;
-
-import org.apache.jackrabbit.rmi.remote.RemoteNodeDef;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeType;
-
-/**
- * Remote adapter for the JCR {@link javax.jcr.nodetype.NodeDef NodeDef}
- * interface. This class makes a local node definition available as an
- * RMI service using the
- * {@link org.apache.jackrabbit.rmi.remote.RemoteNodeDef RemoteNodeDef}
- * interface.
- *
- * @author Jukka Zitting
- * @see javax.jcr.nodetype.NodeDef
- * @see org.apache.jackrabbit.rmi.remote.RemoteNodeDef
- */
-public class ServerNodeDef extends ServerItemDef implements RemoteNodeDef {
-
- /** The adapted node definition. */
- private NodeDef def;
-
- /**
- * Creates a remote adapter for the given local node definition.
- *
- * @param def local node definition
- * @param factory remote adapter factory
- * @throws RemoteException on RMI errors
- */
- public ServerNodeDef(NodeDef def, RemoteAdapterFactory factory)
- throws RemoteException {
- super(def, factory);
- this.def = def;
- }
-
- /** {@inheritDoc} */
- public RemoteNodeType[] getRequiredPrimaryTypes() throws RemoteException {
- return getRemoteNodeTypeArray(def.getRequiredPrimaryTypes());
- }
-
- /** {@inheritDoc} */
- public RemoteNodeType getDefaultPrimaryType() throws RemoteException {
- return getFactory().getRemoteNodeType(def.getDefaultPrimaryType());
- }
-
- /** {@inheritDoc} */
- public boolean allowSameNameSibs() throws RemoteException {
- return def.allowSameNameSibs();
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerNodeType.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerNodeType.java
deleted file mode 100644
index 313ef4104f1..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerNodeType.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.server;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.Value;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.nodetype.PropertyDef;
-
-import org.apache.jackrabbit.rmi.remote.RemoteNodeDef;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeType;
-import org.apache.jackrabbit.rmi.remote.RemotePropertyDef;
-
-/**
- * Remote adapter for the JCR {@link javax.jcr.nodetype.NodeType NodeType}
- * interface. This class makes a local node type available as an RMI service
- * using the
- * {@link org.apache.jackrabbit.rmi.remote.RemoteNodeType RemoteNodeType}
- * interface.
- *
- * @author Jukka Zitting
- * @see javax.jcr.nodetype.NodeType
- * @see org.apache.jackrabbit.rmi.remote.RemoteNodeType
- */
-public class ServerNodeType extends ServerObject implements RemoteNodeType {
-
- /** The adapted local node type. */
- private NodeType type;
-
- /**
- * Creates a remote adapter for the given local node type.
- *
- * @param type local node type
- * @param factory remote adapter factory
- * @throws RemoteException on RMI errors
- */
- public ServerNodeType(NodeType type, RemoteAdapterFactory factory)
- throws RemoteException {
- super(factory);
- this.type = type;
- }
-
- /** {@inheritDoc} */
- public String getName() throws RemoteException {
- return type.getName();
- }
-
- /** {@inheritDoc} */
- public boolean isMixin() throws RemoteException {
- return type.isMixin();
- }
-
- /** {@inheritDoc} */
- public boolean hasOrderableChildNodes() throws RemoteException {
- return type.hasOrderableChildNodes();
- }
-
- /** {@inheritDoc} */
- public RemoteNodeType[] getSupertypes() throws RemoteException {
- return getRemoteNodeTypeArray(type.getSupertypes());
- }
-
- /** {@inheritDoc} */
- public RemoteNodeType[] getDeclaredSupertypes() throws RemoteException {
- return getRemoteNodeTypeArray(type.getDeclaredSupertypes());
- }
-
- /** {@inheritDoc} */
- public boolean isNodeType(String type) throws RemoteException {
- return this.type.isNodeType(type);
- }
-
- /** {@inheritDoc} */
- public RemotePropertyDef[] getPropertyDefs() throws RemoteException {
- PropertyDef[] defs = type.getPropertyDefs();
- return getRemotePropertyDefArray(defs);
- }
-
- /** {@inheritDoc} */
- public RemotePropertyDef[] getDeclaredPropertyDefs()
- throws RemoteException {
- PropertyDef[] defs = type.getDeclaredPropertyDefs();
- return getRemotePropertyDefArray(defs);
- }
-
- /** {@inheritDoc} */
- public RemoteNodeDef[] getChildNodeDefs() throws RemoteException {
- return getRemoteNodeDefArray(type.getChildNodeDefs());
- }
-
- /** {@inheritDoc} */
- public RemoteNodeDef[] getDeclaredChildNodeDefs() throws RemoteException {
- return getRemoteNodeDefArray(type.getDeclaredChildNodeDefs());
- }
-
- /** {@inheritDoc} */
- public boolean canSetProperty(String name, Value value)
- throws RemoteException {
- return type.canSetProperty(name, value);
- }
-
- /** {@inheritDoc} */
- public boolean canSetProperty(String name, Value[] values)
- throws RemoteException {
- return type.canSetProperty(name, values);
- }
-
- /** {@inheritDoc} */
- public boolean canAddChildNode(String name) throws RemoteException {
- return type.canAddChildNode(name);
- }
-
- /** {@inheritDoc} */
- public boolean canAddChildNode(String name, String type)
- throws RemoteException {
- return this.type.canAddChildNode(name, type);
- }
-
- /** {@inheritDoc} */
- public boolean canRemoveItem(String name) throws RemoteException {
- return type.canRemoveItem(name);
- }
-
- /** {@inheritDoc} */
- public String getPrimaryItemName() throws RemoteException {
- return type.getPrimaryItemName();
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerNodeTypeManager.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerNodeTypeManager.java
deleted file mode 100644
index f95d6aad53e..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerNodeTypeManager.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.server;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.nodetype.NodeTypeManager;
-
-import org.apache.jackrabbit.rmi.remote.RemoteNodeType;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeTypeManager;
-
-/**
- * Remote adapter for the JCR
- * {@link javax.jcr.nodetype.NodeTypeManager NodeTypeManager}
- * interface. This class makes a local node type manager available as an
- * RMI service using the
- * {@link org.apache.jackrabbit.rmi.remote.RemoteNodeTypeManager RemoteNodeTypeManager}
- * interface.
- *
- * @author Jukka Zitting
- * @see javax.jcr.nodetype.NodeTypeManager
- * @see org.apache.jackrabbit.rmi.remote.RemoteNodeTypeManager
- */
-public class ServerNodeTypeManager extends ServerObject
- implements RemoteNodeTypeManager {
-
- /** The adapted local node type manager. */
- private NodeTypeManager manager;
-
- /**
- * Creates a remote adapter for the given local node type manager.
- *
- * @param manager local node type manager
- * @param factory remote adapter factory
- * @throws RemoteException on RMI errors
- */
- public ServerNodeTypeManager(
- NodeTypeManager manager, RemoteAdapterFactory factory)
- throws RemoteException {
- super(factory);
- this.manager = manager;
- }
-
- /** {@inheritDoc} */
- public RemoteNodeType getNodeType(String name)
- throws RepositoryException, RemoteException {
- try {
- return getFactory().getRemoteNodeType(manager.getNodeType(name));
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteNodeType[] getAllNodeTypes()
- throws RepositoryException, RemoteException {
- try {
- return getRemoteNodeTypeArray(manager.getAllNodeTypes());
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteNodeType[] getPrimaryNodeTypes()
- throws RepositoryException, RemoteException {
- try {
- return getRemoteNodeTypeArray(manager.getPrimaryNodeTypes());
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteNodeType[] getMixinNodeTypes()
- throws RepositoryException, RemoteException {
- try {
- return getRemoteNodeTypeArray(manager.getMixinNodeTypes());
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerObject.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerObject.java
deleted file mode 100644
index 07589e81bf2..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerObject.java
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.server;
-
-import java.rmi.RemoteException;
-import java.rmi.server.UnicastRemoteObject;
-
-import javax.jcr.AccessDeniedException;
-import javax.jcr.InvalidItemStateException;
-import javax.jcr.InvalidSerializedDataException;
-import javax.jcr.Item;
-import javax.jcr.ItemExistsException;
-import javax.jcr.ItemNotFoundException;
-import javax.jcr.LoginException;
-import javax.jcr.MergeException;
-import javax.jcr.NamespaceException;
-import javax.jcr.NoSuchWorkspaceException;
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.PathNotFoundException;
-import javax.jcr.Property;
-import javax.jcr.PropertyIterator;
-import javax.jcr.ReferentialIntegrityException;
-import javax.jcr.RepositoryException;
-import javax.jcr.UnsupportedRepositoryOperationException;
-import javax.jcr.ValueFormatException;
-import javax.jcr.lock.LockException;
-import javax.jcr.nodetype.ConstraintViolationException;
-import javax.jcr.nodetype.NoSuchNodeTypeException;
-import javax.jcr.nodetype.NodeDef;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.nodetype.NodeTypeIterator;
-import javax.jcr.nodetype.PropertyDef;
-import javax.jcr.query.InvalidQueryException;
-import javax.jcr.version.Version;
-import javax.jcr.version.VersionException;
-import javax.jcr.version.VersionHistory;
-import javax.jcr.version.VersionIterator;
-
-import org.apache.jackrabbit.rmi.remote.RemoteItem;
-import org.apache.jackrabbit.rmi.remote.RemoteNode;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeDef;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeType;
-import org.apache.jackrabbit.rmi.remote.RemoteProperty;
-import org.apache.jackrabbit.rmi.remote.RemotePropertyDef;
-import org.apache.jackrabbit.rmi.remote.RemoteVersion;
-
-/**
- * Base class for remote adapters. The purpose of this class is to
- * centralize the handling of the RemoteAdapterFactory instance used
- * to instantiate new server adapters.
- *
- * @author Jukka Zitting
- */
-public class ServerObject extends UnicastRemoteObject {
-
- /** Factory for creating server adapters. */
- private RemoteAdapterFactory factory;
-
- /**
- * Creates a basic server adapter that uses the given factory
- * to create new adapters.
- *
- * @param factory remote adapter factory
- * @throws RemoteException on RMI errors
- */
- protected ServerObject(RemoteAdapterFactory factory)
- throws RemoteException {
- this.factory = factory;
- }
-
- /**
- * Returns the remote adapter factory used to create new adapters.
- *
- * @return remote adapter factory
- */
- protected RemoteAdapterFactory getFactory() {
- return factory;
- }
-
- /**
- * Returns a cleaned version of the given exception. In some cases
- * the underlying repository implementation may throw exceptions
- * that are either unserializable, use exception subclasses that are
- * only locally available, contain references to unserializable or
- * only locally available classes. This method returns a cleaned
- * version of such an exception. The returned exception contains only
- * the message string from the original exception, and uses the public
- * JCR exception class that most specifically matches the original
- * exception.
- *
- * @param ex the original exception
- * @return clean exception
- */
- protected RepositoryException getRepositoryException(
- RepositoryException ex) {
- if (ex instanceof AccessDeniedException) {
- return new AccessDeniedException(ex.getMessage());
- } else if (ex instanceof ConstraintViolationException) {
- return new ConstraintViolationException(ex.getMessage());
- } else if (ex instanceof InvalidItemStateException) {
- return new InvalidItemStateException(ex.getMessage());
- } else if (ex instanceof InvalidQueryException) {
- return new InvalidQueryException(ex.getMessage());
- } else if (ex instanceof InvalidSerializedDataException) {
- return new InvalidSerializedDataException(ex.getMessage());
- } else if (ex instanceof ItemExistsException) {
- return new ItemExistsException(ex.getMessage());
- } else if (ex instanceof ItemNotFoundException) {
- return new ItemNotFoundException(ex.getMessage());
- } else if (ex instanceof LockException) {
- return new LockException(ex.getMessage());
- } else if (ex instanceof LoginException) {
- return new LoginException(ex.getMessage());
- } else if (ex instanceof MergeException) {
- return new MergeException(ex.getMessage());
- } else if (ex instanceof NamespaceException) {
- return new NamespaceException(ex.getMessage());
- } else if (ex instanceof NoSuchNodeTypeException) {
- return new NoSuchNodeTypeException(ex.getMessage());
- } else if (ex instanceof NoSuchWorkspaceException) {
- return new NoSuchWorkspaceException(ex.getMessage());
- } else if (ex instanceof PathNotFoundException) {
- return new PathNotFoundException(ex.getMessage());
- } else if (ex instanceof ReferentialIntegrityException) {
- return new ReferentialIntegrityException(ex.getMessage());
- } else if (ex instanceof UnsupportedRepositoryOperationException) {
- return new UnsupportedRepositoryOperationException(ex.getMessage());
- } else if (ex instanceof ValueFormatException) {
- return new ValueFormatException(ex.getMessage());
- } else if (ex instanceof VersionException) {
- return new VersionException(ex.getMessage());
- } else {
- return new RepositoryException(ex.getMessage());
- }
- }
-
- /**
- * Utility method for creating a remote reference for a local item.
- * Unlike the factory method for creating remote item references, this
- * method introspects the type of the local item and returns the
- * corresponding node, property, or item remote reference using the
- * remote adapter factory.
- *
- * If the item, this method calls the
- * {@link #getRemoteNode(Node)} to return the correct remote type.
- *
- * @param item local node, property, or item
- * @return remote node, property, or item reference
- * @throws RemoteException on RMI errors
- */
- protected RemoteItem getRemoteItem(Item item) throws RemoteException {
- if (item instanceof Property) {
- return factory.getRemoteProperty((Property) item);
- } else if (item instanceof Node) {
- return getRemoteNode((Node) item);
- } else {
- return factory.getRemoteItem(item);
- }
- }
-
- /**
- * Utility method for creating a remote reference for a local node.
- * Unlike the factory method for creating remote node references, this
- * method introspects the type of the local node and returns the
- * corresponding node, version, or version history remote reference using
- * the remote adapter factory.
- *
- * @param node local version, versionhistory, or normal node
- * @return remote node, property, or item reference
- * @throws RemoteException on RMI errors
- */
- protected RemoteNode getRemoteNode(Node node) throws RemoteException {
- if (node instanceof Version) {
- return factory.getRemoteVersion((Version) node);
- } else if (node instanceof VersionHistory) {
- return factory.getRemoteVersionHistory((VersionHistory) node);
- } else {
- return factory.getRemoteNode(node);
- }
- }
-
- /**
- * Utility method for creating an array of remote references for
- * local properties. The remote references are created using the
- * remote adapter factory.
- *
- * A null input is treated as an empty iterator.
- *
- * @param iterator local property iterator
- * @return remote property array
- * @throws RemoteException on RMI errors
- */
- protected RemoteProperty[] getRemotePropertyArray(PropertyIterator iterator)
- throws RemoteException {
- if (iterator == null) {
- return new RemoteProperty[0]; // for safety
- }
-
- RemoteProperty[] remotes = new RemoteProperty[(int) iterator.getSize()];
- for (int i = 0; iterator.hasNext(); i++) {
- remotes[i] = factory.getRemoteProperty(iterator.nextProperty());
- }
- return remotes;
- }
-
- /**
- * Utility method for creating an array of remote references for
- * local nodes. The remote references are created using the
- * remote adapter factory.
- *
- * A null input is treated as an empty iterator.
- *
- * @param iterator local node iterator
- * @return remote node array
- * @throws RemoteException on RMI errors
- */
- protected RemoteNode[] getRemoteNodeArray(NodeIterator iterator)
- throws RemoteException {
- if (iterator != null) {
- RemoteNode[] remotes = new RemoteNode[(int) iterator.getSize()];
- for (int i = 0; iterator.hasNext(); i++) {
- remotes[i] = getRemoteNode(iterator.nextNode());
- }
- return remotes;
- } else {
- return new RemoteNode[0]; // for safety
- }
- }
-
- /**
- * Utility method for creating an array of remote references for
- * local versions. The remote references are created using the
- * remote adapter factory.
- *
- * A null input is treated as an empty array.
- *
- * @param versions local version array
- * @return remote version array
- * @throws RemoteException on RMI errors
- */
- protected RemoteVersion[] getRemoteVersionArray(Version[] versions)
- throws RemoteException {
- if (versions != null) {
- RemoteVersion[] remotes = new RemoteVersion[versions.length];
- for (int i = 0; i < remotes.length; i++) {
- remotes[i] = factory.getRemoteVersion(versions[i]);
- }
- return remotes;
- } else {
- return new RemoteVersion[0]; // for safety
- }
- }
-
- /**
- * Utility method for creating an array of remote references for
- * local versions. The remote references are created using the
- * remote adapter factory.
- *
- * A null input is treated as an empty iterator.
- *
- * @param iterator local version iterator
- * @return remote version array
- * @throws RemoteException on RMI errors
- */
- protected RemoteVersion[] getRemoteVersionArray(VersionIterator iterator)
- throws RemoteException {
- if (iterator != null) {
- RemoteVersion[] remotes = new RemoteVersion[(int) iterator.getSize()];
- for (int i = 0; iterator.hasNext(); i++) {
- remotes[i] = factory.getRemoteVersion(iterator.nextVersion());
- }
- return remotes;
- } else {
- return new RemoteVersion[0]; // for safety
- }
- }
-
- /**
- * Utility method for creating an array of remote references for
- * local node types. The remote references are created using the
- * remote adapter factory.
- *
- * A null input is treated as an empty array.
- *
- * @param types local node type array
- * @return remote node type array
- * @throws RemoteException on RMI errors
- */
- protected RemoteNodeType[] getRemoteNodeTypeArray(NodeType[] types)
- throws RemoteException {
- if (types != null) {
- RemoteNodeType[] remotes = new RemoteNodeType[types.length];
- for (int i = 0; i < types.length; i++) {
- remotes[i] = factory.getRemoteNodeType(types[i]);
- }
- return remotes;
- } else {
- return new RemoteNodeType[0]; // for safety
- }
- }
-
- /**
- * Utility method for creating an array of remote references for
- * local node types. The remote references are created using the
- * remote adapter factory.
- *
- * A null input is treated as an empty iterator.
- *
- * @param iterator local node type iterator
- * @return remote node type array
- * @throws RemoteException on RMI errors
- */
- protected RemoteNodeType[] getRemoteNodeTypeArray(NodeTypeIterator iterator)
- throws RemoteException {
- if (iterator != null) {
- RemoteNodeType[] remotes =
- new RemoteNodeType[(int) iterator.getSize()];
- for (int i = 0; iterator.hasNext(); i++) {
- remotes[i] = factory.getRemoteNodeType(iterator.nextNodeType());
- }
- return remotes;
- } else {
- return new RemoteNodeType[0]; // for safety
- }
- }
-
- /**
- * Utility method for creating an array of remote references for
- * local node definitions. The remote references are created using the
- * remote adapter factory.
- *
- * A null input is treated as an empty array.
- *
- * @param defs local node definition array
- * @return remote node definition array
- * @throws RemoteException on RMI errors
- */
- protected RemoteNodeDef[] getRemoteNodeDefArray(NodeDef[] defs)
- throws RemoteException {
- if (defs != null) {
- RemoteNodeDef[] remotes = new RemoteNodeDef[defs.length];
- for (int i = 0; i < defs.length; i++) {
- remotes[i] = factory.getRemoteNodeDef(defs[i]);
- }
- return remotes;
- } else {
- return new RemoteNodeDef[0]; // for safety
- }
- }
-
- /**
- * Utility method for creating an array of remote references for
- * local property definitions. The remote references are created using the
- * remote adapter factory.
- *
- * A null input is treated as an empty array.
- *
- * @param defs local property definition array
- * @return remote property definition array
- * @throws RemoteException on RMI errors
- */
- protected RemotePropertyDef[] getRemotePropertyDefArray(PropertyDef[] defs)
- throws RemoteException {
- if (defs != null) {
- RemotePropertyDef[] remotes = new RemotePropertyDef[defs.length];
- for (int i = 0; i < defs.length; i++) {
- remotes[i] = factory.getRemotePropertyDef(defs[i]);
- }
- return remotes;
- } else {
- return new RemotePropertyDef[0]; // for safety
- }
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerPropertyDef.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerPropertyDef.java
deleted file mode 100644
index 51d0d4a28e6..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerPropertyDef.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.server;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.Value;
-import javax.jcr.nodetype.PropertyDef;
-
-import org.apache.jackrabbit.rmi.remote.RemotePropertyDef;
-import org.apache.jackrabbit.rmi.remote.SerialValue;
-
-/**
- * Remote adapter for the JCR
- * {@link javax.jcr.nodetype.PropertyDef PropertyDef} interface. This
- * class makes a local property definition available as an RMI service
- * using the
- * {@link org.apache.jackrabbit.rmi.remote.RemotePropertyDef RemotePropertyDef}
- * interface.
- *
- * @author Jukka Zitting
- * @see javax.jcr.nodetype.PropertyDef
- * @see org.apache.jackrabbit.rmi.remote.RemotePropertyDef
- */
-public class ServerPropertyDef extends ServerItemDef
- implements RemotePropertyDef {
-
- /** The adapted local property definition. */
- private PropertyDef def;
-
- /**
- * Creates a remote adapter for the given local property definition.
- *
- * @param def local property definition
- * @param factory remote adapter factory
- * @throws RemoteException on RMI errors
- */
- public ServerPropertyDef(PropertyDef def, RemoteAdapterFactory factory)
- throws RemoteException {
- super(def, factory);
- this.def = def;
- }
-
- /** {@inheritDoc} */
- public int getRequiredType() throws RemoteException {
- return def.getRequiredType();
- }
-
- /** {@inheritDoc} */
- public String[] getValueConstraints() throws RemoteException {
- return def.getValueConstraints();
- }
-
- /** {@inheritDoc} */
- public Value[] getDefaultValues() throws RemoteException {
- return SerialValue.makeSerialValueArray(def.getDefaultValues());
- }
-
- /** {@inheritDoc} */
- public boolean isMultiple() throws RemoteException {
- return def.isMultiple();
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerQuery.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerQuery.java
deleted file mode 100644
index 4510f5f115f..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerQuery.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.server;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.query.Query;
-
-import org.apache.jackrabbit.rmi.remote.RemoteQuery;
-import org.apache.jackrabbit.rmi.remote.RemoteQueryResult;
-
-/**
- * Remote adapter for the JCR {@link javax.jcr.query.Query Query} interface.
- * This class makes a local session available as an RMI service using the
- * {@link org.apache.jackrabbit.rmi.remote.RemoteQuery RemoteQuery}
- * interface.
- *
- * @author Philipp Koch
- * @see javax.jcr.query.Query
- * @see org.apache.jackrabbit.rmi.remote.RemoteQuery
- */
-public class ServerQuery extends ServerObject implements RemoteQuery {
-
- /** The adapted local query manager. */
- private Query query;
-
- /**
- * Creates a remote adapter for the given local Query.
- *
- * @param query local Query
- * @param factory remote adapter factory
- * @throws RemoteException on RMI errors
- */
- public ServerQuery(Query query, RemoteAdapterFactory factory)
- throws RemoteException {
- super(factory);
- this.query = query;
- }
-
- /** {@inheritDoc} */
- public RemoteQueryResult execute()
- throws RepositoryException, RemoteException {
- return new ServerQueryResult(query.execute(), getFactory());
- }
-
- /** {@inheritDoc} */
- public String getStatement() throws RemoteException {
- return query.getStatement();
- }
-
- /** {@inheritDoc} */
- public String getLanguage() throws RemoteException {
- return query.getLanguage();
- }
-
- /** {@inheritDoc} */
- public String getPersistentQueryPath()
- throws RepositoryException, RemoteException {
- return query.getPersistentQueryPath();
- }
-
- /** {@inheritDoc} */
- public void save(String absPath)
- throws RepositoryException, RemoteException {
- query.save(absPath);
- }
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerQueryManager.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerQueryManager.java
deleted file mode 100644
index 26ce7f032c7..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerQueryManager.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.server;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryManager;
-
-import org.apache.jackrabbit.rmi.remote.RemoteQuery;
-import org.apache.jackrabbit.rmi.remote.RemoteQueryManager;
-
-/**
- * Remote adapter for the JCR {@link javax.jcr.query.QueryManager QueryManager}
- * interface. This class makes a local query manager available as an RMI
- * service using the
- * {@link org.apache.jackrabbit.rmi.remote.RemoteQueryManager RemoteQueryManager}
- * interface.
- *
- * @author Philipp Koch
- * @see javax.jcr.query.QueryManager
- * @see org.apache.jackrabbit.rmi.remote.RemoteQueryManager
- */
-public class ServerQueryManager extends ServerObject
- implements RemoteQueryManager {
-
- /** The adapted local query manager. */
- private QueryManager manager;
-
- /**
- * Creates a remote adapter for the given local query manager.
- *
- * @param manager local query manager
- * @param factory remote adapter factory
- * @throws RemoteException on RMI errors
- */
- public ServerQueryManager(
- QueryManager manager, ServerAdapterFactory factory)
- throws RemoteException {
- super(factory);
- this.manager = manager;
- }
-
- /** {@inheritDoc} */
- public RemoteQuery createQuery(String statement, String language)
- throws RepositoryException, RemoteException {
- try {
- Query query = manager.createQuery(statement, language);
- return getFactory().getRemoteQuery(query);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteQuery getQuery(String absPath)
- throws RepositoryException, RemoteException {
- try {
- Node node = null; // TODO
- return getFactory().getRemoteQuery(manager.getQuery(node));
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String[] getSupportedQueryLanguages() throws RemoteException {
- return manager.getSupportedQueryLanguages();
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerQueryResult.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerQueryResult.java
deleted file mode 100644
index 60616929934..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerQueryResult.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.server;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.NodeIterator;
-import javax.jcr.RepositoryException;
-import javax.jcr.query.QueryResult;
-import javax.jcr.query.RowIterator;
-
-import org.apache.jackrabbit.rmi.remote.RemoteNode;
-import org.apache.jackrabbit.rmi.remote.RemoteQueryResult;
-import org.apache.jackrabbit.rmi.remote.RemoteRow;
-
-/**
- * Remote adapter for the JCR {@link javax.jcr.query.QueryResult QueryResult} interface.
- * This class makes a local session available as an RMI service using the
- * {@link org.apache.jackrabbit.rmi.remote.RemoteQueryResult RemoteQueryResult}
- * interface.
- *
- * @author Philipp Koch
- * @see javax.jcr.query.QueryResult
- * @see org.apache.jackrabbit.rmi.remote.RemoteQueryResult
- */
-public class ServerQueryResult extends ServerObject
- implements RemoteQueryResult {
-
- /** The adapted local query result. */
- private QueryResult result;
-
- /**
- * Creates a remote adapter for the given local QueryResult.
- *
- * @param result local QueryResult
- * @param factory remote adapter factory
- * @throws RemoteException on RMI errors
- */
- public ServerQueryResult(QueryResult result, RemoteAdapterFactory factory)
- throws RemoteException {
- super(factory);
- this.result = result;
- }
-
- /** {@inheritDoc} */
- public String[] getPropertyNames()
- throws RepositoryException, RemoteException {
- return result.getPropertyNames();
- }
-
- /** {@inheritDoc} */
- public RemoteRow[] getRows() throws RepositoryException, RemoteException {
- RowIterator iterator = result.getRows();
- if (iterator != null) {
- RemoteRow[] remotes = new RemoteRow[(int) iterator.getSize()];
- for (int i = 0; iterator.hasNext(); i++) {
- remotes[i] = getFactory().getRemoteRow(iterator.nextRow());
- }
- return remotes;
- } else {
- return new RemoteRow[0]; // for safety
- }
- }
-
- /** {@inheritDoc} */
- public RemoteNode[] getNodes() throws RepositoryException, RemoteException {
- NodeIterator iterator = result.getNodes();
- if (iterator != null) {
- RemoteNode[] remotes = new RemoteNode[(int) iterator.getSize()];
- for (int i = 0; iterator.hasNext(); i++) {
- remotes[i] = getRemoteNode(iterator.nextNode());
- }
- return remotes;
- } else {
- return new RemoteNode[0]; // for safety
- }
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerRepository.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerRepository.java
deleted file mode 100644
index abc1425ae34..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerRepository.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.server;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.Credentials;
-import javax.jcr.Repository;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.apache.jackrabbit.rmi.remote.RemoteRepository;
-import org.apache.jackrabbit.rmi.remote.RemoteSession;
-
-/**
- * Remote adapter for the JCR {@link javax.jcr.Repository Repository}
- * interface. This class makes a local repository available as an RMI service
- * using the
- * {@link org.apache.jackrabbit.rmi.remote.RemoteRepository RemoteRepository}
- * interface.
- *
- * @author Jukka Zitting
- * @see javax.jcr.Repository
- * @see org.apache.jackrabbit.rmi.remote.RemoteRepository
- */
-public class ServerRepository extends ServerObject implements RemoteRepository {
-
- /** The adapted local repository. */
- private Repository repository;
-
- /**
- * Creates a remote adapter for the given local repository.
- *
- * @param repository local repository
- * @param factory remote adapter factory
- * @throws RemoteException on RMI errors
- */
- public ServerRepository(
- Repository repository, RemoteAdapterFactory factory)
- throws RemoteException {
- super(factory);
- this.repository = repository;
- }
-
- /** {@inheritDoc} */
- public String getDescriptor(String name) throws RemoteException {
- return repository.getDescriptor(name);
- }
-
- /** {@inheritDoc} */
- public String[] getDescriptorKeys() throws RemoteException {
- return repository.getDescriptorKeys();
- }
-
- /** {@inheritDoc} */
- public RemoteSession login() throws RepositoryException, RemoteException {
- try {
- Session session = repository.login();
- return getFactory().getRemoteSession(session);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteSession login(String workspace)
- throws RepositoryException, RemoteException {
- try {
- Session session = repository.login(workspace);
- return getFactory().getRemoteSession(session);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteSession login(Credentials credentials)
- throws RepositoryException, RemoteException {
- try {
- Session session = repository.login(credentials);
- return getFactory().getRemoteSession(session);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteSession login(Credentials credentials, String workspace)
- throws RepositoryException, RemoteException {
- try {
- Session session = repository.login(credentials, workspace);
- return getFactory().getRemoteSession(session);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerRow.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerRow.java
deleted file mode 100644
index 99c2c913a33..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerRow.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.server;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.Value;
-import javax.jcr.query.Row;
-
-import org.apache.jackrabbit.rmi.remote.RemoteRow;
-
-/**
- * Remote adapter for the JCR {@link javax.jcr.query.Row Row} interface.
- * This class makes a local session available as an RMI service using the
- * {@link org.apache.jackrabbit.rmi.remote.RemoteRow RemoteRow}
- * interface.
- *
- * @author Philipp Koch
- * @see javax.jcr.query.Row
- * @see org.apache.jackrabbit.rmi.remote.RemoteRow
- */
-public class ServerRow extends ServerObject implements RemoteRow {
-
- /** The adapted local row. */
- private Row row;
-
- /**
- * Creates a remote adapter for the given local query row.
- *
- * @param row local query row
- * @param factory remote adapter factory
- * @throws RemoteException on RMI errors
- */
- public ServerRow(Row row, RemoteAdapterFactory factory)
- throws RemoteException {
- super(factory);
- this.row = row;
- }
-
- /** {@inheritDoc} */
- public Value[] getValues() throws RepositoryException, RemoteException {
- return row.getValues();
- }
-
- /** {@inheritDoc} */
- public Value getValue(String propertyName)
- throws RepositoryException, RemoteException {
- return row.getValue(propertyName);
- }
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerSession.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerSession.java
deleted file mode 100644
index 72c327758fc..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerSession.java
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.server;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.rmi.RemoteException;
-import java.security.AccessControlException;
-
-import javax.jcr.Credentials;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-
-import org.apache.jackrabbit.rmi.remote.RemoteItem;
-import org.apache.jackrabbit.rmi.remote.RemoteNode;
-import org.apache.jackrabbit.rmi.remote.RemoteSession;
-import org.apache.jackrabbit.rmi.remote.RemoteWorkspace;
-
-/**
- * Remote adapter for the JCR {@link javax.jcr.Session Session} interface.
- * This class makes a local session available as an RMI service using the
- * {@link org.apache.jackrabbit.rmi.remote.RemoteSession RemoteSession}
- * interface.
- *
- * @author Jukka Zitting
- * @see javax.jcr.Session
- * @see org.apache.jackrabbit.rmi.remote.RemoteSession
- */
-public class ServerSession extends ServerObject implements RemoteSession {
-
- /** The adapted local session. */
- private Session session;
-
- /**
- * Creates a remote adapter for the given local session.
- *
- * @param session local session
- * @param factory remote adapter factory
- * @throws RemoteException on RMI errors
- */
- public ServerSession(Session session, RemoteAdapterFactory factory)
- throws RemoteException {
- super(factory);
- this.session = session;
- }
-
- /** {@inheritDoc} */
- public String getUserId() throws RemoteException {
- return session.getUserId();
- }
-
- /** {@inheritDoc} */
- public Object getAttribute(String name) throws RemoteException {
- return session.getAttribute(name);
- }
-
- /** {@inheritDoc} */
- public String[] getAttributeNames() throws RemoteException {
- return session.getAttributeNames();
- }
-
- /** {@inheritDoc} */
- public RemoteSession impersonate(Credentials credentials)
- throws RepositoryException, RemoteException {
- try {
- Session newSession = session.impersonate(credentials);
- return getFactory().getRemoteSession(newSession);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteWorkspace getWorkspace() throws RemoteException {
- return getFactory().getRemoteWorkspace(session.getWorkspace());
- }
-
- /** {@inheritDoc} */
- public void checkPermission(String path, String actions)
- throws AccessControlException, RemoteException {
- session.checkPermission(path, actions);
- }
-
- /** {@inheritDoc} */
- public String getNamespacePrefix(String uri)
- throws RepositoryException, RemoteException {
- try {
- return session.getNamespacePrefix(uri);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String[] getNamespacePrefixes()
- throws RepositoryException, RemoteException {
- try {
- return session.getNamespacePrefixes();
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String getNamespaceURI(String prefix)
- throws RepositoryException, RemoteException {
- try {
- return session.getNamespaceURI(prefix);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void setNamespacePrefix(String prefix, String uri)
- throws RepositoryException, RemoteException {
- try {
- session.setNamespacePrefix(prefix, uri);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean itemExists(String path) throws RemoteException {
- return session.itemExists(path);
- }
-
- /** {@inheritDoc} */
- public RemoteNode getNodeByUUID(String uuid)
- throws RepositoryException, RemoteException {
- try {
- return getRemoteNode(session.getNodeByUUID(uuid));
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteNode getRootNode()
- throws RepositoryException, RemoteException {
- try {
- return getRemoteNode(session.getRootNode());
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteItem getItem(String path)
- throws RepositoryException, RemoteException {
- try {
- return getRemoteItem(session.getItem(path));
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean hasPendingChanges()
- throws RepositoryException, RemoteException {
- try {
- return session.hasPendingChanges();
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void move(String from, String to)
- throws RepositoryException, RemoteException {
- try {
- session.move(from, to);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void save() throws RepositoryException, RemoteException {
- try {
- session.save();
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void refresh(boolean keepChanges)
- throws RepositoryException, RemoteException {
- try {
- session.refresh(keepChanges);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void logout() throws RemoteException {
- session.logout();
- }
-
- /** {@inheritDoc} */
- public void importXML(String path, byte[] xml)
- throws IOException, RepositoryException, RemoteException {
- try {
- session.importXML(path, new ByteArrayInputStream(xml));
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void addLockToken(String token) throws RemoteException {
- session.addLockToken(token);
- }
-
- /** {@inheritDoc} */
- public String[] getLockTokens() throws RemoteException {
- return session.getLockTokens();
- }
-
- /** {@inheritDoc} */
- public void removeLockToken(String token) throws RemoteException {
- session.removeLockToken(token);
- }
-
- /** {@inheritDoc} */
- public byte[] exportDocView(
- String path, boolean binaryAsLink, boolean noRecurse)
- throws IOException, RepositoryException, RemoteException {
- try {
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- session.exportDocView(path, buffer, binaryAsLink, noRecurse);
- return buffer.toByteArray();
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public byte[] exportSysView(
- String path, boolean binaryAsLink, boolean noRecurse)
- throws IOException, RepositoryException, RemoteException {
- try {
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- session.exportSysView(path, buffer, binaryAsLink, noRecurse);
- return buffer.toByteArray();
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerVersion.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerVersion.java
deleted file mode 100644
index b2063b4ee30..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerVersion.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.server;
-
-import java.rmi.RemoteException;
-import java.util.Calendar;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.version.Version;
-
-import org.apache.jackrabbit.rmi.remote.RemoteVersion;
-
-/**
- * Remote adapter for the JCR {@link javax.jcr.version.Version Version} interface.
- * This class makes a local version available as an RMI service using
- * the {@link org.apache.jackrabbit.rmi.remote.RemoteVersion RemoteVersion}
- * interface.
- *
- * @author Felix Meschberger
- * @see javax.jcr.version.Version
- * @see org.apache.jackrabbit.rmi.remote.RemoteVersion
- */
-public class ServerVersion extends ServerNode implements RemoteVersion {
-
- /** The adapted local version. */
- private Version version;
-
- /**
- * Creates a remote adapter for the given local version.
- *
- * @param version local version
- * @param factory remote adapter factory
- * @throws RemoteException on RMI errors
- */
- public ServerVersion(Version version, RemoteAdapterFactory factory)
- throws RemoteException {
- super(version, factory);
- this.version = version;
- }
-
-// This is only available after 0.16.2
-// /** {@inheritDoc} */
-// public RemoteVersionHistory getContainingHistory() throws RepositoryException {
-// try {
-// return getFactory().getRemoteVersionHistory(version.getContainingHistory());
-// } catch (RepositoryException ex) {
-// throw getRepositoryException(ex);
-// }
-// }
-
- /** {@inheritDoc} */
- public Calendar getCreated() throws RepositoryException {
- try {
- return version.getCreated();
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteVersion[] getSuccessors() throws RepositoryException, RemoteException {
- try {
- return getRemoteVersionArray(version.getSuccessors());
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteVersion[] getPredecessors() throws RepositoryException, RemoteException {
- try {
- return getRemoteVersionArray(version.getPredecessors());
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerVersionHistory.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerVersionHistory.java
deleted file mode 100644
index 3d8d63c769c..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerVersionHistory.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.server;
-
-import java.rmi.RemoteException;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.version.Version;
-import javax.jcr.version.VersionHistory;
-
-import org.apache.jackrabbit.rmi.remote.RemoteVersion;
-import org.apache.jackrabbit.rmi.remote.RemoteVersionHistory;
-
-/**
- * Remote adapter for the JCR {@link javax.jcr.version.VersionHistory VersionHistory}
- * interface. This class makes a local version history available as an RMI
- * service using the
- * {@link org.apache.jackrabbit.rmi.remote.RemoteVersionHistory RemoteVersionHistory}
- * interface.
- *
- * @author Felix Meschberger
- * @see javax.jcr.version.VersionHistory
- * @see org.apache.jackrabbit.rmi.remote.RemoteVersionHistory
- */
-public class ServerVersionHistory extends ServerNode
- implements RemoteVersionHistory {
-
- /** The adapted local version history. */
- private VersionHistory versionHistory;
-
- /**
- * Creates a remote adapter for the given local version history.
- *
- * @param versionHistory local version history
- * @param factory remote adapter factory
- * @throws RemoteException on RMI errors
- */
- public ServerVersionHistory(VersionHistory versionHistory,
- RemoteAdapterFactory factory) throws RemoteException {
- super(versionHistory, factory);
- this.versionHistory = versionHistory;
- }
-
- /** {@inheritDoc} */
-// public String getVersionableUUID()
-// throws RepositoryException, RemoteException {
-// try {
-// return versionHistory.getVersionableUUID();
-// } catch (RepositoryException ex) {
-// throw getRepositoryException(ex);
-// }
-// }
-
- /** {@inheritDoc} */
- public RemoteVersion getRootVersion()
- throws RepositoryException, RemoteException {
- try {
- return getFactory().getRemoteVersion(versionHistory.getRootVersion());
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteVersion[] getAllVersions()
- throws RepositoryException, RemoteException {
- try {
- return getRemoteVersionArray(versionHistory.getAllVersions());
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteVersion getVersion(String versionName)
- throws RepositoryException, RemoteException {
- try {
- Version version = versionHistory.getVersion(versionName);
- return getFactory().getRemoteVersion(version);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteVersion getVersionByLabel(String label)
- throws RepositoryException, RemoteException {
- try {
- Version version = versionHistory.getVersionByLabel(label);
- return getFactory().getRemoteVersion(version);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void addVersionLabel(String versionName, String label,
- boolean moveLabel) throws RepositoryException, RemoteException {
- try {
- versionHistory.addVersionLabel(versionName, label, moveLabel);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void removeVersionLabel(String label) throws RepositoryException,
- RemoteException {
- try {
- versionHistory.removeVersionLabel(label);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public boolean hasVersionLabel(String label) throws RemoteException {
- return versionHistory.hasVersionLabel(label);
- }
-
- /** {@inheritDoc} */
- public boolean hasVersionLabel(String versionUUID, String label)
- throws RepositoryException, RemoteException {
- try {
- Version version = getVersionByUUID(versionUUID);
- return versionHistory.hasVersionLabel(version, label);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String[] getVersionLabels() throws RemoteException {
- return versionHistory.getVersionLabels();
- }
-
- /** {@inheritDoc} */
- public String[] getVersionLabels(String versionUUID)
- throws RepositoryException, RemoteException {
- try {
- Version version = getVersionByUUID(versionUUID);
- return versionHistory.getVersionLabels(version);
- } catch (ClassCastException cce) {
- // we do not expect this here as nodes should be returned correctly
- throw getRepositoryException(new RepositoryException(cce));
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void removeVersion(String versionName)
- throws RepositoryException, RemoteException {
- try {
- versionHistory.removeVersion(versionName);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerWorkspace.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerWorkspace.java
deleted file mode 100644
index 0aabda47186..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/ServerWorkspace.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.server;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.rmi.RemoteException;
-
-import javax.jcr.NamespaceRegistry;
-import javax.jcr.RepositoryException;
-import javax.jcr.Workspace;
-import javax.jcr.nodetype.NodeTypeManager;
-import javax.jcr.query.QueryManager;
-
-import org.apache.jackrabbit.rmi.remote.RemoteNamespaceRegistry;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeTypeManager;
-import org.apache.jackrabbit.rmi.remote.RemoteQueryManager;
-import org.apache.jackrabbit.rmi.remote.RemoteWorkspace;
-
-/**
- * Remote adapter for the JCR {@link Workspace Workspace} interface.
- * This class makes a local workspace available as an RMI service using the
- * {@link RemoteWorkspace RemoteWorkspace} interface.
- *
- * @see Workspace
- * @see RemoteWorkspace
- */
-public class ServerWorkspace extends ServerObject implements RemoteWorkspace {
-
- /** The adapted local workspace. */
- private Workspace workspace;
-
- /**
- * Creates a remote adapter for the given local workspace.
- *
- * @param workspace local workspace
- * @param factory remote adapter factory
- * @throws RemoteException on RMI errors
- */
- public ServerWorkspace(Workspace workspace, RemoteAdapterFactory factory)
- throws RemoteException {
- super(factory);
- this.workspace = workspace;
- }
-
- /** {@inheritDoc} */
- public String getName() throws RemoteException {
- return workspace.getName();
- }
-
- /** {@inheritDoc} */
- public void copy(String from, String to)
- throws RepositoryException, RemoteException {
- try {
- workspace.copy(from, to);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void copy(String from, String to, String workspace)
- throws RepositoryException, RemoteException {
- try {
- this.workspace.copy(from, to, workspace);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void clone(
- String workspace, String from, String to, boolean removeExisting)
- throws RepositoryException, RemoteException {
- try {
- this.workspace.clone(workspace, from, to, removeExisting);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void move(String from, String to)
- throws RepositoryException, RemoteException {
- try {
- workspace.move(from, to);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteNodeTypeManager getNodeTypeManager()
- throws RepositoryException, RemoteException {
- try {
- NodeTypeManager manager = workspace.getNodeTypeManager();
- return getFactory().getRemoteNodeTypeManager(manager);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteNamespaceRegistry getNamespaceRegistry()
- throws RepositoryException, RemoteException {
- try {
- NamespaceRegistry registry = workspace.getNamespaceRegistry();
- return getFactory().getRemoteNamespaceRegistry(registry);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public RemoteQueryManager getQueryManager()
- throws RepositoryException, RemoteException {
- try {
- QueryManager queryManager = workspace.getQueryManager();
- return getFactory().getRemoteQueryManager(queryManager);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public String[] getAccessibleWorkspaceNames()
- throws RepositoryException, RemoteException {
- try {
- return workspace.getAccessibleWorkspaceNames();
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void importXML(String path, byte[] xml, int uuidBehaviour)
- throws IOException, RepositoryException, RemoteException {
- try {
- workspace.importXML(
- path, new ByteArrayInputStream(xml), uuidBehaviour);
- } catch (RepositoryException ex) {
- throw getRepositoryException(ex);
- }
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/package.html b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/package.html
deleted file mode 100644
index 9244e3fd966..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/server/package.html
+++ /dev/null
@@ -1,64 +0,0 @@
-
-Server implementation of the transparent JCR-RMI layer.
-
-This package contains the default server implementation of the
-transparent JCR-RMI layer. The classes in this package can be used
-to make a local JCR repository available as an RMI service. In addition,
-this package offers a straightforward mechanism for extending or modifying
-the behaviour of the server layer.
-
-The contents of this package is designed using two design patterns,
-Factory and Adapter. All the remotely accessible ServerObject subclasses
-implement the Adapter pattern to adapt a local JCR interface to the
-corresponding remote JCR-RMI interface. The Factory pattern is used
-to centralize the creation and configuration of all adapter instances.
-
-
Setting up a JCR-RMI server
-
-Setting up the server part of the JCR-RMI layer is quite straightforward.
-After instantiating a local JCR repository you need to wrap it into a
-remote adapter and create an RMI binding for the repository. A variation
-of the following code is usually all that is needed in addition to the
-standard RMI setup (starting rmiregistry, etc.):
-
-
- Repository repository = ...; // The local repository
- String name = ...; // The RMI URL for the repository
-
- RemoteAdapterFactory factory = new ServerAdapterFactory();
- RemoteRepository remote = factory.getRemoteRepository(repository);
- Naming.bind(name, remote); // Make the RMI binding using java.rmi.Naming
-
-
-
Extending the JCR-RMI server
-
-The Factory pattern used by this package makes it easy to extend
-the behaviour of the JCR-RMI server. Such changes in behaviour or policy
-can be implemented by modifying or replacing the default
-ServerAdapterFactory used in the example above.
-
-The following example code adds transparent logging of all session logins
-and logouts:
-
-
- Repository repository = ...; // The local repository
- String name = ...; // The RMI URL for the repository
-
- RemoteAdapterFactory factory = new ServerAdapterFactory() {
- public RemoteSession getRemoteSession(Session session)
- throws RemoteException {
- System.out.println("LOGIN: " + session.getUserId());
- return new ServerSession(session, this) {
- public void logout() {
- System.out.println("LOGOUT: " + session.getUserId());
- super.logout();
- }
- };
- }
- };
-
- RemoteRepository remote = factory.getRemoteRepository(repository);
- Naming.bind(name, remote); // Make the RMI binding using java.rmi.Naming
-
-
-
\ No newline at end of file
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/xml/ImportContentHandler.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/xml/ImportContentHandler.java
deleted file mode 100644
index ef620f94e91..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/xml/ImportContentHandler.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.xml;
-
-import java.io.ByteArrayOutputStream;
-
-import org.apache.xml.serialize.OutputFormat;
-import org.apache.xml.serialize.XMLSerializer;
-import org.xml.sax.Attributes;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.Locator;
-import org.xml.sax.SAXException;
-
-/**
- * Base class for a SAX content handler for importing XML data. This
- * class provides a general mechanism for converting a SAX event stream
- * to raw XML data and feeding the received byte array into an import
- * method. Subclasses can provide different import mechanisms simply by
- * implementing the abstract {@link #importXML(byte[]) importXML(byte[])}
- * method.
- *
- * @author Jukka Zitting
- */
-public abstract class ImportContentHandler implements ContentHandler {
-
- /** Internal buffer for the XML byte stream. */
- private ByteArrayOutputStream buffer;
-
- /** The internal XML serializer. */
- private ContentHandler handler;
-
- /**
- * Creates a SAX content handler for importing XML data.
- */
- public ImportContentHandler() {
- this.buffer = new ByteArrayOutputStream();
- this.handler = new XMLSerializer(buffer, new OutputFormat());
- }
-
- /**
- * Imports the given XML data. This method is called by the
- * {@link #endDocument() endDocument()} method after the received
- * XML stream has been serialized.
- *
- * Subclasses must implement this method to provide the actual
- * import mechanism.
- *
- * @param xml the XML data to import
- * @throws Exception on import errors
- */
- protected abstract void importXML(byte[] xml) throws Exception;
-
- /** {@inheritDoc} */
- public void setDocumentLocator(Locator locator) {
- handler.setDocumentLocator(locator);
- }
-
- /** {@inheritDoc} */
- public void startDocument() throws SAXException {
- handler.startDocument();
- }
-
- /** {@inheritDoc} */
- public void endDocument() throws SAXException {
- handler.endDocument();
- try {
- importXML(buffer.toByteArray());
- } catch (Exception ex) {
- throw new SAXException(ex);
- }
- }
-
- /** {@inheritDoc} */
- public void startPrefixMapping(String prefix, String uri)
- throws SAXException {
- handler.startPrefixMapping(prefix, uri);
- }
-
- /** {@inheritDoc} */
- public void endPrefixMapping(String prefix) throws SAXException {
- handler.endPrefixMapping(prefix);
- }
-
- /** {@inheritDoc} */
- public void startElement(String uri, String localName, String qName,
- Attributes atts) throws SAXException {
- handler.startElement(uri, localName, qName, atts);
- }
-
- /** {@inheritDoc} */
- public void endElement(String uri, String localName, String qName)
- throws SAXException {
- handler.endElement(uri, localName, qName);
- }
-
- /** {@inheritDoc} */
- public void characters(char[] ch, int start, int length)
- throws SAXException {
- handler.characters(ch, start, length);
- }
-
- /** {@inheritDoc} */
- public void ignorableWhitespace(char[] ch, int start, int length)
- throws SAXException {
- handler.ignorableWhitespace(ch, start, length);
- }
-
- /** {@inheritDoc} */
- public void processingInstruction(String target, String data)
- throws SAXException {
- handler.processingInstruction(target, data);
- }
-
- /** {@inheritDoc} */
- public void skippedEntity(String name) throws SAXException {
- handler.skippedEntity(name);
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/xml/SessionImportContentHandler.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/xml/SessionImportContentHandler.java
deleted file mode 100644
index 8f3c57307bb..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/xml/SessionImportContentHandler.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.xml;
-
-import java.io.ByteArrayInputStream;
-
-import javax.jcr.Session;
-
-
-/**
- * SAX content handler for importing XML data to a JCR {@link Session Session}.
- * This utility class can be used to implement the
- * {@link Session#getImportContentHandler(String) Session.getImportContentHandler(String)}
- * method in terms of the
- * {@link Session#importXML(String, java.io.InputStream) Session.importXML(String, InputStream)}
- * method.
- *
- * @author Jukka Zitting
- */
-public class SessionImportContentHandler extends ImportContentHandler {
-
- /** The repository session. */
- private Session session;
-
- /** The import content path. */
- private String path;
-
- /**
- * Creates a SAX content handler for importing XML data to the given
- * session and path.
- *
- * @param session repository session
- * @param path import content path
- */
- public SessionImportContentHandler(Session session, String path) {
- this.session = session;
- this.path = path;
- }
-
- /**
- * Imports the serialized XML stream using the standard
- * {@link Session#importXML(String, java.io.InputStream) Session.importXML(String, InputStream)}
- * method.
- *
- * {@inheritDoc}
- */
- protected void importXML(byte[] xml) throws Exception {
- session.importXML(path, new ByteArrayInputStream(xml));
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/xml/WorkspaceImportContentHandler.java b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/xml/WorkspaceImportContentHandler.java
deleted file mode 100644
index 9fcfd428c85..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/xml/WorkspaceImportContentHandler.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.rmi.xml;
-
-import java.io.ByteArrayInputStream;
-
-import javax.jcr.Workspace;
-
-
-/**
- * SAX content handler for importing XML data to a JCR {@link Workspace Workspace}.
- * This utility class can be used to implement the
- * {@link Workspace#getImportContentHandler(String, int) Workspace.getImportContentHandler(String, int)}
- * method in terms of the
- * {@link Workspace#importXML(String, java.io.InputStream, int) Workspace.importXML(String, InputStream, int)}
- * method.
- *
- * @author Jukka Zitting
- */
-public class WorkspaceImportContentHandler extends ImportContentHandler {
-
- /** The repository workspace. */
- private Workspace workspace;
-
- /** The import content path. */
- private String path;
-
- /** The UUID behaviour. */
- private int uuidBehaviour;
-
- /**
- * Creates a SAX content handler for importing XML data to the given
- * workspace and path using the given UUID behaviour.
- *
- * @param workspace repository workspace
- * @param path import content path
- * @param uuidBehaviour UUID behaviour
- */
- public WorkspaceImportContentHandler(Workspace workspace, String path, int uuidBehaviour) {
- this.workspace = workspace;
- this.path = path;
- this.uuidBehaviour = uuidBehaviour;
- }
-
- /**
- * Imports the serialized XML stream using the standard
- * {@link Workspace#importXML(String, java.io.InputStream, int) Workspace.importXML(String, InputStream, int)}
- * method.
- *
- * {@inheritDoc}
- */
- protected void importXML(byte[] xml) throws Exception {
- workspace.importXML(path, new ByteArrayInputStream(xml), uuidBehaviour);
- }
-
-}
diff --git a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/xml/package.html b/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/xml/package.html
deleted file mode 100644
index 956e5ecb042..00000000000
--- a/contrib/jcr-rmi/src/java/org/apache/jackrabbit/rmi/xml/package.html
+++ /dev/null
@@ -1,15 +0,0 @@
-
-Utility classes for importing SAX event streams.
-
-The classes in this package can be used for to implement the JCR
-{@link javax.jcr.Session#getImportContentHandler(java.lang.String) Session.getImportContentHandler(String)}
-and
-{@link javax.jcr.Workspace#getImportContentHandler(java.lang.String, int) Workspace.getImportContentHandler(String, int)}
-methods in terms of the corresponding importXML() methods.
-
-These utility classes were designed for the transparent JCR-RMI layer,
-but can easily be used as a part of any JCR repository implementation.
-The public interface of this package depends only on the standard JCR and
-J2SE APIs. The implementation uses Xerces as an extra dependency to
-serialize the SAX event streams.
-
diff --git a/contrib/jcr-rmi/src/test/org/apache/jackrabbit/test/rmi/RemoteAdapterTest.java b/contrib/jcr-rmi/src/test/org/apache/jackrabbit/test/rmi/RemoteAdapterTest.java
deleted file mode 100644
index e54279bcc45..00000000000
--- a/contrib/jcr-rmi/src/test/org/apache/jackrabbit/test/rmi/RemoteAdapterTest.java
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.test.rmi;
-
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-import javax.jcr.Item;
-import javax.jcr.NamespaceRegistry;
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.Repository;
-import javax.jcr.Session;
-import javax.jcr.Workspace;
-import javax.jcr.lock.Lock;
-import javax.jcr.nodetype.ItemDef;
-import javax.jcr.nodetype.NodeDef;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.nodetype.NodeTypeManager;
-import javax.jcr.nodetype.PropertyDef;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryManager;
-import javax.jcr.query.QueryResult;
-import javax.jcr.query.Row;
-import javax.jcr.version.Version;
-import javax.jcr.version.VersionHistory;
-
-import junit.framework.TestCase;
-
-import org.apache.jackrabbit.rmi.client.ClientAdapterFactory;
-import org.apache.jackrabbit.rmi.client.LocalAdapterFactory;
-import org.apache.jackrabbit.rmi.remote.RemoteItem;
-import org.apache.jackrabbit.rmi.remote.RemoteItemDef;
-import org.apache.jackrabbit.rmi.remote.RemoteLock;
-import org.apache.jackrabbit.rmi.remote.RemoteNamespaceRegistry;
-import org.apache.jackrabbit.rmi.remote.RemoteNode;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeDef;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeType;
-import org.apache.jackrabbit.rmi.remote.RemoteNodeTypeManager;
-import org.apache.jackrabbit.rmi.remote.RemoteProperty;
-import org.apache.jackrabbit.rmi.remote.RemotePropertyDef;
-import org.apache.jackrabbit.rmi.remote.RemoteQuery;
-import org.apache.jackrabbit.rmi.remote.RemoteQueryManager;
-import org.apache.jackrabbit.rmi.remote.RemoteQueryResult;
-import org.apache.jackrabbit.rmi.remote.RemoteRepository;
-import org.apache.jackrabbit.rmi.remote.RemoteRow;
-import org.apache.jackrabbit.rmi.remote.RemoteSession;
-import org.apache.jackrabbit.rmi.remote.RemoteVersion;
-import org.apache.jackrabbit.rmi.remote.RemoteVersionHistory;
-import org.apache.jackrabbit.rmi.remote.RemoteWorkspace;
-import org.apache.jackrabbit.rmi.server.RemoteAdapterFactory;
-import org.apache.jackrabbit.rmi.server.ServerAdapterFactory;
-import org.easymock.MockControl;
-
-/**
- * Tests for the adapter classes of JCR-RMI. These tests use reflection
- * to invoke all methods of an adapter object and to verify that the
- * corresponding methods of the underlying object get called by the adapter.
- */
-public class RemoteAdapterTest extends TestCase {
-
- /** Factory for creating remote test adapters. */
- private RemoteAdapterFactory remoteFactory;
-
- /** Factory for creating local test adapters. */
- private LocalAdapterFactory localFactory;
-
- /** Map of method names to method descriptions. */
- private Map methods;
-
- /** Mock controller. */
- private MockControl control;
-
- /** Mock object. */
- private Object mock;
-
- /**
- * Prepares the automated test suite to adapters of the given interface.
- *
- * @param iface adapter interface
- * @throws Exception on errors
- */
- private void prepareTests(Class iface) throws Exception {
- remoteFactory = new ServerAdapterFactory();
- localFactory = new ClientAdapterFactory();
-
- methods = new HashMap();
- Method[] m = iface.getDeclaredMethods();
- for (int i = 0; i < m.length; i++) {
- methods.put(m[i].getName(), m[i]);
- }
-
- control = MockControl.createControl(iface);
- mock = control.getMock();
- }
-
- /**
- * Removes the identified method from the automatic tests.
- *
- * @param name method name
- */
- private void ignoreMethod(String name) {
- methods.remove(name);
- }
-
- /**
- * Returns a parameter array for the given method.
- *
- * @param method method description
- * @return parameter array
- */
- private Object[] getParameters(Method method) {
- Class[] types = method.getParameterTypes();
- Object[] parameters = new Object[types.length];
- for (int i = 0; i < types.length; i++) {
- if (!types[i].isPrimitive()) {
- parameters[i] = null;
- } else if ("int".equals(types[i].getName())) {
- parameters[i] = new Integer(0);
- } else if ("boolean".equals(types[i].getName())) {
- parameters[i] = new Boolean(false);
- } else {
- System.out.println(types[i].getName());
- parameters[i] = null;
- }
- }
- return parameters;
- }
-
- /**
- * Sets the expected return value for the given method.
- *
- * @param method method description
- * @param control mock controller
- */
- private void setReturnValue(Method method, MockControl control) {
- Class type = method.getReturnType();
- if (!type.isPrimitive()) {
- control.setReturnValue(null);
- } else if ("void".equals(type.getName())) {
- control.setVoidCallable();
- } else if ("int".equals(type.getName())) {
- control.setReturnValue((int) 0);
- } else if ("long".equals(type.getName())) {
- control.setReturnValue((long) 0);
- } else if ("boolean".equals(type.getName())) {
- control.setReturnValue(false);
- } else {
- System.out.println(type.getName());
- control.setReturnValue(null);
- }
- }
-
- /**
- * Runs the automatic test suite on the given adapter instance.
- *
- * @param adapter adapter instance
- * @throws Exception on errors
- */
- private void runTests(Object adapter) throws Exception {
- Iterator iterator = methods.values().iterator();
- while (iterator.hasNext()) {
- Method method = (Method) iterator.next();
- Object[] parameters = getParameters(method);
-
- method.invoke(mock, parameters);
- setReturnValue(method, control);
- control.replay();
-
- method.invoke(adapter, parameters);
- control.verify();
-
- control.reset();
- }
- }
-
- /**
- * Tests Repository adapters.
- *
- * @throws Exception on errors
- */
- public void testRepository() throws Exception {
- prepareTests(Repository.class);
-
- Repository repository = (Repository) mock;
- RemoteRepository remote = remoteFactory.getRemoteRepository(repository);
- Repository local = localFactory.getRepository(remote);
-
- runTests(local);
- }
-
- /**
- * Tests Session adapters.
- *
- * @throws Exception on errors
- */
- public void testSession() throws Exception {
- prepareTests(Session.class);
- ignoreMethod("getRepository"); // implemented locally
- ignoreMethod("importXML"); // wrapped stream
- ignoreMethod("getImportContentHandler"); // implemented locally
- ignoreMethod("exportSysView"); // multiple methods
- ignoreMethod("exportDocView"); // multiple method
-
- Session session = (Session) mock;
- RemoteSession remote = remoteFactory.getRemoteSession(session);
- Session local = localFactory.getSession(null, remote);
-
- runTests(local);
- }
-
- /**
- * Tests Item adapters.
- *
- * @throws Exception on errors
- */
- public void testItem() throws Exception {
- prepareTests(Item.class);
- ignoreMethod("accept"); // implemented in subclasses
- ignoreMethod("getSession"); // implemented locally
- ignoreMethod("isNode"); // implemented in subclasses
- ignoreMethod("isSame"); // implemented locally
-
- Item item = (Item) mock;
- RemoteItem remote = remoteFactory.getRemoteItem(item);
- Item local = localFactory.getItem(null, remote);
-
- runTests(local);
- }
-
- /**
- * Tests Node adapters.
- *
- * @throws Exception on errors
- */
- public void testNode() throws Exception {
- prepareTests(Node.class);
- ignoreMethod("cancelMerge"); // TODO
- ignoreMethod("doneMerge"); // TODO
- ignoreMethod("checkin"); // TODO
- ignoreMethod("restore"); // multiple methods
- ignoreMethod("getVersionHistory"); // TODO
- ignoreMethod("getBaseVersion"); // TODO
- ignoreMethod("setProperty"); // multiple methods
-
- Node node = (Node) mock;
- RemoteNode remote = remoteFactory.getRemoteNode(node);
- Node local = localFactory.getNode(null, remote);
-
- runTests(local);
- }
-
- /**
- * Tests Property adapters.
- *
- * @throws Exception on errors
- */
- public void testProperty() throws Exception {
- prepareTests(Property.class);
- ignoreMethod("getBoolean"); // implemented locally
- ignoreMethod("getLong"); // implemented locally
- ignoreMethod("getDouble"); // implemented locally
- ignoreMethod("getDate"); // implemented locally
- ignoreMethod("getString"); // implemented locally
- ignoreMethod("getStream"); // implemented locally
- ignoreMethod("getNode"); // implemented locally
- ignoreMethod("setValue"); // multiple methods
-
- Property property = (Property) mock;
- RemoteProperty remote = remoteFactory.getRemoteProperty(property);
- Property local = localFactory.getProperty(null, remote);
-
- runTests(local);
- }
-
- /**
- * Tests Lock adapters.
- *
- * @throws Exception on errors
- */
- public void testLock() throws Exception {
- prepareTests(Lock.class);
- ignoreMethod("getNode"); // implemented locally
-
- Lock lock = (Lock) mock;
- RemoteLock remote = remoteFactory.getRemoteLock(lock);
- Lock local = localFactory.getLock(null, remote);
-
- runTests(local);
- }
-
- /**
- * Tests Workspace adapters.
- *
- * @throws Exception on errors
- */
- public void testWorkspace() throws Exception {
- prepareTests(Workspace.class);
- ignoreMethod("getObservationManager"); // TODO
- ignoreMethod("restore"); // TODO
- ignoreMethod("getSession"); // implemented locally
- ignoreMethod("copy"); // multiple methods
- ignoreMethod("importXML"); // wrapped stream
- ignoreMethod("getImportContentHandler"); // implemented locally
-
- Workspace workspace = (Workspace) mock;
- RemoteWorkspace remote = remoteFactory.getRemoteWorkspace(workspace);
- Workspace local = localFactory.getWorkspace(null, remote);
-
- runTests(local);
- }
-
- /**
- * Tests NamespaceRegistry adapters.
- *
- * @throws Exception on errors
- */
- public void testNamespaceRegistry() throws Exception {
- prepareTests(NamespaceRegistry.class);
-
- NamespaceRegistry registry = (NamespaceRegistry) mock;
- RemoteNamespaceRegistry remote =
- remoteFactory.getRemoteNamespaceRegistry(registry);
- NamespaceRegistry local = localFactory.getNamespaceRegistry(remote);
-
- runTests(local);
- }
-
- /**
- * Tests NodeTypeManager adapters.
- *
- * @throws Exception on errors
- */
- public void testNodeTypeManager() throws Exception {
- prepareTests(NodeTypeManager.class);
-
- NodeTypeManager manager = (NodeTypeManager) mock;
- RemoteNodeTypeManager remote =
- remoteFactory.getRemoteNodeTypeManager(manager);
- NodeTypeManager local = localFactory.getNodeTypeManager(remote);
-
- runTests(local);
- }
-
- /**
- * Tests NodeType adapters.
- *
- * @throws Exception on errors
- */
- public void testNodeType() throws Exception {
- prepareTests(NodeType.class);
- ignoreMethod("canSetProperty"); // wrapped Value object
-
- NodeType type = (NodeType) mock;
- RemoteNodeType remote = remoteFactory.getRemoteNodeType(type);
- NodeType local = localFactory.getNodeType(remote);
-
- runTests(local);
- }
-
- /**
- * Tests ItemDef adapters.
- *
- * @throws Exception on errors
- */
- public void testItemDef() throws Exception {
- prepareTests(ItemDef.class);
-
- ItemDef def = (ItemDef) mock;
- RemoteItemDef remote = remoteFactory.getRemoteItemDef(def);
- ItemDef local = localFactory.getItemDef(remote);
-
- runTests(local);
- }
-
- /**
- * Tests NodeDef adapters.
- *
- * @throws Exception on errors
- */
- public void testNodeDef() throws Exception {
- prepareTests(NodeDef.class);
-
- NodeDef def = (NodeDef) mock;
- RemoteNodeDef remote = remoteFactory.getRemoteNodeDef(def);
- NodeDef local = localFactory.getNodeDef(remote);
-
- runTests(local);
- }
-
- /**
- * Tests PropertyDef adapters.
- *
- * @throws Exception on errors
- */
- public void testPropertyDef() throws Exception {
- prepareTests(PropertyDef.class);
-
- PropertyDef def = (PropertyDef) mock;
- RemotePropertyDef remote = remoteFactory.getRemotePropertyDef(def);
- PropertyDef local = localFactory.getPropertyDef(remote);
-
- runTests(local);
- }
-
- /**
- * Tests QueryManager adapters.
- *
- * @throws Exception on errors
- */
- public void testQueryManager() throws Exception {
- prepareTests(QueryManager.class);
- ignoreMethod("getQuery"); // TODO
-
- QueryManager manager = (QueryManager) mock;
- RemoteQueryManager remote = remoteFactory.getRemoteQueryManager(manager);
- QueryManager local = localFactory.getQueryManager(null, remote);
-
- runTests(local);
- }
-
- /**
- * Tests Query adapters.
- *
- * @throws Exception on errors
- */
- public void testQuery() throws Exception {
- prepareTests(Query.class);
-
- Query query = (Query) mock;
- RemoteQuery remote = remoteFactory.getRemoteQuery(query);
- Query local = localFactory.getQuery(null, remote);
-
- runTests(local);
- }
-
- /**
- * Tests QueryResult adapters.
- *
- * @throws Exception on errors
- */
- public void testQueryResult() throws Exception {
- prepareTests(QueryResult.class);
-
- QueryResult result = (QueryResult) mock;
- RemoteQueryResult remote = remoteFactory.getRemoteQueryResult(result);
- QueryResult local = localFactory.getQueryResult(null, remote);
-
- runTests(local);
- }
-
- /**
- * Tests Row adapters.
- *
- * @throws Exception on errors
- */
- public void testRow() throws Exception {
- prepareTests(Row.class);
-
- Row row = (Row) mock;
- RemoteRow remote = remoteFactory.getRemoteRow(row);
- Row local = localFactory.getRow(remote);
-
- runTests(local);
- }
-
- /**
- * Tests Version adapters.
- *
- * @throws Exception on errors
- */
- public void testVersion() throws Exception {
- prepareTests(Version.class);
-
- Version version = (Version) mock;
- RemoteVersion remote = remoteFactory.getRemoteVersion(version);
- Version local = localFactory.getVersion(null, remote);
-
- runTests(local);
- }
-
- /**
- * Tests VersionHistory adapters.
- *
- * @throws Exception on errors
- */
- public void testVersionHistory() throws Exception {
- prepareTests(VersionHistory.class);
-
- VersionHistory history = (VersionHistory) mock;
- RemoteVersionHistory remote =
- remoteFactory.getRemoteVersionHistory(history);
- VersionHistory local = localFactory.getVersionHistory(null, remote);
-
- runTests(local);
- }
-
-}
diff --git a/contrib/jcr-rmi/src/test/org/apache/jackrabbit/test/rmi/TestAll.java b/contrib/jcr-rmi/src/test/org/apache/jackrabbit/test/rmi/TestAll.java
deleted file mode 100644
index 90c12a25dc3..00000000000
--- a/contrib/jcr-rmi/src/test/org/apache/jackrabbit/test/rmi/TestAll.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.test.rmi;
-
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-/**
- * Test suite that contains all JCR-RMI test cases.
- */
-public class TestAll {
-
- /** This class cannot be instantiated. */
- private TestAll() {
- }
-
- /**
- * Returns the JCR-RMI test suite.
- *
- * @return JCR-RMI test suite
- */
- public static Test suite() {
- TestSuite suite = new TestSuite("Tests for org.apache.jackrabbit.rmi");
- //$JUnit-BEGIN$
- suite.addTestSuite(RemoteAdapterTest.class);
- //$JUnit-END$
- return suite;
- }
-
-}
diff --git a/contrib/jcr-rmi/src/test/org/apache/jackrabbit/test/rmi/package.html b/contrib/jcr-rmi/src/test/org/apache/jackrabbit/test/rmi/package.html
deleted file mode 100644
index 92594a1014d..00000000000
--- a/contrib/jcr-rmi/src/test/org/apache/jackrabbit/test/rmi/package.html
+++ /dev/null
@@ -1,6 +0,0 @@
-
-Test cases for the JCR-RMI wrapper. The test cases use the EasyMock library
-to generate mock objects that are then wrapped into the remote client-server
-wrappers. The test cases then access the client wrappers and verify that the
-corresponding operations are performed also on the underlying mock objects.
-
diff --git a/contrib/jcr-server/LICENSE.txt b/contrib/jcr-server/LICENSE.txt
deleted file mode 100644
index d6456956733..00000000000
--- a/contrib/jcr-server/LICENSE.txt
+++ /dev/null
@@ -1,202 +0,0 @@
-
- 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/contrib/jcr-server/client/maven.xml b/contrib/jcr-server/client/maven.xml
deleted file mode 100644
index ef564ff1229..00000000000
--- a/contrib/jcr-server/client/maven.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/contrib/jcr-server/client/project.properties b/contrib/jcr-server/client/project.properties
deleted file mode 100644
index 0569e85c372..00000000000
--- a/contrib/jcr-server/client/project.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-maven.javadoc.links=http://java.sun.com/j2se/1.4.2/docs/api/,http://www.day.com/maven/jsr170/javadocs/jcr-0.16.1-pfd/
-maven.repo.remote = http://www.ibiblio.org/maven/,http://www.day.com/maven/
diff --git a/contrib/jcr-server/client/project.xml b/contrib/jcr-server/client/project.xml
deleted file mode 100644
index 856ed641a5e..00000000000
--- a/contrib/jcr-server/client/project.xml
+++ /dev/null
@@ -1,125 +0,0 @@
-
-
-
-
-
-
- ${basedir}/../project.xml
- jcr-client
- jcr-server
- jar
- JCRWebdavServer Client Library
-
-
-
-
-
-
- jcr-webdav
- jcr-server
- ${pom.currentVersion}
-
-
-
- jsr170
- jcr
- 0.16.2
- http://www.day.com/maven/jsr170/jars/jcr-0.16.2.jar
-
-
- jackrabbit
- 0.16.2-dev
-
-
- jdom
- 1.0
-
-
- log4j
- 1.2.8
-
-
- servletapi
- 2.3
-
-
- jcr-rmi
- 0.16.2
-
-
-
-
-
-
-
-
-
- ${basedir}/src/java
-
-
- src/java
-
- **/*.xml
- **/*.xsd
- **/*.properties
- **/*.dtd
-
-
-
-
-
-
diff --git a/contrib/jcr-server/client/src/java/org/apache/jackrabbit/client/RepositoryAccessServlet.java b/contrib/jcr-server/client/src/java/org/apache/jackrabbit/client/RepositoryAccessServlet.java
deleted file mode 100644
index e450f91358e..00000000000
--- a/contrib/jcr-server/client/src/java/org/apache/jackrabbit/client/RepositoryAccessServlet.java
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.client;
-
-import org.apache.log4j.Logger;
-import org.apache.log4j.PropertyConfigurator;
-import org.apache.jackrabbit.rmi.client.ClientRepositoryFactory;
-import org.apache.jackrabbit.core.util.Base64;
-
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.ServletException;
-import javax.jcr.*;
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
-
-import java.util.Properties;
-import java.util.Enumeration;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.ByteArrayOutputStream;
-import java.rmi.RemoteException;
-import java.rmi.NotBoundException;
-import java.net.MalformedURLException;
-
-/**
- * This Class implements a servlet that is used as unified mechanism to retrieve
- * a jcr repository either through JNID, RMI or JCRWebdavServer.
- */
-public class RepositoryAccessServlet extends HttpServlet {
-
- /** default logger */
- private static Logger log;
-
- // todo: implement correctly
- public final static String INIT_PARAM_LOG4J_CONFIG = "log4j-config";
-
- /** the 'repository-name' init parameter */
- public final static String INIT_PARAM_REPOSITORY_NAME = "repository-name";
-
- /** the 'rmi-uri' init parameter */
- public final static String INIT_PARAM_RMI_URI = "rmi-uri";
-
- /** Authorization header name */
- private static final String HEADER_AUTHORIZATION = "Authorization";
-
- /** the configured repository name */
- private static String repositoryName;
-
- private static String rmiURI;
-
- private static InitialContext jndiContext;
-
- private static Repository repository;
-
- /**
- * Initializes this servlet
- *
- * @throws javax.servlet.ServletException
- */
- public void init() throws ServletException {
- initLog4J();
- log.info("RepositoryAccessServlet initializing...");
- initJNDI();
- initRMI();
- initRepository();
- log.info("RepositoryAccessServlet initialized.");
- }
-
- private void initLog4J() throws ServletException {
- // setup log4j
- String log4jConfig = getServletConfig().getInitParameter(INIT_PARAM_LOG4J_CONFIG);
- InputStream in =getServletContext().getResourceAsStream(log4jConfig);
- if (in==null) {
- // try normal init
- PropertyConfigurator.configure(log4jConfig);
- } else {
- try {
- Properties log4jProperties = new Properties();
- log4jProperties.load(in);
- in.close();
- PropertyConfigurator.configure(log4jProperties);
- } catch (IOException e) {
- throw new ServletException("Unable to load log4jProperties: " + e.toString());
- }
- }
- log = Logger.getLogger(RepositoryAccessServlet.class);
- }
-
- private void initJNDI() throws ServletException {
- // setup repository name
- repositoryName = getServletConfig().getInitParameter(INIT_PARAM_REPOSITORY_NAME);
- if (repositoryName==null) {
- repositoryName="default";
- }
- log.info(" repository-name = " + repositoryName);
-
- // retrieve JNDI Context environment
- try {
- Properties env = new Properties();
- Enumeration names = getServletConfig().getInitParameterNames();
- while (names.hasMoreElements()) {
- String name = (String) names.nextElement();
- if (name.startsWith("java.naming.")) {
- env.put(name, getServletConfig().getInitParameter(name));
- log.info(" adding property to JNDI environment: " + name + "=" + env.getProperty(name));
- }
- }
- jndiContext = new InitialContext(env);
- } catch (NamingException e) {
- log.error("Create initial context: " + e.toString());
- throw new ServletException(e);
- }
- }
-
- private void initRMI() {
- // setup repository name
- rmiURI = getServletConfig().getInitParameter(INIT_PARAM_RMI_URI);
- if (rmiURI != null) {
- log.info(" rmi-uri = " + rmiURI);
- }
- }
-
- /**
- * tries to retrieve the repository
- */
- private void initRepository() throws ServletException {
- getRepositoryByRMI();
- if (repository == null) {
- getRepositoryByJNDI();
- }
- if (repository == null) {
- log.error("Unable to retrieve repository");
- throw new ServletException("Unable to retrieve repository");
- }
- log.info(repository.getDescriptor(Repository.REP_NAME_DESC) + " " + repository.getDescriptor(Repository.REP_VERSION_DESC));
- }
-
- /**
- * tries to retrieve the repository using RMI
- */
- private void getRepositoryByJNDI() {
- if (jndiContext != null) {
- // acquire via JNDI
- try {
- repository = (Repository) jndiContext.lookup(repositoryName);
- } catch (NamingException e) {
- log.error("Error while retrieving repository using JNDI: " + e);
- return;
- }
- log.info("Acquired repository via JNDI.");
- }
- }
-
- /**
- * tries to retrieve the repository using RMI
- */
- private void getRepositoryByRMI() {
- if (rmiURI != null) {
- // acquire via RMI
- ClientFactoryDelegater cfd = null;
- try {
- Class clazz = Class.forName("org.apache.jackrabbit.client.RMIClientFactoryDelegater");
- cfd = (ClientFactoryDelegater) clazz.newInstance();
- } catch (NoClassDefFoundError e) {
- log.error("Unable to locate RMI ClientRepositoryFactory. jcr-rmi.jar missing? " + e.toString());
- return;
- } catch (Exception e) {
- log.error("Unable to locate RMI ClientRepositoryFactory. jcr-rmi.jar missing?" + e.toString());
- return;
- }
-
- try {
- repository = cfd.getRepository(rmiURI);
- } catch (Exception e) {
- log.error("Error while retrieving repository using RMI: " + e);
- return;
- }
- log.info("Acquired repository via RMI.");
- }
- }
-
- /**
- * Returns the JSR170 repository
- *
- * @return a jsr170 repository
- */
- public static Repository getRepository() {
- return repository;
- }
-
- /**
- * Build a {@link Credentials} object for the given authorization header.
- * The creds may be used to login to the repository. If the specified header
- * string is null or not of the required format, null
- * is returned.
- *
- * @param authHeader Authorization header as present in the Http request
- * @return credentials or null.
- * @throws ServletException If an IOException occured while decoding the
- * Authorization header.
- * @see #getRepository()
- * @see #login(HttpServletRequest)
- */
- public static Credentials getCredentialsFromHeader(String authHeader)
- throws ServletException {
- try {
- if (authHeader != null) {
- String[] authStr = authHeader.split(" ");
- if (authStr.length >= 2 && authStr[0].equalsIgnoreCase(HttpServletRequest.BASIC_AUTH)) {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- Base64.decode(authStr[1].toCharArray(), out);
- String decAuthStr = out.toString("ISO-8859-1");
- int pos = decAuthStr.indexOf(':');
- String userid = decAuthStr.substring(0, pos);
- String passwd = decAuthStr.substring(pos + 1);
- return new SimpleCredentials(userid, passwd.toCharArray());
- }
- }
- return null;
- } catch (IOException e) {
- throw new ServletException("Unable to decode authorization: " + e.toString());
- }
- }
-
- /**
- * Simple login to the {@link Repository} accessed by this servlet using the
- * Authorization header present in the given request.
- * Please note, that no workspace information is provided to the repository
- * login ({@link Repository#login(javax.jcr.Credentials)}), thus the default
- * workspace will be selected. In order to provide a specific workspace name,
- * manual {@link Repository#login(Credentials, String) login} is required (see
- * also {@link #getRepository()}).
- *
- * @param request
- * @return Session object obtained upon {@link Repository#login(javax.jcr.Credentials)}.
- * @throws ServletException
- * @see #getRepository() in order to be able to login to a specific workspace.
- * @see #getCredentialsFromHeader(String) for a utility method to retrieve
- * credentials from the Authorization header string.
- */
- public static Session login(HttpServletRequest request) throws ServletException {
- String authHeader = request.getHeader(HEADER_AUTHORIZATION);
- try {
- return repository.login(getCredentialsFromHeader(authHeader));
- } catch (RepositoryException e) {
- throw new ServletException("Failed to login to the repository: " + e.toString());
- }
- }
-}
-
-/**
- * optional class for RMI, will only be used, if RMI client is present
- */
-abstract class ClientFactoryDelegater {
-
- public abstract Repository getRepository(String uri)
- throws RemoteException, MalformedURLException, NotBoundException;
-}
-
-/**
- * optional class for RMI, will only be used, if RMI server is present
- */
-class RMIClientFactoryDelegater extends ClientFactoryDelegater {
-
- // only used to enforce linking upon Class.forName()
- static String FactoryClassName = ClientRepositoryFactory.class.getName();
-
- public Repository getRepository(String uri)
- throws MalformedURLException, NotBoundException, RemoteException {
- System.setProperty("java.rmi.server.useCodebaseOnly", "true");
- return new ClientRepositoryFactory().getRepository(uri);
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/maven.xml b/contrib/jcr-server/maven.xml
deleted file mode 100644
index 11f77929899..00000000000
--- a/contrib/jcr-server/maven.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/contrib/jcr-server/project.properties b/contrib/jcr-server/project.properties
deleted file mode 100644
index 0569e85c372..00000000000
--- a/contrib/jcr-server/project.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-maven.javadoc.links=http://java.sun.com/j2se/1.4.2/docs/api/,http://www.day.com/maven/jsr170/javadocs/jcr-0.16.1-pfd/
-maven.repo.remote = http://www.ibiblio.org/maven/,http://www.day.com/maven/
diff --git a/contrib/jcr-server/project.xml b/contrib/jcr-server/project.xml
deleted file mode 100644
index 0b041dc4f0f..00000000000
--- a/contrib/jcr-server/project.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
- 3
- jcr-server
-
- Jackrabbit-Server
- 0.16.2
- 2005
- org.apache.jackrabbit.server.*
-
- WebDav based JCR client/server connection facility.
-
- JCRWebdav Server
-
-
-
- The Apache Software License, Version 2.0
- /LICENSE.txt
- repo
-
-
-
diff --git a/contrib/jcr-server/server/maven.xml b/contrib/jcr-server/server/maven.xml
deleted file mode 100644
index ef564ff1229..00000000000
--- a/contrib/jcr-server/server/maven.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/contrib/jcr-server/server/project.properties b/contrib/jcr-server/server/project.properties
deleted file mode 100644
index 0569e85c372..00000000000
--- a/contrib/jcr-server/server/project.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-maven.javadoc.links=http://java.sun.com/j2se/1.4.2/docs/api/,http://www.day.com/maven/jsr170/javadocs/jcr-0.16.1-pfd/
-maven.repo.remote = http://www.ibiblio.org/maven/,http://www.day.com/maven/
diff --git a/contrib/jcr-server/server/project.xml b/contrib/jcr-server/server/project.xml
deleted file mode 100644
index 5dcbcd227d3..00000000000
--- a/contrib/jcr-server/server/project.xml
+++ /dev/null
@@ -1,133 +0,0 @@
-
-
-
-
-
-
- ${basedir}/../project.xml
- jcr-server
- jcr-server
- jar
- JCRWebdavServer Server Library
-
-
-
-
-
-
- jcr-webdav
- jcr-server
- ${pom.currentVersion}
-
-
- jcr-client
- jcr-server
- ${pom.currentVersion}
-
- true
-
-
-
-
- jsr170
- jcr
- 0.16.2
- http://www.day.com/maven/jsr170/jars/jcr-0.16.2.jar
-
-
- jackrabbit
- 0.16.2-dev
-
-
- jdom
- 1.0
-
-
- log4j
- 1.2.8
-
-
- servletapi
- 2.3
-
-
- jcr-rmi
- 0.16.2
-
-
-
-
-
-
-
-
-
- ${basedir}/src/java
-
-
- src/java
-
- **/*.xml
- **/*.xsd
- **/*.properties
- **/*.dtd
-
-
-
-
-
-
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/AbstractWebdavServlet.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/AbstractWebdavServlet.java
deleted file mode 100644
index 57722ec78b6..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/AbstractWebdavServlet.java
+++ /dev/null
@@ -1,823 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.server;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.observation.ObservationResource;
-import org.apache.jackrabbit.webdav.observation.SubscriptionInfo;
-import org.apache.jackrabbit.webdav.observation.Subscription;
-import org.apache.jackrabbit.webdav.observation.EventDiscovery;
-import org.apache.jackrabbit.webdav.ordering.OrderingResource;
-import org.apache.jackrabbit.webdav.ordering.OrderPatch;
-import org.apache.jackrabbit.webdav.transaction.TransactionInfo;
-import org.apache.jackrabbit.webdav.transaction.TransactionResource;
-import org.apache.jackrabbit.webdav.lock.LockInfo;
-import org.apache.jackrabbit.webdav.lock.ActiveLock;
-import org.apache.jackrabbit.webdav.version.*;
-import org.apache.jackrabbit.webdav.version.report.ReportInfo;
-import org.apache.jackrabbit.webdav.version.report.Report;
-import org.apache.jackrabbit.webdav.property.*;
-import org.apache.jackrabbit.webdav.search.SearchResource;
-import org.apache.jackrabbit.webdav.search.SearchConstants;
-import org.apache.jackrabbit.webdav.search.SearchRequest;
-
-import org.jdom.Document;
-
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Iterator;
-
-/**
- * AbstractWebdavServlet
- *
- * todo respect Position header
- */
-abstract public class AbstractWebdavServlet extends HttpServlet implements DavConstants {
-
- /** default logger */
- private static Logger log = Logger.getLogger(AbstractWebdavServlet.class);
-
- /**
- * Create a new DavResource
- *
- * @param locator
- * @param request
- * @param response
- * @return resource for the given locator
- * @throws DavException
- */
- abstract protected DavResource createResource(DavResourceLocator locator,
- WebdavRequest request,
- WebdavResponse response) throws DavException;
-
- /**
- * The OPTION method
- *
- * @param request
- * @param response
- * @param resource
- */
- protected void doOptions(WebdavRequest request, WebdavResponse response,
- DavResource resource) throws IOException {
- response.addHeader(DavConstants.HEADER_DAV, resource.getComplianceClass());
- response.addHeader("Allow", resource.getSupportedMethods());
- response.addHeader("MS-Author-Via", DavConstants.HEADER_DAV);
- if (resource instanceof SearchResource) {
- String[] langs = ((SearchResource)resource).getQueryGrammerSet().getQueryLanguages();
- for (int i = 0; i < langs.length; i++) {
- response.addHeader(SearchConstants.HEADER_DASL, "<" + langs[i] + ">");
- }
- }
- // with DeltaV the OPTIONS request may contain a Xml body.
- OptionsResponse oR = null;
- OptionsInfo oInfo = request.getOptionsInfo();
- if (oInfo != null && resource instanceof DeltaVResource) {
- oR = ((DeltaVResource)resource).getOptionResponse(oInfo);
- }
- if (oR == null) {
- response.setStatus(DavServletResponse.SC_OK);
- } else {
- response.sendXmlResponse(oR.toXml(), DavServletResponse.SC_OK);
- }
- }
-
- /**
- * The HEAD method
- *
- * @param request
- * @param response
- * @param resource
- * @throws java.io.IOException
- */
- protected void doHead(WebdavRequest request, WebdavResponse response,
- DavResource resource) throws IOException {
- spoolResource(request, response, resource, false);
- }
-
- /**
- * The GET method
- *
- * @param request
- * @param response
- * @param resource
- * @throws IOException
- */
- protected void doGet(WebdavRequest request, WebdavResponse response,
- DavResource resource) throws IOException {
- spoolResource(request, response, resource, true);
- }
-
- /**
- * @param request
- * @param response
- * @param resource
- * @param sendContent
- * @throws IOException
- */
- private void spoolResource(WebdavRequest request, WebdavResponse response,
- DavResource resource, boolean sendContent)
- throws IOException {
-
- if (!resource.exists()) {
- response.sendError(HttpServletResponse.SC_NOT_FOUND);
- return;
- }
-
- long modTime = resource.getModificationTime();
- if (modTime != DavResource.UNDEFINED_MODIFICATIONTIME && modTime <= request.getDateHeader("If-Modified-Since")) {
- // resource has not been modified since the time indicated in the
- // 'If-Modified-Since' header.
- response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
- return;
- }
-
- DavProperty lastMod = resource.getProperty(DavPropertyName.GETLASTMODIFIED);
- if (lastMod != null) {
- response.setHeader("Last-Modified", String.valueOf(lastMod.getValue()));
- }
-
- DavProperty etag = resource.getProperty(DavPropertyName.GETETAG);
- if (etag != null) {
- response.setHeader("ETag", String.valueOf(etag.getValue()));
- }
-
- DavProperty contentType = resource.getProperty(DavPropertyName.GETCONTENTTYPE);
- if (contentType != null) {
- response.setHeader("Content-Type", String.valueOf(contentType.getValue()));
- }
-
- DavProperty contentLength = resource.getProperty(DavPropertyName.GETCONTENTLENGTH);
- if (contentLength != null) {
- try {
- int length = Integer.parseInt(contentLength.getValue()+"");
- if (length > 0) {
- response.setIntHeader("Content-Length", length);
- }
- } catch (NumberFormatException e) {
- log.error("Could not build content length from property value '" + contentLength.getValue() + "'");
- }
- }
-
- // spool content in case of 'GET' request
- if (sendContent) {
- InputStream in = resource.getStream();
- if (in != null) {
- OutputStream out = response.getOutputStream();
- byte[] buffer = new byte[8192];
- int read;
- while ((read = in.read(buffer)) >= 0 ) {
- out.write(buffer, 0, read);
- }
- in.close();
- }
- }
- response.flushBuffer();
- }
-
- /**
- * The PROPFIND method
- *
- * @param request
- * @param response
- * @param resource
- * @throws IOException
- */
- protected void doPropFind(WebdavRequest request, WebdavResponse response,
- DavResource resource) throws IOException {
-
- if (!resource.exists()) {
- response.sendError(DavServletResponse.SC_NOT_FOUND);
- return;
- }
-
- int depth = request.getDepth(DEPTH_INFINITY);
- DavPropertyNameSet requestProperties = request.getPropFindProperties();
- int propfindType = request.getPropFindType();
-
- MultiStatus mstatus = new MultiStatus();
- mstatus.addResourceProperties(resource, requestProperties, propfindType, depth);
- response.sendMultiStatusResponse(mstatus);
- }
-
- /**
- * The PROPPATCH method
- *
- * @param request
- * @param response
- * @param resource
- * @throws IOException
- */
- protected void doPropPatch(WebdavRequest request, WebdavResponse response,
- DavResource resource)
- throws IOException, DavException {
-
- DavPropertySet setProperties = request.getPropPatchSetProperties();
- DavPropertyNameSet removeProperties = request.getPropPatchRemoveProperties();
- if (setProperties.isEmpty() && removeProperties.isEmpty()) {
- response.sendError(DavServletResponse.SC_BAD_REQUEST);
- return;
- }
-
- // first resolve merge conflicts
- // TODO: not correct resolution of merge conflicts are immediately perstisted
- // TODO: rfc 2518 requires, that no changes must only be persisted if the complete proppatch-req succeeds
- if (resource instanceof VersionControlledResource) {
- ((VersionControlledResource)resource).resolveMergeConflict(setProperties, removeProperties);
- }
-
- // complete any other property setting or removing
- DavPropertyIterator setIter = setProperties.iterator();
- while (setIter.hasNext()) {
- DavProperty prop = setIter.nextProperty();
- resource.setProperty(prop);
- }
- Iterator remNameIter = removeProperties.iterator();
- while (remNameIter.hasNext()) {
- DavPropertyName propName = (DavPropertyName) remNameIter.next();
- resource.removeProperty(propName);
- }
- response.setStatus(DavServletResponse.SC_OK);
-
- // todo return multistatus response in case of failure
- }
-
- /**
- * The PUT method
- *
- * @param request
- * @param response
- * @param resource
- * @throws IOException
- * @throws DavException
- */
- protected void doPut(WebdavRequest request, WebdavResponse response,
- DavResource resource) throws IOException, DavException {
-
- DavResource parentResource = resource.getCollection();
- if (parentResource == null || !parentResource.exists()) {
- // parent does not exist
- response.sendError(DavServletResponse.SC_CONFLICT);
- return;
- }
-
- int status;
- // test if resource already exists
- if (resource.exists()){
- status = DavServletResponse.SC_NO_CONTENT;
- } else {
- status = DavServletResponse.SC_CREATED;
- }
-
- parentResource.addMember(resource, request.getInputStream());
- response.setStatus(status);
- }
-
- /**
- * The MKCOL method
- *
- * @param request
- * @param response
- * @param resource
- * @throws IOException
- * @throws DavException
- */
- protected void doMkCol(WebdavRequest request, WebdavResponse response,
- DavResource resource) throws IOException, DavException {
-
- DavResource parentResource = resource.getCollection();
- if (parentResource == null || !parentResource.exists() || !parentResource.isCollection()) {
- // parent does not exist or is not a collection
- response.sendError(DavServletResponse.SC_CONFLICT);
- return;
- }
-
- if (request.getContentLength() > 0 || request.getHeader("Transfer-Encoding") != null) {
- parentResource.addMember(resource, request.getInputStream());
- } else {
- parentResource.addMember(resource);
- }
- response.setStatus(DavServletResponse.SC_CREATED);
- }
-
- /**
- * The DELETE method
- *
- * @param request
- * @param response
- * @param resource
- * @throws IOException
- * @throws DavException
- */
- protected void doDelete(WebdavRequest request, WebdavResponse response,
- DavResource resource) throws IOException, DavException {
- DavResource parent = resource.getCollection();
- if (parent != null) {
- parent.removeMember(resource);
- response.setStatus(DavServletResponse.SC_NO_CONTENT);
- } else {
- response.sendError(DavServletResponse.SC_FORBIDDEN, "Cannot remove the root resource.");
- }
- }
-
- /**
- * The COPY method
- *
- * @param request
- * @param response
- * @param resource
- * @throws IOException
- * @throws DavException
- */
- protected void doCopy(WebdavRequest request, WebdavResponse response,
- DavResource resource) throws IOException, DavException {
-
- // only depth 0 and infinity is allowed
- int depth = request.getDepth(DEPTH_INFINITY);
- if (!(depth == DEPTH_0 || depth == DEPTH_INFINITY)) {
- response.sendError(DavServletResponse.SC_BAD_REQUEST);
- return;
- }
-
- DavResource destResource = createResource(request.getDestinationLocator(), request, response);
- int status = validateDestination(destResource, request);
- if (status > DavServletResponse.SC_NO_CONTENT) {
- response.sendError(status);
- return;
- }
-
- resource.copy(destResource, depth == DEPTH_0);
- response.setStatus(status);
- }
-
- /**
- * The MOVE method
- *
- * @param request
- * @param response
- * @param resource
- * @throws IOException
- * @throws DavException
- */
- protected void doMove(WebdavRequest request, WebdavResponse response,
- DavResource resource) throws IOException, DavException {
-
- DavResource destResource = createResource(request.getDestinationLocator(), request, response);
- int status = validateDestination(destResource, request);
- if (status > DavServletResponse.SC_NO_CONTENT) {
- response.sendError(status);
- return;
- }
-
- resource.move(destResource);
- response.setStatus(status);
- }
-
- /**
- * Validate the given destination resource and return the proper status
- * code: Any return value greater/equal than {@link DavServletResponse#SC_NO_CONTENT}
- * indicates an error.
- *
- * @param destResource destination resource to be validated.
- * @param request
- * @return status code indicating whether the destination is valid.
- */
- private int validateDestination(DavResource destResource, WebdavRequest request) {
-
- String destHeader = request.getHeader(HEADER_DESTINATION);
- if (destHeader == null || "".equals(destHeader)){
- return DavServletResponse.SC_BAD_REQUEST;
- }
- if (destResource.getLocator().equals(request.getRequestLocator())) {
- return DavServletResponse.SC_FORBIDDEN;
- }
-
- int status;
- if (destResource.exists()) {
- if (request.isOverwrite()) {
- // matching if-header required for existing resources
- if (!request.matchesIfHeader(destResource)) {
- return DavServletResponse.SC_PRECONDITION_FAILED;
- } else {
- // overwrite existing resource: its up to the webdavresource
- // object to deal with any delete prior to the copy/move
- status = DavServletResponse.SC_NO_CONTENT;
- }
- } else {
- // cannot copy/move to an existing item, if overwrite is not forced
- return DavServletResponse.SC_PRECONDITION_FAILED;
- }
- } else {
- // destination does not exist >> copy/move can be performed
- status = DavServletResponse.SC_CREATED;
- }
- return status;
- }
-
- /**
- * The LOCK method
- *
- * @param request
- * @param response
- * @param resource
- * @throws IOException
- * @throws DavException
- */
- protected void doLock(WebdavRequest request, WebdavResponse response,
- DavResource resource) throws IOException, DavException {
-
- LockInfo lockInfo = request.getLockInfo();
- if (lockInfo.isRefreshLock()) {
- // refresh any matching existing locks
- ActiveLock[] activeLocks = resource.getLocks();
- List lList = new ArrayList();
- for (int i = 0; i < activeLocks.length; i++) {
- if (request.matchesIfHeader(resource.getHref(), activeLocks[i].getToken(), "")) {
- lList.add(resource.refreshLock(lockInfo, activeLocks[i].getToken()));
- }
- }
- if (lList.isEmpty()) {
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED);
- }
- ActiveLock[] refreshedLocks = (ActiveLock[]) lList.toArray(new ActiveLock[lList.size()]);
- response.sendRefreshLockResponse(refreshedLocks);
- } else {
- // create a new lock
- ActiveLock lock = resource.lock(lockInfo);
- response.sendLockResponse(lock);
- }
-
- // TODO multistatus in case of failure...
- // NOTE: spec says 409 status, but example says 207 (multistatus)
- }
-
- /**
- * The UNLOCK method
- *
- * @param request
- * @param response
- * @param resource
- * @throws DavException
- */
- protected void doUnlock(WebdavRequest request, WebdavResponse response,
- DavResource resource) throws DavException {
- // get lock token from header
- String lockToken = request.getLockToken();
- TransactionInfo tInfo = request.getTransactionInfo();
- if (tInfo != null) {
- ((TransactionResource)resource).unlock(lockToken, tInfo);
- } else {
- resource.unlock(lockToken);
- }
- response.setStatus(DavServletResponse.SC_NO_CONTENT);
- }
-
- /**
- * The ORDERPATCH method
- *
- * @param request
- * @param response
- * @param resource
- * @throws java.io.IOException
- * @throws DavException
- */
- protected void doOrderPatch(WebdavRequest request,
- WebdavResponse response,
- DavResource resource)
- throws IOException, DavException {
-
- if (!(resource instanceof OrderingResource)) {
- response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- return;
- }
-
- OrderPatch op = request.getOrderPatch();
- if (op == null) {
- response.sendError(DavServletResponse.SC_BAD_REQUEST);
- return;
- }
- // perform reordering of internal members
- ((OrderingResource)resource).orderMembers(op);
- response.setStatus(DavServletResponse.SC_OK);
-
- //TODO: in case of failure Multistatus is required...
- }
-
- /**
- * The SUBSCRIBE method
- *
- * @param request
- * @param response
- * @param resource
- * @throws IOException
- * @throws DavException
- */
- protected void doSubscribe(WebdavRequest request,
- WebdavResponse response,
- DavResource resource)
- throws IOException, DavException {
-
- if (!(resource instanceof ObservationResource)) {
- response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- return;
- }
-
- SubscriptionInfo info = request.getSubscriptionInfo();
- if (info == null) {
- response.sendError(DavServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
- return;
- }
- Subscription subs = ((ObservationResource)resource).subscribe(info, request.getSubscriptionId());
- response.sendSubscriptionResponse(subs);
- }
-
- /**
- * The UNSUBSCRIBE method
- *
- * @param request
- * @param response
- * @param resource
- * @throws IOException
- * @throws DavException
- */
- protected void doUnsubscribe(WebdavRequest request,
- WebdavResponse response,
- DavResource resource)
- throws IOException, DavException {
-
- if (!(resource instanceof ObservationResource)) {
- response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- return;
- }
- ((ObservationResource)resource).unsubscribe(request.getSubscriptionId());
- response.setStatus(DavServletResponse.SC_NO_CONTENT);
- }
-
- /**
- * The POLL method
- *
- * @param request
- * @param response
- * @param resource
- * @throws IOException
- * @throws DavException
- */
- protected void doPoll(WebdavRequest request,
- WebdavResponse response,
- DavResource resource)
- throws IOException, DavException {
-
- if (!(resource instanceof ObservationResource)) {
- response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- return;
- }
- EventDiscovery ed = ((ObservationResource)resource).poll(request.getSubscriptionId());
- response.sendPollResponse(ed);
- }
-
- /**
- * The VERSION-CONTROL method
- *
- * @param request
- * @param response
- * @param resource
- * @throws DavException
- * @throws IOException
- */
- protected void doVersionControl(WebdavRequest request, WebdavResponse response,
- DavResource resource)
- throws DavException, IOException {
- if (!(resource instanceof VersionableResource)) {
- response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- return;
- }
- ((VersionableResource)resource).addVersionControl();
- }
-
- /**
- * The LABEL method
- *
- * @param request
- * @param response
- * @param resource
- * @throws DavException
- * @throws IOException
- */
- protected void doLabel(WebdavRequest request, WebdavResponse response,
- DavResource resource)
- throws DavException, IOException {
-
- LabelInfo labelInfo = request.getLabelInfo();
- if (resource instanceof VersionResource) {
- ((VersionResource)resource).label(labelInfo);
- } else if (resource instanceof VersionControlledResource) {
- ((VersionControlledResource)resource).label(labelInfo);
- } else {
- // any other resource type that does not support a LABEL request
- response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- }
- }
-
- /**
- * The REPORT method
- *
- * @param request
- * @param response
- * @param resource
- * @throws DavException
- * @throws IOException
- */
- protected void doReport(WebdavRequest request, WebdavResponse response,
- DavResource resource)
- throws DavException, IOException {
- if (!(resource instanceof DeltaVResource)) {
- response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- return;
- }
- ReportInfo info = request.getReportInfo();
- Report report = ((DeltaVResource)resource).getReport(info);
- response.sendXmlResponse(report.toXml(), DavServletResponse.SC_OK);
- }
-
- /**
- * The CHECKIN method
- *
- * @param request
- * @param response
- * @param resource
- * @throws DavException
- * @throws IOException
- */
- protected void doCheckin(WebdavRequest request, WebdavResponse response,
- DavResource resource)
- throws DavException, IOException {
-
- if (!(resource instanceof VersionControlledResource)) {
- response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- return;
- }
- String versionHref = ((VersionControlledResource)resource).checkin();
- response.setHeader(DeltaVConstants.HEADER_LOCATION, versionHref);
- }
-
- /**
- * The CHECKOUT method
- *
- * @param request
- * @param response
- * @param resource
- * @throws DavException
- * @throws IOException
- */
- protected void doCheckout(WebdavRequest request, WebdavResponse response,
- DavResource resource)
- throws DavException, IOException {
- if (!(resource instanceof VersionControlledResource)) {
- response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- return;
- }
- ((VersionControlledResource)resource).checkout();
- }
-
- /**
- * The UNCHECKOUT method
- *
- * @param request
- * @param response
- * @param resource
- * @throws DavException
- * @throws IOException
- */
- protected void doUncheckout(WebdavRequest request, WebdavResponse response,
- DavResource resource)
- throws DavException, IOException {
- if (!(resource instanceof VersionControlledResource)) {
- response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- return;
- }
- ((VersionControlledResource)resource).uncheckout();
- }
-
- /**
- * The MERGE method
- *
- * @param request
- * @param response
- * @param resource
- * @throws DavException
- * @throws IOException
- */
- protected void doMerge(WebdavRequest request, WebdavResponse response,
- DavResource resource) throws DavException, IOException {
-
- if (!(resource instanceof VersionControlledResource)) {
- response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- return;
- }
- MergeInfo info = request.getMergeInfo();
- MultiStatus ms = ((VersionControlledResource)resource).merge(info);
- response.sendMultiStatusResponse(ms);
- }
-
- /**
- * The UPDATE method
- *
- * @param request
- * @param response
- * @param resource
- * @throws DavException
- * @throws IOException
- */
- protected void doUpdate(WebdavRequest request, WebdavResponse response,
- DavResource resource) throws DavException, IOException {
-
- if (!(resource instanceof VersionControlledResource)) {
- response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- return;
- }
- UpdateInfo info = request.getUpdateInfo();
- MultiStatus ms = ((VersionControlledResource)resource).update(info);
- response.sendMultiStatusResponse(ms);
- }
-
- /**
- * The MKWORKSPACE method
- *
- * @param request
- * @param response
- * @param resource
- * @throws DavException
- * @throws IOException
- */
- protected void doMkWorkspace(WebdavRequest request, WebdavResponse response,
- DavResource resource) throws DavException, IOException {
- if (resource.exists()) {
- log.warn("Cannot create a new workspace. Resource already exists.");
- response.sendError(DavServletResponse.SC_FORBIDDEN);
- return;
- }
-
- DavResource parentResource = resource.getCollection();
- if (parentResource == null || !parentResource.exists() || !parentResource.isCollection()) {
- // parent does not exist or is not a collection
- response.sendError(DavServletResponse.SC_CONFLICT);
- return;
- }
- if (!(parentResource instanceof DeltaVResource)) {
- response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- return;
- }
- ((DeltaVResource)parentResource).addWorkspace(resource);
- response.setStatus(DavServletResponse.SC_CREATED);
- }
-
- /**
- * The SEARCH method
- *
- * @param request
- * @param response
- * @param resource
- * @throws DavException
- * @throws IOException
- */
- protected void doSearch(WebdavRequest request, WebdavResponse response,
- DavResource resource) throws DavException, IOException {
-
- if (!(resource instanceof SearchResource)) {
- response.sendError(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- return;
- }
- try {
- Document doc = request.getRequestDocument();
- if (doc != null) {
- SearchRequest sR = new SearchRequest(doc);
- response.sendMultiStatusResponse(((SearchResource)resource).search(sR));
- } else {
- // request without request body is valid if requested resource
- // is a 'query' resource.
- response.sendMultiStatusResponse(((SearchResource)resource).search(null));
- }
- } catch (IllegalArgumentException e) {
- response.sendError(DavServletResponse.SC_BAD_REQUEST);
- return;
- }
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/JCRWebdavServer.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/JCRWebdavServer.java
deleted file mode 100644
index 438e3134a19..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/JCRWebdavServer.java
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.server;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.spi.JcrDavException;
-import org.apache.jackrabbit.client.RepositoryAccessServlet;
-
-import javax.jcr.*;
-import javax.servlet.ServletException;
-import java.util.HashMap;
-import java.util.HashSet;
-/**
- * JCRWebdavServer...
- */
-public class JCRWebdavServer implements DavSessionProvider {
-
- /** the default logger */
- private static Logger log = Logger.getLogger(JCRWebdavServer.class);
-
- /** the session cache */
- private final SessionCache cache = new SessionCache();
-
- /** the jcr repository */
- private final Repository repository;
-
- /**
- * Creates a new JCRWebdavServer that operates on the given repository.
- *
- * @param repository
- */
- public JCRWebdavServer(Repository repository) {
- this.repository = repository;
- }
-
- //---------------------------------------< DavSessionProvider interface >---
- /**
- * Acquires a DavSession either from the session cache or creates a new
- * one by login to the repository.
- * Upon success, the WebdavRequest will reference that session.
- *
- * @param request
- * @throws DavException if no session could be obtained.
- * @see DavSessionProvider#acquireSession(org.apache.jackrabbit.webdav.WebdavRequest)
- */
- public void acquireSession(WebdavRequest request)
- throws DavException {
- DavSession session = cache.get(request);
- request.setDavSession(session);
- }
-
- /**
- * Releases the reference from the request to the session. If no further
- * references to the session exist, the session will be removed from the
- * cache.
- *
- * @param request
- * @see DavSessionProvider#releaseSession(org.apache.jackrabbit.webdav.WebdavRequest)
- */
- public void releaseSession(WebdavRequest request) {
- DavSession session = request.getDavSession();
- if (session != null) {
- session.removeReference(request);
- }
- // remove the session from the request
- request.setDavSession(null);
- }
-
- //--------------------------------------------------------------------------
- /**
- * Private inner class implementing the DavSession interface.
- */
- private class DavSessionImpl implements DavSession {
-
- /** the underlaying jcr session */
- private final Session session;
-
- /**
- * Private constructor.
- *
- * @param request
- * @throws DavException in case a {@link javax.jcr.LoginException} or {@link javax.jcr.RepositoryException} occurs.
- */
- private DavSessionImpl(DavServletRequest request) throws DavException {
- try {
- String workspaceName = request.getRequestLocator().getWorkspaceName();
- Credentials creds = RepositoryAccessServlet.getCredentialsFromHeader(request.getHeader(DavConstants.HEADER_AUTHORIZATION));
- session = repository.login(creds, workspaceName);
- } catch (RepositoryException e) {
- // LoginException, RepositoryException both result in FORBIDDEN
- throw new JcrDavException(e);
- } catch (ServletException e) {
- throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
- }
- }
-
- /**
- * Add a reference to this DavSession.
- *
- * @see DavSession#addReference(Object)
- */
- public void addReference(Object reference) {
- cache.addReference(this, reference);
- }
-
- /**
- * Removes the reference from this DavSession. If no
- * more references are present, this DavSession is removed
- * from the internal cache and the underlaying session is released by calling
- * {@link javax.jcr.Session#logout()}.
- *
- * @see DavSession#removeReference(Object)
- */
- public void removeReference(Object reference) {
- cache.removeReference(this, reference);
- }
-
- /**
- * @see DavSession#getRepositorySession()
- */
- public Session getRepositorySession() {
- return session;
- }
-
- /**
- * @see DavSession#addLockToken(String)
- */
- public void addLockToken(String token) {
- session.addLockToken(token);
- }
-
- /**
- * @see DavSession#getLockTokens()
- */
- public String[] getLockTokens() {
- return session.getLockTokens();
- }
-
- /**
- * @see DavSession#removeLockToken(String)
- */
- public void removeLockToken(String token) {
- session.removeLockToken(token);
- }
- }
-
- /**
- * Private inner class providing a cache for referenced session objects.
- */
- private class SessionCache {
-
- private SessionMap sessionMap = new SessionMap();
- private HashMap referenceToSessionMap = new HashMap();
-
- /**
- * Try to retrieve DavSession if a TransactionId or
- * SubscriptionId is present in the request header. If no cached session
- * was found null is returned.
- *
- * @param request
- * @return a cached DavSession or null.
- * @throws DavException
- */
- private DavSession get(WebdavRequest request)
- throws DavException {
- String txId = request.getTransactionId();
- String subscriptionId = request.getSubscriptionId();
- String lockToken = request.getLockToken();
-
- if ((lockToken != null || txId != null) && subscriptionId != null) {
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED, "Ambiguous headers: either TransactionId/Lock-Token or SubscriptionId can be present, not both.");
- }
-
- DavSession session = null;
- // try to retrieve a cached session
- if (lockToken != null && containsReference(lockToken)) {
- session = getSessionByReference(lockToken);
- } else if (txId != null && containsReference(txId)) {
- session = getSessionByReference(txId);
- } else if (subscriptionId != null && containsReference(subscriptionId)) {
- session = getSessionByReference(subscriptionId);
- }
- // no cached session present -> create new one.
- if (session == null) {
- session = new DavSessionImpl(request);
- sessionMap.put(session, new HashSet());
- log.info("login: User '" + session.getRepositorySession().getUserId() + "' logged in.");
- } else {
- log.info("login: Retrieved cached session for user '" + session.getRepositorySession().getUserId() + "'");
- }
- addReference(session, request);
- return session;
- }
-
- /**
- * Add a references to the specified DavSession.
- *
- * @param session
- * @param reference
- */
- private void addReference(DavSession session, Object reference) {
- HashSet referenceSet = sessionMap.get(session);
- if (referenceSet != null) {
- referenceSet.add(reference);
- referenceToSessionMap.put(reference, session);
- } else {
- log.error("Failed to add reference to session. No entry in cache found.");
- }
- }
-
- /**
- * Remove the given reference from the specified DavSession.
- *
- * @param session
- * @param reference
- */
- private void removeReference(DavSession session, Object reference) {
- HashSet referenceSet = sessionMap.get(session);
- if (referenceSet != null) {
- if (referenceSet.remove(reference)) {
- log.info("Removed reference " + reference + " to session " + session);
- referenceToSessionMap.remove(reference);
- } else {
- log.warn("Failed to remove reference " + reference + " to session " + session);
- }
- if (referenceSet.isEmpty()) {
- log.info("No more references present on webdav session -> clean up.");
- sessionMap.remove(session);
- log.info("Login: User '" + session.getRepositorySession().getUserId() + "' logged out");
- session.getRepositorySession().logout();
- } else {
- log.debug(referenceSet.size() + " references remaining on webdav session " + session);
- }
- } else {
- log.error("Failed to remove reference from session. No entry in cache found.");
- }
- }
-
- /**
- * Returns true, if there exists a DavSession in the cache
- * that is referenced by the specified object.
- *
- * @param reference
- * @return true if a DavSession is referenced by the given
- * object.
- */
- private boolean containsReference(Object reference) {
- return referenceToSessionMap.containsKey(reference);
- }
-
- /**
- * Returns the DavSession that is referenced by the
- * specified reference object.
- *
- * @param reference
- * @return DavSession that is referenced by this reference
- * object.
- * @see #containsReference(Object)
- */
- private DavSession getSessionByReference(Object reference) {
- return (DavSession) referenceToSessionMap.get(reference);
- }
- }
-
- /**
- * Simple inner class extending the {@link HashMap}.
- */
- private static class SessionMap extends HashMap {
-
- public HashSet get(DavSession key) {
- return (HashSet) super.get(key);
- }
-
- public HashSet put(DavSession key, HashSet value) {
- return (HashSet) super.put(key, value);
- }
-
- public HashSet remove(DavSession key) {
- return (HashSet) super.remove(key);
- }
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/JCRWebdavServerServlet.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/JCRWebdavServerServlet.java
deleted file mode 100644
index deaf8dac469..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/JCRWebdavServerServlet.java
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.server;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.WebdavRequestImpl;
-import org.apache.jackrabbit.webdav.observation.*;
-import org.apache.jackrabbit.webdav.spi.*;
-import org.apache.jackrabbit.webdav.spi.observation.SubscriptionManagerImpl;
-import org.apache.jackrabbit.webdav.spi.transaction.TxLockManagerImpl;
-import org.apache.jackrabbit.client.RepositoryAccessServlet;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.*;
-import javax.jcr.Repository;
-import java.io.IOException;
-
-/**
- * JCRWebdavServerServlet provides request/response handling for the JCRWebdavServer.
- */
-public class JCRWebdavServerServlet extends AbstractWebdavServlet implements DavConstants {
-
- /** the default logger */
- private static Logger log = Logger.getLogger(JCRWebdavServerServlet.class);
-
- /** Init parameter specifying the prefix used with the resource path. */
- public static final String INIT_PARAM_PREFIX = "resource-path-prefix";
- private static String pathPrefix;
-
- private JCRWebdavServer server;
- private DavResourceFactory resourceFactory;
- private DavLocatorFactory locatorFactory;
- private TxLockManagerImpl txMgr;
- private SubscriptionManager subscriptionMgr;
-
- /**
- * Initializes the servlet set reads the following parameter from the
- * servlet configuration:
- *
- *
resource-path-prefix: optional prefix for all resources.
- *
- *
- * @throws ServletException
- */
- public void init() throws ServletException {
- super.init();
-
- // set resource path prefix
- pathPrefix = getInitParameter(INIT_PARAM_PREFIX);
- log.debug(INIT_PARAM_PREFIX + " = " + pathPrefix);
-
- Repository repository = RepositoryAccessServlet.getRepository();
- if (repository == null) {
- throw new ServletException("Repository could not be retrieved. Check config of 'RepositoryServlet'.");
- }
- server = new JCRWebdavServer(repository);
- txMgr = new TxLockManagerImpl();
- subscriptionMgr = new SubscriptionManagerImpl();
-
- // todo: ev. make configurable
- resourceFactory = new DavResourceFactoryImpl(txMgr, subscriptionMgr);
- locatorFactory = new DavLocatorFactoryImpl(pathPrefix);
- }
-
- /**
- * Returns the path prefix
- *
- * @return pathPrefix
- * @see #INIT_PARAM_PREFIX
- */
- public static String getPathPrefix() {
- return pathPrefix;
- }
-
- /**
- * Service the request.
- *
- * @param request
- * @param response
- * @throws javax.servlet.ServletException
- * @throws java.io.IOException
- * @see HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
- */
- protected void service(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
-
- WebdavRequest webdavRequest = new WebdavRequestImpl(request, locatorFactory);
- WebdavResponse webdavResponse = new WebdavResponseImpl(response);
- try {
- // login to the server
- server.acquireSession(webdavRequest);
-
- // create the resource and perform initial precondition tests
- DavResource resource = createResource(webdavRequest.getRequestLocator(), webdavRequest, webdavResponse);
- if (preconditionFailed(webdavRequest, resource)) {
- webdavResponse.sendError(DavServletResponse.SC_PRECONDITION_FAILED);
- return;
- }
-
- // execute the requested method
- int methodCode = DavMethods.getMethodCode(webdavRequest.getMethod());
- execute(webdavRequest, webdavResponse, methodCode, resource);
- } catch (DavException e) {
- webdavResponse.sendErrorResponse(e);
- } finally {
- // logout
- server.releaseSession(webdavRequest);
- }
- }
-
- /**
- *
- * @param locator
- * @param request
- * @param response
- * @return
- */
- protected DavResource createResource(DavResourceLocator locator, WebdavRequest request,
- WebdavResponse response) throws DavException {
- return resourceFactory.createResource(locator, request, response);
- }
-
- /**
- *
- * @param request
- * @param resource
- * @return
- */
- private boolean preconditionFailed(WebdavRequest request, DavResource resource) {
- // first check matching If header
- if (!request.matchesIfHeader(resource)) {
- return true;
- }
-
- // test if the requested path matches to the existing session
- // this may occur if the session was retrieved from the cache.
- String wsName = request.getDavSession().getRepositorySession().getWorkspace().getName();
- boolean failed = !resource.getLocator().isSameWorkspace(wsName);
- if (!failed) {
- // make sure, the TransactionId header is valid
- String txId = request.getTransactionId();
- if (txId != null && !txMgr.hasLock(txId, resource)) {
- failed = true;
- }
- }
- return failed;
- }
-
- /**
- * @param request
- * @param response
- * @param method
- * @param resource
- * @throws ServletException
- * @throws IOException
- * @throws DavException
- */
- private void execute(WebdavRequest request, WebdavResponse response,
- int method, DavResource resource)
- throws ServletException, IOException, DavException {
-
- switch (method) {
- case DavMethods.DAV_GET:
- doGet(request, response, resource);
- break;
- case DavMethods.DAV_HEAD:
- doHead(request, response, resource);
- break;
- case DavMethods.DAV_PROPFIND:
- doPropFind(request, response, resource);
- break;
- case DavMethods.DAV_PROPPATCH:
- doPropPatch(request, response, resource);
- break;
- case DavMethods.DAV_POST:
- case DavMethods.DAV_PUT:
- doPut(request, response, resource);
- break;
- case DavMethods.DAV_DELETE:
- doDelete(request, response, resource);
- break;
- case DavMethods.DAV_COPY:
- doCopy(request, response, resource);
- break;
- case DavMethods.DAV_MOVE:
- doMove(request, response, resource);
- break;
- case DavMethods.DAV_MKCOL:
- doMkCol(request, response, resource);
- break;
- case DavMethods.DAV_OPTIONS:
- doOptions(request, response, resource);
- break;
- case DavMethods.DAV_LOCK:
- doLock(request, response, resource);
- break;
- case DavMethods.DAV_UNLOCK:
- doUnlock(request, response, resource);
- break;
- case DavMethods.DAV_ORDERPATCH:
- doOrderPatch(request, response, resource);
- break;
- case DavMethods.DAV_SUBSCRIBE:
- doSubscribe(request, response, resource);
- break;
- case DavMethods.DAV_UNSUBSCRIBE:
- doUnsubscribe(request, response, resource);
- break;
- case DavMethods.DAV_POLL:
- doPoll(request, response, resource);
- break;
- case DavMethods.DAV_SEARCH:
- doSearch(request, response, resource);
- break;
- case DavMethods.DAV_VERSION_CONTROL:
- doVersionControl(request, response, resource);
- break;
- case DavMethods.DAV_LABEL:
- doLabel(request, response, resource);
- break;
- case DavMethods.DAV_REPORT:
- doReport(request, response, resource);
- break;
- case DavMethods.DAV_CHECKIN:
- doCheckin(request, response, resource);
- break;
- case DavMethods.DAV_CHECKOUT:
- doCheckout(request, response, resource);
- break;
- case DavMethods.DAV_UNCHECKOUT:
- doUncheckout(request, response, resource);
- break;
- case DavMethods.DAV_MERGE:
- doMerge(request, response, resource);
- break;
- case DavMethods.DAV_UPDATE:
- doUpdate(request, response, resource);
- break;
- case DavMethods.DAV_MKWORKSPACE:
- doMkWorkspace(request, response, resource);
- break;
- default:
- // any other method
- super.service(request, response);
- }
- }
-}
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/RepositoryStartupServlet.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/RepositoryStartupServlet.java
deleted file mode 100644
index 182687b5393..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/RepositoryStartupServlet.java
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.server;
-
-import org.apache.log4j.PropertyConfigurator;
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.core.config.RepositoryConfig;
-import org.apache.jackrabbit.core.RepositoryImpl;
-import org.apache.jackrabbit.rmi.server.ServerAdapterFactory;
-import org.xml.sax.InputSource;
-
-import javax.servlet.http.HttpServlet;
-import javax.servlet.ServletException;
-import javax.jcr.*;
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
-import java.io.*;
-import java.util.Properties;
-import java.util.Enumeration;
-import java.rmi.registry.Registry;
-import java.rmi.registry.LocateRegistry;
-import java.rmi.Naming;
-import java.rmi.RemoteException;
-import java.rmi.AlreadyBoundException;
-import java.rmi.Remote;
-import java.net.MalformedURLException;
-
-/**
- * The RepositoryStartupServlet starts a jackrabbit repository and registers it
- * to the JNDI environment and optional to the RMI registry.
- */
-public class RepositoryStartupServlet extends HttpServlet {
-
- /** the default logger */
- private static Logger log;
-
- /** initial param name for the repository config location */
- public final static String INIT_PARAM_REPOSITORY_CONFIG = "repository-config";
-
- /** initial param name for the repository home directory */
- public final static String INIT_PARAM_REPOSITORY_HOME = "repository-home";
-
- /** initial param name for the repository name */
- public final static String INIT_PARAM_REPOSITORY_NAME = "repository-name";
-
- /** initial param name for the rmi port */
- public final static String INIT_PARAM_RMI_PORT = "rmi-port";
-
- /** initial param name for the log4j config properties */
- public final static String INIT_PARAM_LOG4J_CONFIG = "log4j-config";
-
- /** the registered repository */
- private static RepositoryImpl repository;
-
- /** the name of the repository as configured */
- private static String repositoryName;
-
- /** the jndi context, created base on configuration */
- private static InitialContext jndiContext;
-
- /** the rmi uri, in the form of '//:${rmi-port}/${repository-name}' */
- private static String rmiURI;
-
- /**
- * Initializes the servlet
- * @throws ServletException
- */
- public void init() throws ServletException {
- super.init();
- initLog4J();
- log.info("RepositoryStartupServlet initializing...");
- initRepository();
- registerJNDI();
- registerRMI();
- log.info("RepositoryStartupServlet initialized.");
- }
-
- /**
- * destroy the servlet
- */
- public void destroy() {
- super.destroy();
- if (log == null) {
- log("RepositoryStartupServlet shutting down...");
- } else {
- log.info("RepositoryStartupServlet shutting down...");
- }
- unregisterRMI();
- unregisterJNDI();
- log("RepositoryStartupServlet shut down.");
- }
-
- /**
- * Initializes Log4J
- * @throws ServletException
- */
- private void initLog4J() throws ServletException {
- // setup log4j
- String log4jConfig = getServletConfig().getInitParameter(INIT_PARAM_LOG4J_CONFIG);
- InputStream in =getServletContext().getResourceAsStream(log4jConfig);
- if (in==null) {
- // try normal init
- PropertyConfigurator.configure(log4jConfig);
- } else {
- try {
- Properties log4jProperties = new Properties();
- log4jProperties.load(in);
- in.close();
- PropertyConfigurator.configure(log4jProperties);
- } catch (IOException e) {
- throw new ServletException("Unable to load log4jProperties: " + e.toString());
- }
- }
- log = Logger.getLogger(RepositoryStartupServlet.class);
- }
-
- /**
- * Creates a new Repository based on configuration
- * @throws ServletException
- */
- private void initRepository() throws ServletException {
- // setup home directory
- String repHome = getServletConfig().getInitParameter(INIT_PARAM_REPOSITORY_HOME);
- if (repHome==null) {
- log.error(INIT_PARAM_REPOSITORY_HOME + " missing.");
- throw new ServletException(INIT_PARAM_REPOSITORY_HOME + " missing.");
- }
- File repositoryHome;
- try {
- repositoryHome = new File(repHome).getCanonicalFile();
- } catch (IOException e) {
- log.error(INIT_PARAM_REPOSITORY_HOME + " invalid." + e.toString());
- throw new ServletException(INIT_PARAM_REPOSITORY_HOME + " invalid." + e.toString());
- }
- log.info(" repository-home = " + repositoryHome.getPath());
-
- // get repository config
- String repConfig = getServletConfig().getInitParameter(INIT_PARAM_REPOSITORY_CONFIG);
- if (repConfig==null) {
- log.error(INIT_PARAM_REPOSITORY_CONFIG + " missing.");
- throw new ServletException(INIT_PARAM_REPOSITORY_CONFIG + " missing.");
- }
- log.info(" repository-config = " + repConfig);
-
- InputStream in = getServletContext().getResourceAsStream(repConfig);
- if (in==null) {
- try {
- in = new FileInputStream(new File(repositoryHome, repConfig));
- } catch (FileNotFoundException e) {
- log.error(INIT_PARAM_REPOSITORY_CONFIG + " invalid." + e.toString());
- throw new ServletException(INIT_PARAM_REPOSITORY_CONFIG + " invalid." + e.toString());
- }
- }
-
- // get repository name
- repositoryName = getServletConfig().getInitParameter(INIT_PARAM_REPOSITORY_NAME);
- if (repositoryName==null) {
- repositoryName="default";
- }
- log.info(" repository-name = " + repositoryName);
-
- try {
- InputSource is = new InputSource(in);
- RepositoryConfig config = RepositoryConfig.create(is, repositoryHome.getAbsolutePath());
- repository = RepositoryImpl.create(config);
- } catch (RepositoryException e) {
- throw new ServletException("Error while creating repository", e);
- }
- }
-
- /**
- * Registers the repository in the JNDI context
- * @throws ServletException
- */
- private void registerJNDI() throws ServletException {
- // registering via jndi
- Properties env = new Properties();
- Enumeration names = getServletConfig().getInitParameterNames();
- while (names.hasMoreElements()) {
- String name = (String) names.nextElement();
- if (name.startsWith("java.naming.")) {
- env.put(name, getServletConfig().getInitParameter(name));
- log.info(" adding property to JNDI environment: " + name + "=" + env.getProperty(name));
- }
- }
- try {
- jndiContext = new InitialContext(env);
- jndiContext.bind(repositoryName, repository);
- } catch (NamingException e) {
- throw new ServletException(e);
- }
- log.info("Repository bound to JNDI with name: " + repositoryName);
- }
-
- /**
- * Unregisters the repository from the JNDI context
- */
- private void unregisterJNDI() {
- if (jndiContext != null) {
- try {
- jndiContext.unbind(repositoryName);
- } catch (NamingException e) {
- log("Error while unbinding repository from JNDI: " + e);
- }
- }
- }
-
- /**
- * Registers the repositroy to the RMI registry
- * @throws ServletException
- */
- private void registerRMI() throws ServletException {
- // check registering via RMI
- String rmiPortStr = getServletConfig().getInitParameter(INIT_PARAM_RMI_PORT);
- if (rmiPortStr != null) {
- int rmiPort = 0;
- try {
- rmiPort = Integer.parseInt(rmiPortStr);
- } catch (NumberFormatException e) {
- log.warn("Invalid port in rmi-port param: " + e);
- }
- if (rmiPort == 0) {
- rmiPort = Registry.REGISTRY_PORT;
- }
-
- // try to create remote repository
- Remote remote = null;
- try {
- Class clazz = Class.forName("org.apache.jackrabbit.server.RMIRemoteFactoryDelegater");
- RemoteFactoryDelegater rmf = (RemoteFactoryDelegater) clazz.newInstance();
- remote = rmf.createRemoteRepository(repository);
- } catch (RemoteException e) {
- throw new ServletException("Unable to create remote repository: " + e.toString(), e);
- } catch (NoClassDefFoundError e) {
- log.warn("Unable to create RMI repository. jcr-rmi.jar might be missing.: " + e.toString());
- return;
- } catch (Exception e) {
- log.warn("Unable to create RMI repository. jcr-rmi.jar might be missing.: " + e.toString());
- return;
- }
-
- try {
- System.setProperty("java.rmi.server.useCodebaseOnly", "true");
- try {
- // start registry
- LocateRegistry.createRegistry(rmiPort);
- } catch (RemoteException e) {
- // ignore
- }
- rmiURI = "//:" + rmiPort + "/" + repositoryName;
- Naming.bind(rmiURI, remote);
-
- log.info("Repository bound via RMI with name: " + rmiURI);
- } catch (MalformedURLException e) {
- throw new ServletException("Unable to bind repository via RMI: " + e.toString(), e);
- } catch (RemoteException e) {
- throw new ServletException("Unable to bind repository via RMI: " + e.toString(), e);
- } catch (AlreadyBoundException e) {
- throw new ServletException("Unable to bind repository via RMI: " + e.toString(), e);
- }
- }
- }
-
- /**
- * Unregisters the repository from the RMI registry
- */
- private void unregisterRMI() {
- if (rmiURI != null) {
- try {
- Naming.unbind(rmiURI);
- } catch (Exception e) {
- log("Error while unbinding repository from JNDI: " + e);
- }
- }
- }
-
-}
-
-/**
- * optional class for RMI, will only be used, if RMI server is present
- */
-abstract class RemoteFactoryDelegater {
-
- public abstract Remote createRemoteRepository(Repository repository)
- throws RemoteException;
-}
-/**
- * optional class for RMI, will only be used, if RMI server is present
- */
-class RMIRemoteFactoryDelegater extends RemoteFactoryDelegater {
-
- // only used to enforce linking upon Class.forName()
- static String FactoryClassName = ServerAdapterFactory.class.getName();
-
- public Remote createRemoteRepository(Repository repository)
- throws RemoteException {
- return new ServerAdapterFactory().getRemoteRepository(repository);
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/WebdavServlet.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/WebdavServlet.java
deleted file mode 100644
index d9259539487..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/WebdavServlet.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.server.simple;
-
-import org.apache.jackrabbit.server.simple.dav.lock.SimpleLockManager;
-import org.apache.jackrabbit.server.simple.dav.ResourceFactoryImpl;
-import org.apache.jackrabbit.server.simple.dav.LocatorFactoryImpl;
-import org.apache.jackrabbit.server.simple.dav.DavSessionProviderImpl;
-
-import javax.servlet.http.*;
-import javax.servlet.*;
-import java.io.*;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.server.AbstractWebdavServlet;
-import org.apache.jackrabbit.webdav.*;
-
-/**
- * WebdavServlet provides webdav support (level 1 and 2 complient) for repository
- * resources.
- */
-public class WebdavServlet extends AbstractWebdavServlet {
-
- /** the default logger */
- private static final Logger log = Logger.getLogger(WebdavServlet.class);
-
- /** init param name of the repository prefix */
- public static final String INIT_PARAM_RESOURCE_PATH_PREFIX = "resource-path-prefix";
-
- /**
- * Map used to remember any webdav lock created without being reflected
- * in the underlaying repository.
- * This is needed because some clients rely on a successful locking
- * mechanism in order to perform properly (e.g. mac OSX built-in dav client)
- */
- private SimpleLockManager lockManager;
-
- /** the resource factory */
- private DavResourceFactory resourceFactory;
-
- /** the locator factory */
- private DavLocatorFactory locatorFactory;
-
- /** the session provider */
- private DavSessionProvider sessionProvider;
-
- /** the repository prefix retrieved from config */
- private static String resourcePathPrefix;
-
- /**
- * Init this servlet
- *
- * @throws ServletException
- */
- public void init() throws ServletException {
- super.init();
-
- resourcePathPrefix = getInitParameter(INIT_PARAM_RESOURCE_PATH_PREFIX);
- if (resourcePathPrefix == null) {
- log.debug("Missing path prefix > setting to empty string.");
- resourcePathPrefix = "";
- } else if (resourcePathPrefix.endsWith("/")) {
- log.debug("Path prefix ends with '/' > removing trailing slash.");
- resourcePathPrefix = resourcePathPrefix.substring(0, resourcePathPrefix.length()-1);
- }
- log.info(INIT_PARAM_RESOURCE_PATH_PREFIX + " = '" + resourcePathPrefix + "'");
-
- lockManager = new SimpleLockManager();
- resourceFactory = new ResourceFactoryImpl(lockManager);
- locatorFactory = new LocatorFactoryImpl(resourcePathPrefix);
- }
-
- /**
- * Service the given request.
- *
- * @param request
- * @param response
- * @throws ServletException
- * @throws IOException
- */
- protected void service(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
-
- try {
- WebdavRequest webdavRequest = new WebdavRequestImpl(request, locatorFactory);
- WebdavResponse webdavResponse = new WebdavResponseImpl(response);
-
- // make sure there is a authenticated user
- getDavSessionProvider().acquireSession(webdavRequest);
- if (webdavRequest.getDavSession() == null) {
- return;
- }
-
- // check matching if=header for lock-token relevant operations
- DavResource resource = createResource(webdavRequest.getRequestLocator(), webdavRequest, webdavResponse);
- if (resource.exists() && !webdavRequest.matchesIfHeader(resource)) {
- webdavResponse.sendError(DavServletResponse.SC_PRECONDITION_FAILED);
- return;
- }
-
- /* set cache control headers in order to deal with non-dav complient
- * http1.1 or http1.0 proxies. >> see RFC2518 9.4.5 */
- webdavResponse.addHeader("Pragma", "No-cache"); // http1.0
- webdavResponse.addHeader("Cache-Control", "no-cache"); // http1.1
-
- int methodCode = DavMethods.getMethodCode(webdavRequest.getMethod());
- switch (methodCode) {
- case DavMethods.DAV_HEAD:
- case DavMethods.DAV_GET:
- doGet(webdavRequest, webdavResponse, resource);
- case DavMethods.DAV_OPTIONS:
- doOptions(webdavRequest, webdavResponse, resource);
- break;
- case DavMethods.DAV_PROPFIND:
- doPropFind(webdavRequest, webdavResponse, resource);
- break;
- case DavMethods.DAV_PROPPATCH:
- doPropPatch(webdavRequest, webdavResponse, resource);
- break;
- case DavMethods.DAV_PUT:
- case DavMethods.DAV_POST:
- doPut(webdavRequest, webdavResponse, resource);
- break;
- case DavMethods.DAV_DELETE:
- doDelete(webdavRequest, webdavResponse, resource);
- break;
- case DavMethods.DAV_COPY:
- doCopy(webdavRequest, webdavResponse, resource);
- break;
- case DavMethods.DAV_MOVE:
- doMove(webdavRequest, webdavResponse, resource);
- break;
- case DavMethods.DAV_MKCOL:
- doMkCol(webdavRequest, webdavResponse, resource);
- break;
- case DavMethods.DAV_LOCK:
- doLock(webdavRequest, webdavResponse, resource);
- break;
- case DavMethods.DAV_UNLOCK:
- doUnlock(webdavRequest, webdavResponse, resource);
- break;
- default:
- // GET, HEAD, TRACE......
- super.service(request, response);
- }
- getDavSessionProvider().releaseSession(webdavRequest);
-
- } catch (DavException e) {
- response.sendError(e.getErrorCode());
- }
- }
-
- /**
- * The MKCOL method
- *
- * @throws IOException
- */
- protected void doMkCol(WebdavRequest request, WebdavResponse response,
- DavResource resource) throws IOException, DavException {
- // mkcol request with request.body is not supported.
- if (request.getContentLength()>0 || request.getHeader("Transfer-Encoding") != null) {
- response.sendError(DavServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
- return;
- }
- super.doMkCol(request, response, resource);
- }
-
- /**
- * Build a DavResource from the given path.
- * Please note, that the resource may not have a corresponding element in
- * the repository in which case, {@link DavResource#exists()} will return
- * false.
- *
- * @see AbstractWebdavServlet#createResource(org.apache.jackrabbit.webdav.DavResourceLocator, org.apache.jackrabbit.webdav.WebdavRequest, org.apache.jackrabbit.webdav.WebdavResponse)
- */
- protected DavResource createResource(DavResourceLocator locator, WebdavRequest request, WebdavResponse response)
- throws DavException {
- return resourceFactory.createResource(locator, request, response);
- }
-
- /**
- * Returns the configured path prefix
- *
- * @return resourcePathPrefix
- * @see #INIT_PARAM_RESOURCE_PATH_PREFIX
- */
- public static String getPathPrefix() {
- return resourcePathPrefix;
- }
-
- /**
- * Returns the DavSessionProvider. If no session provider has
- * been set or created a new instance of {@link DavSessionProviderImpl} is
- * return.
- *
- * @return the session provider
- */
- public DavSessionProvider getDavSessionProvider() {
- if (sessionProvider == null) {
- sessionProvider = new DavSessionProviderImpl();
- }
- return sessionProvider;
- }
-
- /**
- * Set the session provider
- *
- * @param sessionProvider
- */
- public void setDavSessionProvider(DavSessionProvider sessionProvider) {
- this.sessionProvider = sessionProvider;
- }
-}
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/dav/DavResourceImpl.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/dav/DavResourceImpl.java
deleted file mode 100644
index 28097a3711c..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/dav/DavResourceImpl.java
+++ /dev/null
@@ -1,659 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.server.simple.dav;
-
-import javax.jcr.*;
-import javax.jcr.lock.Lock;
-import java.util.*;
-import java.io.*;
-
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.util.Text;
-import org.apache.jackrabbit.webdav.spi.lock.JcrActiveLock;
-import org.apache.jackrabbit.webdav.spi.JcrDavException;
-import org.apache.jackrabbit.webdav.lock.*;
-import org.apache.jackrabbit.webdav.property.*;
-
-/**
- * DavResourceImpl imeplements a DavResource.
- */
-public class DavResourceImpl implements DavResource {
-
- private DavResourceFactory factory;
- private LockManager lockManager;
- private DavSession session;
- private Node node;
- private DavResourceLocator locator;
-
- private DavPropertySet properties;
- private boolean isCollection = true;
-
- /** is created on initProperties */
- private NodeResource nodeResource;
-
- /**
- * Create a new {@link DavResource}.
- *
- * @param locator
- * @param factory
- * @param session
- */
- public DavResourceImpl(DavResourceLocator locator, DavResourceFactory factory, DavSession session) {
- this.session = session;
- this.factory = factory;
- this.locator = locator;
- if (locator != null && locator.getResourcePath() != null) {
- try {
- init(session.getRepositorySession().getItem(locator.getResourcePath()));
- } catch (RepositoryException e) {
- // ignore: exists field evaluates to false
- }
- }
- }
-
- /**
- * Init the webdav resource and retrieve the relevant property.
- *
- * @param repositoryItem
- * @throws RepositoryException
- */
- private void init(Item repositoryItem) throws RepositoryException {
- if (repositoryItem == null || !repositoryItem.isNode()) {
- return;
- }
- node = (Node)repositoryItem;
-
- // define what is a resource in webdav
- if (node.isNodeType("nt:resource") || node.isNodeType("nt:file")) {
- isCollection = false;
- }
- }
-
- /**
- * @return DavResource#COMPLIANCE_CLASS
- * @see org.apache.jackrabbit.webdav.DavResource#getComplianceClass()
- */
- public String getComplianceClass() {
- return DavResource.COMPLIANCE_CLASS;
- }
-
- /**
- * @return DavResource#METHODS
- * @see org.apache.jackrabbit.webdav.DavResource#getSupportedMethods()
- */
- public String getSupportedMethods() {
- return DavResource.METHODS;
- }
-
- /**
- * @see DavResource#exists() )
- */
- public boolean exists() {
- return node != null;
- }
-
- /**
- * @see DavResource#isCollection()
- */
- public boolean isCollection() {
- return isCollection;
- }
-
- /**
- * @see org.apache.jackrabbit.webdav.DavResource#getLocator()
- */
- public DavResourceLocator getLocator() {
- return locator;
- }
-
- /**
- * @see DavResource#getResourcePath()
- */
- public String getResourcePath() {
- return locator.getResourcePath();
- }
-
- /**
- * @see DavResource#getHref()
- */
- public String getHref() {
- return locator.getHref(isCollection());
- }
-
- /**
- * @see DavResource#getDisplayName()
- */
- public String getDisplayName() {
- String name = null;
- if (exists()) {
- try {
- name = node.getName();
- } catch (RepositoryException e) {
- // ignore
- }
- }
- if (name == null && getResourcePath() != null) {
- name = Text.getLabel(getResourcePath());
- }
- return name;
- }
-
- /**
- * @see org.apache.jackrabbit.webdav.DavResource#getModificationTime()
- */
- public long getModificationTime() {
- initProperties();
- return nodeResource == null ? 0 : nodeResource.getModificationTime();
- }
-
- /**
- * @see org.apache.jackrabbit.webdav.DavResource#getStream()
- */
- public InputStream getStream() {
- initProperties();
- return nodeResource == null ? null : nodeResource.getStream();
- }
-
- /**
- * @see DavResource#getProperty(org.apache.jackrabbit.webdav.property.DavPropertyName)
- */
- public DavProperty getProperty(DavPropertyName name) {
- initProperties();
- return properties.get(name);
- }
-
- /**
- * @see DavResource#getProperties()
- */
- public DavPropertySet getProperties() {
- initProperties();
- return properties;
- }
-
- /**
- * @see DavResource#getPropertyNames()
- */
- public DavPropertyName[] getPropertyNames() {
- return getProperties().getPropertyNames();
- }
-
- /**
- * Fill the set of properties
- */
- private void initProperties() {
- if (properties == null && exists()) {
- properties = new DavPropertySet();
- try {
- nodeResource = new NodeResource(this, node);
- properties.add(new DefaultDavProperty(DavPropertyName.GETCONTENTLENGTH, nodeResource.getContentLength()+""));
- properties.add(new DefaultDavProperty(DavPropertyName.CREATIONDATE, nodeResource.getCreationDate()));
- properties.add(new DefaultDavProperty(DavPropertyName.GETLASTMODIFIED, nodeResource.getLastModified()));
- String contentType = nodeResource.getContentType();
- if (contentType != null) {
- properties.add(new DefaultDavProperty(DavPropertyName.GETCONTENTTYPE, contentType));
- }
- properties.add(new DefaultDavProperty(DavPropertyName.GETETAG, nodeResource.getETag()));
- } catch (RepositoryException e) {
- // should not occure....
- }
-
- if (getDisplayName() != null) {
- properties.add(new DefaultDavProperty(DavPropertyName.DISPLAYNAME, getDisplayName()));
- }
- if (isCollection()) {
- properties.add(new ResourceType(ResourceType.COLLECTION));
- // Windows XP support
- properties.add(new DefaultDavProperty(DavPropertyName.ISCOLLECTION, "1"));
- } else {
- properties.add(new ResourceType(ResourceType.DEFAULT_RESOURCE));
- // Windows XP support
- properties.add(new DefaultDavProperty(DavPropertyName.ISCOLLECTION, "0"));
- }
-
- /* set current lock information. If no lock is set to this resource,
- an empty lockdiscovery will be returned in the response. */
- properties.add(new LockDiscovery(getLock(Type.WRITE, Scope.EXCLUSIVE)));
-
- /* lock support information: all locks are lockable. */
- SupportedLock supportedLock = new SupportedLock();
- supportedLock.addEntry(Type.WRITE, Scope.EXCLUSIVE);
- properties.add(supportedLock);
- }
- }
-
- /**
- * @param property
- * @throws DavException
- * @see DavResource#setProperty(org.apache.jackrabbit.webdav.property.DavProperty)
- */
- public void setProperty(DavProperty property) throws DavException {
- if (isLocked(this)) {
- throw new DavException(DavServletResponse.SC_LOCKED);
- }
- throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- }
-
- /**
- * @param propertyName
- * @throws DavException
- * @see DavResource#removeProperty(org.apache.jackrabbit.webdav.property.DavPropertyName)
- */
- public void removeProperty(DavPropertyName propertyName) throws DavException {
- if (isLocked(this)) {
- throw new DavException(DavServletResponse.SC_LOCKED);
- }
- throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- }
-
- /**
- * @see DavResource#getCollection()
- */
- public DavResource getCollection() {
- DavResource parent = null;
- if (getResourcePath() != null && !getResourcePath().equals("/")) {
- String parentPath = Text.getRelativeParent(getResourcePath(), 1);
- if (parentPath.equals("")) {
- parentPath="/";
- }
- DavResourceLocator parentloc = locator.getFactory().createResourceLocator(locator.getPrefix(), locator.getWorkspacePath(), parentPath);
- try {
- parent = factory.createResource(parentloc, session);
- } catch (DavException e) {
- // should not occur
- }
- }
- return parent;
- }
-
- /**
- * @see DavResource#getMembers()
- */
- public DavResourceIterator getMembers() {
- ArrayList list = new ArrayList();
- if (exists() && isCollection()) {
- try {
- NodeIterator it = node.getNodes();
- while(it.hasNext()) {
- list.add(buildResourceFromItem(it.nextNode()));
- }
- } catch (RepositoryException e) {
- // should not occure
- } catch (DavException e) {
- // should not occure
- }
- }
- return new DavResourceIteratorImpl(list);
- }
-
- /**
- * @see DavResource#addMember(DavResource, InputStream)
- */
- public void addMember(DavResource member, InputStream in) throws DavException {
- if (!exists() || in == null) {
- throw new DavException(DavServletResponse.SC_BAD_REQUEST);
- }
- if (isLocked(this)) {
- throw new DavException(DavServletResponse.SC_LOCKED);
- }
-
- try {
- String fileName = member.getDisplayName();
- Node file;
- boolean makeVersionable = true; // todo: to be configurable somewhere
- if (node.hasNode(fileName)) {
- file = node.getNode(fileName);
- if (file.hasNode("jcr:content")) {
- // remove an existing repository entry for 'overwriting' is not possible
- file.getNode("jcr:content").remove();
- }
- } else {
- file = node.addNode(fileName, "nt:file");
- if (makeVersionable) {
- file.addMixin("mix:versionable");
- }
- }
-
- if (fileName.endsWith(".xml")) {
- importXml(file, in, "text/xml");
- } else {
- // todo: retrieve proper mimetype from filename
- importFile(file, in, "application/octet-stream");
- }
- session.getRepositorySession().save();
- } catch (ItemExistsException e) {
- // according to RFC 2518: MKCOL only possible on non-existing/deleted resource
- throw new JcrDavException(e, DavServletResponse.SC_METHOD_NOT_ALLOWED);
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- } catch (IOException e) {
- throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
- }
- }
-
- /**
- * Imports a xml into the repository
- * @param parentNode
- * @param in
- * @param contentType
- * @throws RepositoryException
- * @throws IOException
- */
- private void importXml(Node parentNode, InputStream in, String contentType)
- throws RepositoryException, IOException {
- Node content = parentNode.addNode("jcr:content", "nt:unstructured");
- content.setProperty("jcr:mimeType", contentType);
- content.setProperty("jcr:lastModified", Calendar.getInstance());
- session.getRepositorySession().importXML(content.getPath(), in);
- }
-
- /**
- * Imports a plain file to the repository
- * @param parentNode
- * @param in
- * @param contentType
- * @throws RepositoryException
- */
- private void importFile(Node parentNode, InputStream in, String contentType)
- throws RepositoryException {
- Node content = parentNode.addNode("jcr:content", "nt:resource");
- content.setProperty("jcr:mimeType", contentType);
- content.setProperty("jcr:encoding", "");
- content.setProperty("jcr:data", in);
- content.setProperty("jcr:lastModified", Calendar.getInstance());
- }
-
- /**
- * @see DavResource#addMember(DavResource)
- */
- public void addMember(DavResource member) throws DavException {
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_CONFLICT);
- }
- if (isLocked(this)) {
- throw new DavException(DavServletResponse.SC_LOCKED);
- }
- try {
- node.addNode(member.getDisplayName(), "nt:folder");
- node.save();
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- }
-
- /**
- * @see DavResource#removeMember(DavResource)
- */
- public void removeMember(DavResource member) throws DavException {
- if (!exists() || !member.exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
- if (isLocked(this) || isLocked(member)) {
- throw new DavException(DavServletResponse.SC_LOCKED);
- }
-
- try {
- // make sure, non-jcr locks are removed.
- if (!isJsrLockable()) {
- ActiveLock lock = getLock(Type.WRITE, Scope.EXCLUSIVE);
- if (lock != null) {
- lockManager.releaseLock(lock.getToken(), member);
- }
- }
- ActiveLock lock = getLock(Type.WRITE, Scope.EXCLUSIVE);
- if (lock != null && lockManager.hasLock(lock.getToken(), member)) {
- lockManager.releaseLock(lock.getToken(), member);
- }
-
- Session s = session.getRepositorySession();
- Item memItem = s.getItem(member.getResourcePath());
- memItem.remove();
- s.save();
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- }
-
- /**
- * @see DavResource#move(DavResource)
- */
- public void move(DavResource destination) throws DavException {
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
- if (isLocked(this)) {
- throw new DavException(DavServletResponse.SC_LOCKED);
- }
- try {
- session.getRepositorySession().getWorkspace().move(getResourcePath(), destination.getResourcePath());
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- }
-
- /**
- * @see DavResource#copy(DavResource, boolean)
- */
- public void copy(DavResource destination, boolean shallow) throws DavException {
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
- if (isLocked(destination)) {
- throw new DavException(DavServletResponse.SC_LOCKED);
- }
- // TODO: support shallow and deep copy
- if (shallow) {
- throw new DavException(DavServletResponse.SC_FORBIDDEN, "Unable to perform shallow copy.");
- }
- try {
- session.getRepositorySession().getWorkspace().copy(getResourcePath(), destination.getResourcePath());
- } catch (PathNotFoundException e) {
- // according to rfc 2518: missing parent
- throw new DavException(DavServletResponse.SC_CONFLICT, e.getMessage());
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- }
-
- /**
- * @param type
- * @param scope
- * @return true if type is {@link Type#WRITE} and scope is {@link Scope#EXCLUSIVE}
- * @see DavResource#isLockable(org.apache.jackrabbit.webdav.lock.Type, org.apache.jackrabbit.webdav.lock.Scope)
- */
- public boolean isLockable(Type type, Scope scope) {
- return Type.WRITE.equals(type) && Scope.EXCLUSIVE.equals(scope);
- }
-
- /**
- * @see DavResource#hasLock(org.apache.jackrabbit.webdav.lock.Type, org.apache.jackrabbit.webdav.lock.Scope)
- */
- public boolean hasLock(Type type, Scope scope) {
- return getLock(type, scope) != null;
- }
-
- /**
- * @see DavResource#getLock(Type, Scope)
- */
- public ActiveLock getLock(Type type, Scope scope) {
- ActiveLock lock = null;
- if (exists() && Type.WRITE.equals(type) && Scope.EXCLUSIVE.equals(scope)) {
- // try to retrieve the repository lock information first
- if (isJsrLockable()) {
- try {
- Lock jcrLock = node.getLock();
- if (jcrLock != null && jcrLock.isLive()) {
- lock = new JcrActiveLock(jcrLock);
- }
- } catch (RepositoryException e) {
- // LockException: no lock applies to this node >> ignore
- // RepositoryException, AccessDeniedException or another error >> ignore
- }
- } else {
- // not-jcr lockable >> check for webdav lock
- lock = lockManager.getLock(type, scope, this);
- }
- }
- return lock;
- }
-
- /**
- * @see org.apache.jackrabbit.webdav.DavResource#getLocks()
- */
- public ActiveLock[] getLocks() {
- return new ActiveLock[] {getLock(Type.WRITE, Scope.EXCLUSIVE)};
- }
-
- /**
- * @see DavResource#lock(LockInfo)
- */
- public ActiveLock lock(LockInfo lockInfo) throws DavException {
- ActiveLock lock = null;
- if (isLockable(lockInfo.getType(), lockInfo.getScope())) {
- if (isJsrLockable()) {
- try {
- // try to execute the lock operation
- Lock jcrLock = node.lock(lockInfo.isDeep(), false);
- if (jcrLock != null) {
- lock = new JcrActiveLock(jcrLock);
- }
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- } else {
- // create a new lock which creates a random lock token
- lock = lockManager.createLock(lockInfo, this);
- }
- } else {
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED, "Unsupported lock type or scope.");
- }
- return lock;
- }
-
- /**
- * @see DavResource#refreshLock(LockInfo, String)
- */
- public ActiveLock refreshLock(LockInfo lockInfo, String lockToken) throws DavException{
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
- /* since lock is always has infinite timeout >> no extra refresh needed
- return a lockdiscovery with the lock-info and the default scope and type */
- ActiveLock lock = getLock(lockInfo.getType(), lockInfo.getScope());
- if (lock == null) {
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED, "No lock present on resource " + getResourcePath());
- } else if (lock.isLockedByToken(lockToken)) {
- if (lock instanceof JcrActiveLock) {
- try {
- // refresh JCR lock and return the original lock object.
- node.getLock().refresh();
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- } else {
- lock = lockManager.refreshLock(lockInfo, lockToken, this);
- }
- } else {
- throw new DavException(DavServletResponse.SC_LOCKED);
- }
- return lock;
- }
-
- /**
- * @see DavResource#unlock(String)
- */
- public void unlock(String lockToken) throws DavException {
- ActiveLock lock = getLock(Type.WRITE, Scope.EXCLUSIVE);
- if (lock == null) {
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED);
- } else if (lock.isLockedByToken(lockToken)) {
- if (lock instanceof JcrActiveLock) {
- try {
- node.unlock();
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- } else {
- lockManager.releaseLock(lockToken, this);
- }
- } else {
- throw new DavException(DavServletResponse.SC_LOCKED);
- }
- }
-
- /**
- * @see DavResource#addLockManager(org.apache.jackrabbit.webdav.lock.LockManager)
- */
- public void addLockManager(LockManager lockMgr) {
- this.lockManager = lockMgr;
- }
-
- /**
- * @see org.apache.jackrabbit.webdav.DavResource#getFactory()
- */
- public DavResourceFactory getFactory() {
- return factory;
- }
-
- /**
- * Returns true, if this webdav resource allows for locking without checking
- * its current lock status.
- *
- * @return true if this resource is lockable.
- */
- private boolean isJsrLockable() {
- boolean lockable = false;
- if (exists()) {
- try {
- lockable = node.isNodeType("mix:lockable");
- } catch (RepositoryException e) {
- // not jcr-lockable
- }
- }
- return lockable;
- }
-
- /**
- * Return true if this resource cannot be modified due to a write lock
- * that is not owned by the given session.
- *
- * @return true if this resource cannot be modified due to a write lock
- */
- private boolean isLocked(DavResource res) {
- ActiveLock lock = res.getLock(Type.WRITE, Scope.EXCLUSIVE);
- if (lock == null) {
- return false;
- } else {
- String[] sLockTokens = session.getLockTokens();
- for (int i = 0; i < sLockTokens.length; i++) {
- if (sLockTokens[i].equals(lock.getToken())) {
- return false;
- }
- }
- return true;
- }
- }
-
- /**
- * @param item
- * @return
- * @throws DavException
- * @throws RepositoryException
- */
- private DavResource buildResourceFromItem(Item item) throws DavException, RepositoryException {
- DavResourceLocator parentloc = locator.getFactory().createResourceLocator(locator.getPrefix(), locator.getWorkspacePath(), item.getPath());
- return factory.createResource(parentloc, session);
- }
-}
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/dav/DavSessionImpl.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/dav/DavSessionImpl.java
deleted file mode 100644
index c9b68142834..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/dav/DavSessionImpl.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.server.simple.dav;
-
-import javax.jcr.Session;
-import java.util.HashSet;
-
-import org.apache.jackrabbit.webdav.DavSession;
-
-/**
- * Simple implementation of the {@link DavSession} interface. Stores
- * lock tokens but does not yet store references.
- */
-public class DavSessionImpl implements DavSession {
-
- /** the underlaying jcr session */
- private final Session session;
-
- /** the lock tokens of this session */
- private final HashSet lockTokens = new HashSet();
-
- /**
- * Creates a new DavSession based on a jcr session
- * @param session
- */
- public DavSessionImpl(Session session) {
- this.session = session;
- }
-
- /**
- * @see DavSession#addReference(Object)
- */
- public void addReference(Object reference) {
- throw new UnsupportedOperationException("No yet implemented.");
- }
-
- /**
- * @see DavSession#removeReference(Object)
- */
- public void removeReference(Object reference) {
- throw new UnsupportedOperationException("No yet implemented.");
- }
-
- /**
- * @see DavSession#getRepositorySession()
- */
- public Session getRepositorySession() {
- return session;
- }
-
- /**
- * @see DavSession#addLockToken(String)
- */
- public void addLockToken(String token) {
- lockTokens.add(token);
- }
-
- /**
- * @see DavSession#getLockTokens()
- */
- public String[] getLockTokens() {
- return (String[]) lockTokens.toArray(new String[lockTokens.size()]);
- }
-
- /**
- * @see DavSession#removeLockToken(String)
- */
- public void removeLockToken(String token) {
- lockTokens.remove(token);
- }
-}
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/dav/DavSessionProviderImpl.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/dav/DavSessionProviderImpl.java
deleted file mode 100644
index ae9297dce6e..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/dav/DavSessionProviderImpl.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.server.simple.dav;
-
-import javax.jcr.*;
-import javax.servlet.ServletException;
-
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.spi.JcrDavException;
-import org.apache.jackrabbit.client.RepositoryAccessServlet;
-
-/**
- * Simple implementation of the {@link DavSessionProvider}
- * interface that uses the {@link RepositoryAccessServlet} to locate
- * credentials in the request, log into the respository, and provide
- * a {@link DavSession} to the request.
- */
-public class DavSessionProviderImpl implements DavSessionProvider {
-
- /**
- * Acquires a DavSession. Upon success, the WebdavRequest will
- * reference that session.
- *
- * A session will not be available if credentials can not be found
- * in the request (meaning that the request has not been
- * authenticated).
- *
- * @param request
- * @throws DavException if a problem occurred while obtaining the
- * session
- * @see DavSessionProvider#acquireSession(org.apache.jackrabbit.webdav.WebdavRequest)
- */
- public void acquireSession(WebdavRequest request) throws DavException {
- try {
- Credentials creds = RepositoryAccessServlet.getCredentialsFromHeader(request.getHeader(DavConstants.HEADER_AUTHORIZATION));
- if (creds == null) {
- // generate anonymous login to gain write access
- creds = new SimpleCredentials("anonymous", "anonymous".toCharArray());
- }
- Session repSession = RepositoryAccessServlet.getRepository().login(creds);
- DavSession ds = new DavSessionImpl(repSession);
- request.setDavSession(ds);
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- } catch (ServletException e) {
- throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
- }
- }
-
- /**
- * Only removes the DavSession object from the given request object.
- * No further actions required, since DavSessionImpl does not
- * allow to keep track of references to it.
- *
- * @param request
- * @see DavSessionProvider#releaseSession(org.apache.jackrabbit.webdav.WebdavRequest)
- */
- public void releaseSession(WebdavRequest request) {
- request.setDavSession(null);
- }
-}
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/dav/LocatorFactoryImpl.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/dav/LocatorFactoryImpl.java
deleted file mode 100644
index 9cb98d1ea32..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/dav/LocatorFactoryImpl.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.server.simple.dav;
-
-import org.apache.jackrabbit.webdav.*;
-import org.apache.log4j.Logger;
-
-/**
- * ResourceFactoryImpl implements a simple DavLocatorFactory
- *
- * @todo improve special handling of root item....
- */
-public class LocatorFactoryImpl implements DavLocatorFactory {
-
- /** the default logger */
- private static final Logger log = Logger.getLogger(LocatorFactoryImpl.class);
-
- private final String repositoryPrefix;
-
- public LocatorFactoryImpl(String repositoryPrefix) {
- this.repositoryPrefix = repositoryPrefix;
- }
-
- public DavResourceLocator createResourceLocator(String prefix, String requestHandle) {
- String rPrefix = prefix + repositoryPrefix;
- String rHandle = requestHandle;
- // remove the configured repository prefix from the path
- if (rHandle != null && rHandle.startsWith(repositoryPrefix)) {
- rHandle = rHandle.substring(repositoryPrefix.length());
- }
- // special treatment for root item, that has no name but '/' path.
- if (rHandle == null || "".equals(rHandle)) {
- rHandle = "/";
- }
- return new Locator(rPrefix, rHandle, this);
- }
-
- public DavResourceLocator createResourceLocator(String prefix, String workspacePath, String resourcePath) {
- return new Locator(prefix, resourcePath, this);
- }
-
- private class Locator implements DavResourceLocator {
-
- private final String prefix;
- private final String itemPath;
- private final DavLocatorFactory factory;
-
- private Locator(String prefix, String itemPath, DavLocatorFactory factory) {
- this.prefix = prefix;
- this.factory = factory;
- // remove trailing '/' that is not part of the itemPath except for the root item.
- if (itemPath.endsWith("/") && !"/".equals(itemPath)) {
- itemPath = itemPath.substring(0, itemPath.length()-1);
- }
- this.itemPath = itemPath;
- }
-
- public String getPrefix() {
- return prefix;
- }
-
- public String getResourcePath() {
- return itemPath;
- }
-
- public String getWorkspacePath() {
- return "";
- }
-
- public String getWorkspaceName() {
- return "";
- }
-
- public boolean isSameWorkspace(DavResourceLocator path) {
- return isSameWorkspace(path.getWorkspaceName());
- }
-
- public boolean isSameWorkspace(String workspaceName) {
- return getWorkspaceName().equals(workspaceName);
- }
-
- public String getHref(boolean isCollection) {
- // avoid doubled trainling '/' for the root item
- String suffix = (isCollection && !isRootLocation()) ? "/" : "";
- return prefix + itemPath + suffix;
- }
-
- public boolean isRootLocation() {
- return "/".equals(itemPath);
- }
-
- public DavLocatorFactory getFactory() {
- return factory;
- }
-
- /**
- * Computes the hash code using the prefix and the itemPath
- *
- * @return the hash code
- */
- public int hashCode() {
- int hashCode = prefix.hashCode();
- if (itemPath != null) {
- hashCode += itemPath.hashCode();
- }
- return hashCode % Integer.MAX_VALUE;
- }
-
- /**
- * Equality of path is achieved if the specified object is a DavResourceLocator
- * and the return values of the two getHref(boolean) methods are
- * equal.
- *
- * @param obj the object to compare to
- * @return true if the 2 objects are equal;
- * false otherwise
- */
- public boolean equals(Object obj) {
- if (obj instanceof DavResourceLocator) {
- DavResourceLocator path = (DavResourceLocator) obj;
- this.getHref(true).equals(path.getHref(true));
- }
- return false;
- }
- }
-}
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/dav/NodeResource.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/dav/NodeResource.java
deleted file mode 100644
index c5bcaf0c017..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/dav/NodeResource.java
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.server.simple.dav;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.util.Text;
-
-import javax.jcr.*;
-import java.util.Date;
-import java.util.Locale;
-import java.io.*;
-import java.text.SimpleDateFormat;
-
-/**
- * The NodeResource class wraps a jcr item in order to respond
- * to 'GET', 'HEAD', 'PROPFIND' or 'PROPPATCH' requests. If the item is a
- * {@link javax.jcr.Node} its primary property is determined. The value of the
- * primary property can be accessed by {@link #getStream()}. If possible other
- * required information (last modification date, content type...) is retrieved
- * from the property siblings.
- * If the requested item is a {@link javax.jcr.Property} it is treated accordingly.
- */
-public class NodeResource {
-
- /** the default logger */
- private static final Logger log = Logger.getLogger(NodeResource.class);
-
- /**
- * modificationDate date format per RFC 1123
- */
- public static SimpleDateFormat modificationDateFormat =
- new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
-
- /**
- * Simple date format for the creation date ISO representation (partial).
- */
- public static SimpleDateFormat creationDateFormat =
- new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
-
- private static final String PROP_MIMETYPE = "jcr:mimeType";
- private static final String PROP_ENCODING = "jcr:encoding";
- private static final String PROP_LASTMODIFIED = "jcr:lastModified";
- private static final String PROP_CREATED = "jcr:created";
-
- private long creationTime = 0;
- private long modificationTime = new Date().getTime();
- private long contentLength = 0;
- private String contentType = null;
- private InputStream in = null;
-
- /**
- * Create a new NodeResource that wraps a JSR170 item.
- *
- * @throws ItemNotFoundException
- * @throws RepositoryException
- * @throws IllegalArgumentException if the given item is null
- */
- public NodeResource(DavResourceImpl davResource, Node node) throws ItemNotFoundException, RepositoryException {
- try {
- if (davResource.isCollection()) {
- createDirListingContent(node);
- } else {
- if (node.hasProperty(PROP_CREATED)) {
- creationTime = node.getProperty(PROP_CREATED).getValue().getLong();
- }
- Node content = node.getPrimaryNodeType().getName().equals("nt:file")
- ? node.getNode("jcr:content")
- : node;
- if (content.getPrimaryNodeType().getName().equals("nt:resource")) {
- createPlainFileContent(content);
- } else {
- createDocViewContent(content);
- }
- }
- } catch (IOException e) {
- // ignore
- }
- }
-
- private void createPlainFileContent(Node content) throws IOException, RepositoryException {
- if (content.hasProperty(PROP_LASTMODIFIED)) {
- modificationTime = content.getProperty(PROP_LASTMODIFIED).getLong();
- }
- if (content.hasProperty(PROP_MIMETYPE)) {
- contentType = content.getProperty(PROP_MIMETYPE).getString();
- }
- if (content.hasProperty(PROP_ENCODING)) {
- String encoding = content.getProperty(PROP_ENCODING).getString();
- if (!encoding.equals("")) {
- contentType+="; charset=\"" + encoding + "\"";
- }
- }
- if (content.hasProperty("jcr:data")) {
- Property p = content.getProperty("jcr:data");
- contentLength = p.getLength();
- in = p.getStream();
- } else {
- contentLength = 0;
- }
- }
-
- private void createDocViewContent(Node node) throws IOException, RepositoryException {
- File tmpfile = File.createTempFile("__webdav", ".xml");
- FileOutputStream out = new FileOutputStream(tmpfile);
- node.getSession().exportDocView(node.getPath(), out, true, false);
- out.close();
- in = new FileInputStream(tmpfile);
- contentLength = tmpfile.length();
- modificationTime = tmpfile.lastModified();
- contentType = "text/xml";
- tmpfile.deleteOnExit();
- }
-
- private void createSysViewContent(Node node) throws IOException, RepositoryException {
- File tmpfile = File.createTempFile("__webdav", ".xml");
- FileOutputStream out = new FileOutputStream(tmpfile);
- node.getSession().exportSysView(node.getPath(), out, true, false);
- out.close();
- in = new FileInputStream(tmpfile);
- contentLength = tmpfile.length();
- modificationTime = tmpfile.lastModified();
- contentType = "text/xml";
- tmpfile.deleteOnExit();
- }
-
- private void createDirListingContent(Node node) throws IOException, RepositoryException {
- File tmpfile = File.createTempFile("__webdav", ".xml");
- FileOutputStream out = new FileOutputStream(tmpfile);
-
- String repName = node.getSession().getRepository().getDescriptor(Repository.REP_NAME_DESC);
- String repURL = node.getSession().getRepository().getDescriptor(Repository.REP_VENDOR_URL_DESC);
- String repVersion = node.getSession().getRepository().getDescriptor(Repository.REP_VERSION_DESC);
- PrintWriter writer = new PrintWriter(out);
- writer.print("");
- writer.print(repName);
- writer.print(" ");
- writer.print(repVersion);
- writer.print(" ");
- writer.print(node.getPath());
- writer.print("");
- writer.print("
Powered by ");
- writer.print(repName);
- writer.print(" version ");
- writer.print(repVersion);
- writer.print("");
-
- writer.close();
- out.close();
- in = new FileInputStream(tmpfile);
- contentLength = tmpfile.length();
- modificationTime = tmpfile.lastModified();
- contentType = "text/html";
- tmpfile.deleteOnExit();
- }
-
- /**
- * Return the content length or '0'.
- * @return content Length or '0' if it could not be determined.
- */
- public long getContentLength() {
- return contentLength;
- }
-
- /**
- * Return the creation time or '0'.
- *
- * @return creation time or '0' if it could not be determined.
- */
- public long getCreationTime() {
- return creationTime;
- }
-
- /**
- * Return the last modification time. By default it is set to the current
- * time.
- *
- * @return time of last modification or the current time, if it could not
- * be determined.
- */
- public long getModificationTime() {
- return modificationTime;
- }
-
- /**
- * Return the last modification time as formatted string.
- *
- * @return last modification time as string.
- * @see NodeResource#modificationDateFormat
- */
- public String getLastModified() {
- if (modificationTime >= 0) {
- return modificationDateFormat.format(new Date(modificationTime));
- } else {
- return null;
- }
- }
-
- /**
- * Return the creation time as formatted string.
- *
- * @return creation time as string.
- * @see NodeResource#creationDateFormat
- */
- public String getCreationDate() {
- if (creationTime >= 0) {
- return creationDateFormat.format(new Date(creationTime));
- } else {
- return null;
- }
- }
-
- /**
- * Return the weak ETag
- *
- * @return weak ETag
- */
- public String getETag() {
- return "W/\"" + this.contentLength + "-" + this.modificationTime + "\"";
- }
-
- /**
- * Return the strong ETag or empty string if it cannot be determined.
- *
- * @return strong ETag
- */
- public String getStrongETag() {
- return "";
- }
-
- /**
- * Return the content type or null if it could not be determined.
- *
- * @return content type
- */
- public String getContentType() {
- return contentType;
- }
-
- /**
- * Return a stream to the resource value.
- *
- * @return
- */
- public InputStream getStream() {
- return in;
- }
-}
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/dav/ResourceFactoryImpl.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/dav/ResourceFactoryImpl.java
deleted file mode 100644
index e7cdb6d6d15..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/dav/ResourceFactoryImpl.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.server.simple.dav;
-
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.lock.LockManager;
-
-/**
- * ResourceFactoryImpl implements a simple DavResourceFactory
- */
-public class ResourceFactoryImpl implements DavResourceFactory {
-
- private final LockManager lockMgr;
-
- public ResourceFactoryImpl(LockManager lockMgr) {
- this.lockMgr = lockMgr;
- }
-
- public DavResource createResource(DavResourceLocator locator, DavServletRequest request,
- DavServletResponse response) throws DavException {
- return createResource(locator, request.getDavSession());
- }
-
- public DavResource createResource(DavResourceLocator locator, DavSession session) throws DavException {
- DavResource res = new DavResourceImpl(locator, this, session);
- res.addLockManager(lockMgr);
- return res;
- }
-}
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/dav/lock/SimpleLockManager.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/dav/lock/SimpleLockManager.java
deleted file mode 100644
index 02232ca1a4b..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/server/simple/dav/lock/SimpleLockManager.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.server.simple.dav.lock;
-
-import java.util.HashMap;
-import java.util.Iterator;
-
-import org.apache.jackrabbit.webdav.lock.*;
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.util.Text;
-
-/**
- * Simple manager for webdav locks.
- * NOTE: the timeout requested is always replace by a infinite timeout and
- * expiration of locks is not checked.
- */
-public class SimpleLockManager implements LockManager {
-
- /** map of locks */
- private HashMap locks = new HashMap();
-
- /**
- *
- * @param lockToken
- * @param resource
- * @return
- * @see LockManager#hasLock(String, org.apache.jackrabbit.webdav.DavResource)
- */
- public boolean hasLock(String lockToken, DavResource resource) {
- ActiveLock lock = (ActiveLock) locks.get(resource.getResourcePath());
- if (lock != null && lock.getToken().equals(lockToken)) {
- return true;
- }
- return false;
- }
-
- /**
- * Returns the lock applying to the given resource or null if
- * no lock can be found.
- *
- * @param type
- * @param scope
- * @param resource
- * @return lock that applies to the given resource or null.
- */
- public ActiveLock getLock(Type type, Scope scope, DavResource resource) {
- if (!(Type.WRITE.equals(type) && Scope.EXCLUSIVE.equals(scope))) {
- return null;
- }
- String key = resource.getResourcePath();
- ActiveLock lock = (locks.containsKey(key)) ? (ActiveLock)locks.get(key) : null;
-
- // look for an inherited lock
- if (lock == null) {
- // cut path instead of retrieving the parent resource
- String parentPath = Text.getRelativeParent(key, 1);
- boolean found = false;
- /* stop as soon as parent lock is found:
- if the lock is deep or the parent is a collection the lock
- applies to the given resource. */
- while (!"/".equals(parentPath) && !(found = locks.containsKey(parentPath))) {
- parentPath = Text.getRelativeParent(parentPath, 1);
- }
- if (found) {
- ActiveLock parentLock = (ActiveLock)locks.get(parentPath);
- if (parentLock.isDeep()) {
- lock = parentLock;
- }
- }
- }
- // since locks have infinite timeout, check for expired lock is omitted.
- return lock;
- }
-
- /**
- * Adds the lock for the given resource, replacing any existing lock.
- *
- * @param lockInfo
- * @param resource being the lock holder
- */
- public synchronized ActiveLock createLock(LockInfo lockInfo, DavResource resource)
- throws DavException {
- if (lockInfo == null || resource == null) {
- throw new IllegalArgumentException("Neither lockInfo nor resource must be null.");
- }
-
- String resourcePath = resource.getResourcePath();
- // test if there is already a lock present on this resource
- if (locks.containsKey(resourcePath)) {
- throw new DavException(DavServletResponse.SC_LOCKED, "Resource '" + resource.getResourcePath() + "' already holds a lock.");
- }
- // test if the new lock would conflict with any lock inherited from the
- // collection or with a lock present on any member resource.
- Iterator it = locks.keySet().iterator();
- while (it.hasNext()) {
- String key = (String) it.next();
- // TODO: is check for lock on internal-member correct?
- if (Text.isDescendant(key, resourcePath)) {
- ActiveLock l = (ActiveLock) locks.get(key);
- if (l.isDeep() || (key.equals(Text.getRelativeParent(resourcePath, 1)) && !resource.isCollection())) {
- throw new DavException(DavServletResponse.SC_LOCKED, "Resource '" + resource.getResourcePath() + "' already inherits a lock by its collection.");
- }
- } else if (Text.isDescendant(resourcePath, key)) {
- if (lockInfo.isDeep() || isInternalMember(resource, key)) {
- throw new DavException(DavServletResponse.SC_LOCKED, "Resource '" + resource.getResourcePath() + "' cannot be locked due to a lock present on a member resource '" + key + "'.");
- }
-
- }
- }
- ActiveLock lock = new DefaultActiveLock(lockInfo);
- // Lazy: reset the timeout to 'Infinite', in order to omit the tests for
- // lock expiration.
- lock.setTimeout(DavConstants.INFINITE_TIMEOUT);
- locks.put(resource.getResourcePath(), lock);
- return lock;
- }
-
- /**
- *
- * @param lockInfo
- * @param lockToken
- * @param resource
- * @return
- * @throws DavException
- * @see DavResource#refreshLock(org.apache.jackrabbit.webdav.lock.LockInfo, String)
- */
- public ActiveLock refreshLock(LockInfo lockInfo, String lockToken, DavResource resource)
- throws DavException {
- // timeout is always infinite > no test for expiration or adjusting timeout needed.
- ActiveLock lock = (ActiveLock)locks.get(resource.getResourcePath());
- if (lock == null) {
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED);
- } else if (!lock.getToken().equals(lockToken)) {
- throw new DavException(DavServletResponse.SC_LOCKED);
- }
- return lock;
- }
-
- /**
- * Remove the lock hold by the given resource.
- *
- * @param lockToken
- * @param resource that is the lock holder
- */
- public synchronized void releaseLock(String lockToken, DavResource resource)
- throws DavException {
- if (!locks.containsKey(resource.getResourcePath())) {
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED);
- }
- // since locks have infinite timeout, check for expiration is omitted.
-
- ActiveLock lock = (ActiveLock) locks.get(resource.getResourcePath());
- if (lock.getToken().equals(lockToken)) {
- locks.remove(resource.getResourcePath());
- } else {
- throw new DavException(DavServletResponse.SC_LOCKED);
- }
- }
-
- /**
- * Return true, if the resource with the given memberPath is a internal
- * non-collection member of the given resource, thus affected by a
- * non-deep lock present on the resource.
- *
- * @param resource
- * @param memberPath
- * @return
- */
- private static boolean isInternalMember(DavResource resource, String memberPath) {
- if (resource.getResourcePath().equals(Text.getRelativeParent(memberPath, 1))) {
- // find the member with the given path
- DavResourceIterator it = resource.getMembers();
- while (it.hasNext()) {
- DavResource member = it.nextResource();
- if (member.getResourcePath().equals(memberPath)) {
- // return true if that member is not a collection
- return !member.isCollection();
- }
- }
- }
- return false;
- }
-}
-
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/AbstractItemResource.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/AbstractItemResource.java
deleted file mode 100644
index c6201ccb9c2..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/AbstractItemResource.java
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.property.*;
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.spi.search.SearchResourceImpl;
-import org.apache.jackrabbit.webdav.spi.version.report.NodeTypesReport;
-import org.apache.jackrabbit.webdav.spi.version.report.ExportViewReport;
-import org.apache.jackrabbit.webdav.spi.version.report.LocateByUuidReport;
-import org.apache.jackrabbit.webdav.spi.version.report.RegisteredNamespacesReport;
-import org.apache.jackrabbit.webdav.DavResource;
-import org.apache.jackrabbit.webdav.transaction.TxLockEntry;
-import org.apache.jackrabbit.webdav.version.report.SupportedReportSetProperty;
-import org.apache.jackrabbit.webdav.version.report.ReportType;
-import org.apache.jackrabbit.webdav.search.*;
-import org.apache.jackrabbit.webdav.util.Text;
-
-import javax.jcr.*;
-
-/**
- * AbstractItemResource covers common functionality for the various
- * resources, that represent a repository item.
- */
-abstract class AbstractItemResource extends AbstractResource implements
- SearchResource, ItemResourceConstants {
-
- private static Logger log = Logger.getLogger(AbstractItemResource.class);
-
- protected final Item item;
-
- /**
- * Create a new AbstractItemResource.
- *
- * @param locator
- * @param session
- */
- AbstractItemResource(DavResourceLocator locator, DavSession session, DavResourceFactory factory) {
- super(locator, session, factory);
- Item repositoryItem = null;
- if (locator != null) {
- try {
- repositoryItem = getRepositorySession().getItem(locator.getResourcePath());
- } catch (RepositoryException e) {
- // ignore: exists field evaluates to false
- log.info(e.getMessage());
- }
- }
- item = repositoryItem;
- }
-
- //----------------------------------------------< DavResource interface >---
- /**
- * @see org.apache.jackrabbit.webdav.DavResource#getComplianceClass()
- */
- public String getComplianceClass() {
- return ItemResourceConstants.COMPLIANCE_CLASS;
- }
-
- /**
- * @see org.apache.jackrabbit.webdav.DavResource#getSupportedMethods()
- */
- public String getSupportedMethods() {
- return ItemResourceConstants.METHODS;
- }
-
- /**
- * Returns true if there exists a {@link Item repository item} with the given
- * resource path, false otherwise.
- *
- * @see DavResource#exists()
- */
- public boolean exists() {
- return item != null;
- }
-
- /**
- * @see DavResource#getDisplayName() )
- */
- public String getDisplayName() {
- String name = null;
- if (exists()) {
- try {
- name = item.getName();
- } catch (RepositoryException e) {
- // ignore: should not occure
- log.warn(e.getMessage());
- }
- }
- String resPath = getResourcePath();
- if (name == null && resPath != null) {
- int pos = resPath.lastIndexOf('/');
- if (pos>=0) {
- name = resPath.substring(pos+1);
- } else {
- name = resPath;
- }
- // note: since index info is present only with existing resources
- // there is no need to check for any '[index]' suffix.
- }
- return name;
- }
-
- /**
- * Returns the resource representing the parent item of the repository item
- * represented by this resource. If this resoure represents the root item
- * a {@link RootCollection} is returned.
- *
- * @return the collection this resource is internal member of. Except for the
- * repository root, the returned collection always represent the parent
- * repository node.
- * @see DavResource#getCollection()
- */
- public DavResource getCollection() {
- DavResource collection = null;
-
- String resourcePath = getResourcePath();
- // No special treatment for the root-item needed, because this is
- // covered by the RootItemCollection itself.
- String parentResourcePath = Text.getRelativeParent(resourcePath, 1);
- String parentWorkspacePath = getLocator().getWorkspacePath();
-
- DavResourceLocator parentLoc = getLocator().getFactory().createResourceLocator(getLocator().getPrefix(), parentWorkspacePath, parentResourcePath);
- try {
- collection = createResourceFromLocator(parentLoc);
- } catch (DavException e) {
- log.error("Unexpected error while retrieving collection: " + e.getMessage());
- }
-
- return collection;
- }
-
- /**
- * Moves the underlaying repository item to the indicated destination.
- *
- * @param destination
- * @throws DavException
- * @see DavResource#move(DavResource)
- * @see Session#move(String, String)
- */
- public void move(DavResource destination) throws DavException {
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
- DavResourceLocator destPath = destination.getLocator();
- if (!getLocator().isSameWorkspace(destPath)) {
- throw new DavException(DavServletResponse.SC_FORBIDDEN);
- }
-
- try {
- getRepositorySession().move(getResourcePath(), destination.getResourcePath());
- complete();
-
- } catch (PathNotFoundException e) {
- // according to rfc 2518
- throw new DavException(DavServletResponse.SC_CONFLICT, e.getMessage());
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- }
-
- /**
- * Copies the underlaying repository item to the indicated destination. If
- * the locator of the specified destination resource indicates a different
- * workspace, {@link Workspace#copy(String, String, String)} is used to perform
- * the copy operation, {@link Workspace#copy(String, String)} otherwise.
- *
- * Note, that this implementation does not support shallow copy.
- *
- * @param destination
- * @param shallow
- * @throws DavException
- * @see DavResource#copy(DavResource, boolean)
- * @see Workspace#copy(String, String)
- * @see Workspace#copy(String, String, String)
- */
- public void copy(DavResource destination, boolean shallow) throws DavException {
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
- // TODO: support shallow and deep copy is required by RFC 2518
- if (shallow) {
- throw new DavException(DavServletResponse.SC_FORBIDDEN, "Unable to perform shallow copy.");
- }
-
- if (!(destination instanceof AbstractItemResource)) {
- throw new DavException(DavServletResponse.SC_FORBIDDEN, "Cannot copy a resource that does not represent a repository item.");
- }
-
- try {
- AbstractItemResource destResource = (AbstractItemResource) destination;
- String destResourcePath = destResource.getResourcePath();
- Workspace workspace = getRepositorySession().getWorkspace();
- if (getLocator().isSameWorkspace(destination.getLocator())) {
- workspace.copy(getResourcePath(), destResourcePath);
- } else {
- Workspace destWorkspace = destResource.getRepositorySession().getWorkspace();
- destWorkspace.copy(workspace.getName(), getResourcePath(), destResourcePath);
- }
- } catch (PathNotFoundException e) {
- // according to RFC 2518, should not occur
- throw new DavException(DavServletResponse.SC_NOT_FOUND, e.getMessage());
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- }
-
- //-------------------------------------------< SearchResource interface >---
- /**
- * @return
- * @see org.apache.jackrabbit.webdav.search.SearchResource#getQueryGrammerSet()
- */
- public QueryGrammerSet getQueryGrammerSet() {
- return new SearchResourceImpl(getLocator(), getSession()).getQueryGrammerSet();
- }
-
- /**
- * @param sRequest
- * @return
- * @throws DavException
- * @see SearchResource#search(org.apache.jackrabbit.webdav.search.SearchRequest)
- */
- public MultiStatus search(SearchRequest sRequest) throws DavException {
- return new SearchResourceImpl(getLocator(), getSession()).search(sRequest);
- }
-
- //--------------------------------------------------------------------------
- /**
- * Initialize the {@link org.apache.jackrabbit.webdav.lock.SupportedLock} property
- * with entries that are valid for any type item resources.
- *
- * @see org.apache.jackrabbit.webdav.lock.SupportedLock
- * @see org.apache.jackrabbit.webdav.transaction.TxLockEntry
- * @see AbstractResource#initLockSupport()
- */
- protected void initLockSupport() {
- if (exists()) {
- // add supportedlock entries for local and eventually for global transaction locks
- supportedLock.addEntry(new TxLockEntry(true));
- supportedLock.addEntry(new TxLockEntry(false));
- }
- }
-
- /**
- * Define the set of reports supported by this resource.
- *
- * @see org.apache.jackrabbit.webdav.version.report.SupportedReportSetProperty
- * @see AbstractResource#initSupportedReports()
- */
- protected void initSupportedReports() {
- if (exists()) {
- supportedReports = new SupportedReportSetProperty(new ReportType[] {
- ReportType.EXPAND_PROPERTY,
- NodeTypesReport.NODETYPES_REPORT,
- ExportViewReport.EXPORTVIEW_REPORT,
- LocateByUuidReport.LOCATE_BY_UUID_REPORT,
- RegisteredNamespacesReport.REGISTERED_NAMESPACES_REPORT
- });
- }
- }
-
- /**
- * Fill the property set for this resource.
- */
- protected void initProperties() {
- super.initProperties();
- if (exists()) {
- try {
- properties.add(new DefaultDavProperty(JCR_NAME, item.getName()));
- properties.add(new DefaultDavProperty(JCR_PATH, item.getPath()));
- properties.add(new DefaultDavProperty(JCR_DEPTH, String.valueOf(item.getDepth())));
- } catch (RepositoryException e) {
- log.error("Error while accessing jcr properties: " + e.getMessage());
- }
-
- // transaction resource additional protected properties
- if (item.isNew()) {
- properties.add(new DefaultDavProperty(JCR_ISNEW, null, true));
- } else if (item.isModified()) {
- properties.add(new DefaultDavProperty(JCR_ISMODIFIED, null, true));
- }
- }
- }
-
- /**
- * @return href of the workspace or null if this resource
- * does not represent a repository item.
- *
- * @see AbstractResource#getWorkspaceHref()
- */
- protected String getWorkspaceHref() {
- String workspaceHref = null;
- DavResourceLocator locator = getLocator();
- if (locator != null && locator.getWorkspaceName() != null) {
- workspaceHref = locator.getHref(isCollection());
- if (locator.getResourcePath() != null) {
- workspaceHref = workspaceHref.substring(workspaceHref.indexOf(locator.getResourcePath()));
- }
- }
- log.info(workspaceHref);
- return workspaceHref;
- }
-
- /**
- * If this resource exists but does not contain a transaction id, complete
- * will try to persist any modifications prsent on the underlaying repository
- * item.
- *
- * @throws DavException if calling {@link Item#save()} fails
- */
- void complete() throws DavException {
- if (exists() && getTransactionId() == null) {
- try {
- if (item.isModified()) {
- item.save();
- }
- } catch (RepositoryException e) {
- // this includes LockException, ConstraintViolationException etc. not detected before
- log.error("Error while completing request: " + e.getMessage() +" -> reverting changes.");
- try {
- item.refresh(false);
- } catch (RepositoryException re) {
- log.error("Error while reverting changes: " + re.getMessage());
- }
- throw new JcrDavException(e);
- }
- }
- }
-
- /**
- * Build a new {@link DavResourceLocator} from the given repository item.
- *
- * @param repositoryItem
- * @return a new locator for the specified item.
- * @see #getLocatorFromResourcePath(String)
- */
- protected DavResourceLocator getLocatorFromItem(Item repositoryItem) {
- String itemPath = null;
- try {
- if (repositoryItem != null) {
- itemPath = repositoryItem.getPath();
- }
- } catch (RepositoryException e) {
- // ignore: should not occur
- log.warn(e.getMessage());
- }
- return getLocatorFromResourcePath(itemPath);
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/AbstractResource.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/AbstractResource.java
deleted file mode 100644
index 903a4811ebd..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/AbstractResource.java
+++ /dev/null
@@ -1,648 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.transaction.TransactionResource;
-import org.apache.jackrabbit.webdav.transaction.TransactionInfo;
-import org.apache.jackrabbit.webdav.transaction.TransactionConstants;
-import org.apache.jackrabbit.webdav.transaction.TxLockManager;
-import org.apache.jackrabbit.webdav.spi.transaction.TxLockManagerImpl;
-import org.apache.jackrabbit.webdav.observation.*;
-import org.apache.jackrabbit.webdav.util.Text;
-import org.apache.jackrabbit.webdav.version.*;
-import org.apache.jackrabbit.webdav.version.report.Report;
-import org.apache.jackrabbit.webdav.version.report.ReportInfo;
-import org.apache.jackrabbit.webdav.version.report.ReportType;
-import org.apache.jackrabbit.webdav.version.report.SupportedReportSetProperty;
-import org.apache.jackrabbit.webdav.lock.*;
-import org.apache.jackrabbit.webdav.property.*;
-import org.apache.jackrabbit.webdav.property.ResourceType;
-
-import javax.jcr.Session;
-import java.io.InputStream;
-import java.util.*;
-
-/**
- * AbstractResource provides functionality common to all
- * resources.
- */
-abstract class AbstractResource implements DavResource, ObservationResource,
- TransactionResource, DeltaVResource {
-
- private static Logger log = Logger.getLogger(AbstractResource.class);
-
- private final DavResourceLocator locator;
- private final DavSession session;
- private final DavResourceFactory factory;
-
- private SubscriptionManager subsMgr;
- private TxLockManagerImpl txMgr;
- private String transactionId;
-
- private long modificationTime = DavResource.UNDEFINED_MODIFICATIONTIME;
-
- protected boolean initedProps;
- protected DavPropertySet properties = new DavPropertySet();
- protected SupportedLock supportedLock = new SupportedLock();
- protected SupportedReportSetProperty supportedReports = new SupportedReportSetProperty();
-
- /**
- * Create a new AbstractResource
- *
- * @param locator
- * @param session
- */
- AbstractResource(DavResourceLocator locator, DavSession session, DavResourceFactory factory) {
- if (session == null) {
- throw new IllegalArgumentException("Creating AbstractItemResource: DavSession must not be null.");
- }
-
- this.locator = locator;
- this.session = session;
- this.factory = factory;
-
- // initialize the supported locks and reports
- initLockSupport();
- initSupportedReports();
- }
-
- /**
- * @see org.apache.jackrabbit.webdav.DavResource#getLocator()
- */
- public DavResourceLocator getLocator() {
- return locator;
- }
-
- /**
- * Returns the path of the underlaying repository item or the item to
- * be created (PUT/MKCOL). If the resource exists but does not represent
- * a repository item null is returned.
- *
- * @return path of the underlaying repository item.
- * @see DavResource#getResourcePath()
- * @see org.apache.jackrabbit.webdav.DavResourceLocator#getResourcePath()
- */
- public String getResourcePath() {
- return locator.getResourcePath();
- }
-
- /**
- * @see DavResource#getHref()
- * @see DavResourceLocator#getHref(boolean)
- */
- public String getHref() {
- return locator.getHref(true);
- }
-
- /**
- * @see org.apache.jackrabbit.webdav.DavResource#getModificationTime()
- */
- public long getModificationTime() {
- return modificationTime;
- }
-
- /**
- * Set the modificationTime field and adds the {@link DavPropertyName.GETLASTMODIFIED}
- * property to the set of properties.
- * @param modificationTime
- */
- void setModificationTime(long modificationTime) {
- this.modificationTime = modificationTime;
- if (this.modificationTime >= 0) {
- properties.add(new DefaultDavProperty(DavPropertyName.GETLASTMODIFIED,
- DavConstants.modificationDateFormat.format(new Date(modificationTime))));
- }
- }
-
- /**
- * Returns null
- *
- * @return Always returns null
- * @see org.apache.jackrabbit.webdav.DavResource#getStream()
- */
- public InputStream getStream() {
- return null;
- }
-
- /**
- * @see org.apache.jackrabbit.webdav.DavResource#getPropertyNames()
- */
- public DavPropertyName[] getPropertyNames() {
- return getProperties().getPropertyNames();
- }
-
- /**
- * @see org.apache.jackrabbit.webdav.DavResource#getProperty(org.apache.jackrabbit.webdav.property.DavPropertyName)
- */
- public DavProperty getProperty(DavPropertyName name) {
- return getProperties().get(name);
- }
-
- /**
- * @see org.apache.jackrabbit.webdav.DavResource#getProperties()
- */
- public DavPropertySet getProperties() {
- if (!initedProps) {
- initProperties();
- }
- return properties;
- }
-
- /**
- * Throws {@link DavServletResponse#SC_METHOD_NOT_ALLOWED}
- *
- * @param property
- * @throws DavException Always throws {@link DavServletResponse#SC_METHOD_NOT_ALLOWED}
- * @see org.apache.jackrabbit.webdav.DavResource#setProperty(org.apache.jackrabbit.webdav.property.DavProperty)
- */
- public void setProperty(DavProperty property) throws DavException {
- throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- }
-
- /**
- * Throws {@link DavServletResponse#SC_METHOD_NOT_ALLOWED}
- *
- * @param propertyName
- * @throws DavException Always throws {@link DavServletResponse#SC_METHOD_NOT_ALLOWED}
- * @see org.apache.jackrabbit.webdav.DavResource#removeProperty(org.apache.jackrabbit.webdav.property.DavPropertyName)
- */
- public void removeProperty(DavPropertyName propertyName) throws DavException {
- throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- }
-
- /**
- * Throws {@link DavServletResponse#SC_METHOD_NOT_ALLOWED}
- *
- * @param destination
- * @throws DavException Always throws {@link DavServletResponse#SC_METHOD_NOT_ALLOWED}
- * @see DavResource#move(org.apache.jackrabbit.webdav.DavResource)
- */
- public void move(DavResource destination) throws DavException {
- throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- }
-
- /**
- * Throws {@link DavServletResponse#SC_METHOD_NOT_ALLOWED}
- *
- * @param destination
- * @param shallow
- * @throws DavException Always throws {@link DavServletResponse#SC_METHOD_NOT_ALLOWED}
- * @see DavResource#copy(org.apache.jackrabbit.webdav.DavResource, boolean)
- */
- public void copy(DavResource destination, boolean shallow) throws DavException {
- throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- }
-
-
- /**
- * Returns true, if the {@link SupportedLock} property contains an entry
- * with the given type and scope. By default resources allow for {@link org.apache.jackrabbit.webdav.transaction.TransactionConstants.XML_TRANSACTION
- * transaction} lock only.
- *
- * @param type
- * @param scope
- * @return true if this resource may be locked by the given type and scope.
- * @see DavResource#isLockable(org.apache.jackrabbit.webdav.lock.Type, org.apache.jackrabbit.webdav.lock.Scope)
- */
- public boolean isLockable(Type type, Scope scope) {
- return supportedLock.isSupportedLock(type, scope);
- }
-
- /**
- * Returns true if this resource has a lock applied with the given type and scope.
- *
- * @param type
- * @param scope
- * @return true if this resource has a lock applied with the given type and scope.
- * @see DavResource#hasLock(Type, Scope)
- */
- public boolean hasLock(Type type, Scope scope) {
- return getLock(type, scope) != null;
- }
-
- /**
- * @see DavResource#getLock(Type, Scope)
- */
- public ActiveLock getLock(Type type, Scope scope) {
- ActiveLock lock = null;
- if (TransactionConstants.TRANSACTION.equals(type)) {
- lock = txMgr.getLock(type, scope, this);
- }
- return lock;
- }
-
- /**
- * @see DavResource#getLocks()
- * todo improve....
- */
- public ActiveLock[] getLocks() {
- List locks = new ArrayList();
- // tx locks
- ActiveLock l = getLock(TransactionConstants.TRANSACTION, TransactionConstants.LOCAL);
- if (l != null) {
- locks.add(l);
- }
- l = getLock(TransactionConstants.TRANSACTION, TransactionConstants.GLOBAL);
- if (l != null) {
- locks.add(l);
- }
- // write lock (either exclusive or session-scoped).
- l = getLock(Type.WRITE, Scope.EXCLUSIVE);
- if (l != null) {
- locks.add(l);
- } else {
- l = getLock(Type.WRITE, ItemResourceConstants.EXCLUSIVE_SESSION);
- if (l != null) {
- locks.add(l);
- }
- }
- return (ActiveLock[]) locks.toArray(new ActiveLock[locks.size()]);
- }
-
- /**
- * @see DavResource#lock(org.apache.jackrabbit.webdav.lock.LockInfo)
- */
- public ActiveLock lock(LockInfo reqLockInfo) throws DavException {
- if (isLockable(reqLockInfo.getType(), reqLockInfo.getScope())) {
- return txMgr.createLock(reqLockInfo, this);
- } else {
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED);
- }
- }
-
- /**
- * Only transaction lock may be available on this resource.
- *
- * @param info
- * @param lockToken
- * @throws DavException
- * @see DavResource#refreshLock(org.apache.jackrabbit.webdav.lock.LockInfo, String)
- */
- public ActiveLock refreshLock(LockInfo info, String lockToken) throws DavException {
- return txMgr.refreshLock(info, lockToken, this);
- }
-
- /**
- * Throws {@link DavServletResponse#SC_METHOD_NOT_ALLOWED} since only transaction
- * locks may be present on this resource, that need to be released by calling
- * {@link TransactionResource#unlock(String, org.apache.jackrabbit.webdav.transaction.TransactionInfo)}.
- *
- * @param lockToken
- * @throws DavException Always throws {@link DavServletResponse#SC_METHOD_NOT_ALLOWED}
- */
- public void unlock(String lockToken) throws DavException {
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED);
- }
-
- /**
- * @see DavResource#addLockManager(org.apache.jackrabbit.webdav.lock.LockManager)
- */
- public void addLockManager(LockManager lockMgr) {
- if (lockMgr instanceof TxLockManagerImpl) {
- txMgr = (TxLockManagerImpl) lockMgr;
- }
- }
-
- /**
- * @see org.apache.jackrabbit.webdav.DavResource#getFactory()
- */
- public DavResourceFactory getFactory() {
- return factory;
- }
-
- //--------------------------------------------------------------------------
- /**
- * @see org.apache.jackrabbit.webdav.transaction.TransactionResource#getSession()
- * @see org.apache.jackrabbit.webdav.observation.ObservationResource#getSession()
- */
- public DavSession getSession() {
- return session;
- }
-
- //--------------------------------------< ObservationResource interface >---
- /**
- * @see ObservationResource#init(SubscriptionManager)
- */
- public void init(SubscriptionManager subsMgr) {
- this.subsMgr = subsMgr;
- }
-
- /**
- * @see ObservationResource#subscribe(org.apache.jackrabbit.webdav.observation.SubscriptionInfo, String)
- * @see SubscriptionManager#subscribe(org.apache.jackrabbit.webdav.observation.SubscriptionInfo, String, org.apache.jackrabbit.webdav.observation.ObservationResource)
- */
- public Subscription subscribe(SubscriptionInfo info, String subscriptionId)
- throws DavException {
- return subsMgr.subscribe(info, subscriptionId, this);
- }
-
- /**
- * @see ObservationResource#unsubscribe(String)
- * @see SubscriptionManager#unsubscribe(String, org.apache.jackrabbit.webdav.observation.ObservationResource)
- */
- public void unsubscribe(String subscriptionId) throws DavException {
- subsMgr.unsubscribe(subscriptionId, this);
- }
-
- /**
- * @see ObservationResource#poll(String)
- * @see SubscriptionManager#poll(String, org.apache.jackrabbit.webdav.observation.ObservationResource)
- */
- public EventDiscovery poll(String subscriptionId) throws DavException {
- return subsMgr.poll(subscriptionId, this);
- }
-
- //--------------------------------------< TransactionResource interface >---
- /**
- * @see TransactionResource#init(TxLockManager, String)
- */
- public void init(TxLockManager txMgr, String transactionId) {
- this.txMgr = (TxLockManagerImpl) txMgr;
- this.transactionId = transactionId;
- }
-
- /**
- * @see TransactionResource#unlock(String, org.apache.jackrabbit.webdav.transaction.TransactionInfo)
- */
- public void unlock(String lockToken, TransactionInfo tInfo) throws DavException {
- txMgr.releaseLock(tInfo, lockToken, this);
- }
-
- /**
- * @see TransactionResource#getTransactionId()
- */
- public String getTransactionId() {
- return transactionId;
- }
-
- //-------------------------------------------< DeltaVResource interface >---
- /**
- * @param optionsInfo
- * @return object to be used in the OPTIONS response body or null
- * @see DeltaVResource#getOptionResponse(org.apache.jackrabbit.webdav.version.OptionsInfo)
- */
- public OptionsResponse getOptionResponse(OptionsInfo optionsInfo) {
- OptionsResponse oR = null;
- if (optionsInfo != null) {
- oR = new OptionsResponse();
- // currently on DAV:version-history-collection-set and
- // DAV:workspace-collection-set is supported.
- if (optionsInfo.containsElement(DeltaVConstants.XML_VH_COLLECTION_SET, DeltaVConstants.NAMESPACE)) {
- String[] hrefs = new String[] { getLocatorFromResourcePath(ItemResourceConstants.VERSIONSTORAGE_PATH).getHref(true)};
- oR.addEntry(DeltaVConstants.XML_VH_COLLECTION_SET, DeltaVConstants.NAMESPACE, hrefs);
- } else if (optionsInfo.containsElement(DeltaVConstants.XML_WSP_COLLECTION_SET, DeltaVConstants.NAMESPACE)) {
- // workspaces cannot be created anywhere.
- oR.addEntry(DeltaVConstants.XML_WSP_COLLECTION_SET, DeltaVConstants.NAMESPACE, new String[0]);
- }
- }
- return oR;
- }
-
- /**
- * @param reportInfo
- * @return the requested report
- * @throws DavException
- * @see DeltaVResource#getReport(org.apache.jackrabbit.webdav.version.report.ReportInfo)
- */
- public Report getReport(ReportInfo reportInfo) throws DavException {
- if (reportInfo == null) {
- throw new DavException(DavServletResponse.SC_BAD_REQUEST, "A REPORT request must provide a valid XML request body.");
- }
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
-
- if (supportedReports.isSupportedReport(reportInfo)) {
- try {
- Report report = ReportType.getType(reportInfo).createReport();
- report.setInfo(reportInfo);
- report.setResource(this);
- return report;
- } catch (IllegalArgumentException e) {
- // should never occur.
- throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
- }
- } else {
- throw new DavException(DavServletResponse.SC_UNPROCESSABLE_ENTITY, "Unkown report "+ reportInfo.getReportElement().getNamespacePrefix() + reportInfo.getReportElement().getName() +"requested.");
- }
- }
-
- /**
- * The JCR api does not provide methods to create new workspaces. Calling
- * addWorkspace on this resource will always fail.
- *
- * @param workspace
- * @throws DavException Always throws.
- * @see DeltaVResource#addWorkspace(org.apache.jackrabbit.webdav.DavResource)
- */
- public void addWorkspace(DavResource workspace) throws DavException {
- throw new DavException(DavServletResponse.SC_FORBIDDEN);
- }
-
- /**
- * Return an array of DavResource objects that are referenced
- * by the property with the specified name.
- *
- * @param hrefPropertyName
- * @return array of DavResources
- * @throws DavException
- * @see DeltaVResource#getReferenceResources(org.apache.jackrabbit.webdav.property.DavPropertyName)
- */
- public DavResource[] getReferenceResources(DavPropertyName hrefPropertyName) throws DavException {
- DavProperty prop = getProperty(hrefPropertyName);
- if (prop == null || !(prop instanceof HrefProperty)) {
- throw new DavException(DavServletResponse.SC_CONFLICT, "Unknown Href-Property '"+hrefPropertyName+"' on resource "+getResourcePath());
- }
-
- List hrefs = ((HrefProperty)prop).getHrefs();
- DavResource[] refResources = new DavResource[hrefs.size()];
- Iterator hrefIter = hrefs.iterator();
- int i = 0;
- while (hrefIter.hasNext()) {
- refResources[i] = getResourceFromHref((String)hrefIter.next());
- i++;
- }
- return refResources;
- }
-
- /**
- * Retrieve the DavResource object that is represented by
- * the given href String.
- *
- * @param href
- * @return DavResource object
- */
- private DavResource getResourceFromHref(String href) throws DavException {
- // build a new locator: remove trailing prefix
- DavResourceLocator locator = getLocator();
- String prefix = locator.getPrefix();
- if (href.startsWith(prefix)) {
- href = href.substring(prefix.length());
- }
- DavResourceLocator loc = locator.getFactory().createResourceLocator(prefix, href);
-
- // create a new resource object
- DavResource res;
- if (getRepositorySession().itemExists(loc.getResourcePath())) {
- res = createResourceFromLocator(loc);
- } else {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
- return res;
- }
-
- //--------------------------------------------------------------------------
- /**
- * Fill the set of default properties
- */
- protected void initProperties() {
- if (getDisplayName() != null) {
- properties.add(new DefaultDavProperty(DavPropertyName.DISPLAYNAME, getDisplayName()));
- }
- if (isCollection()) {
- properties.add(new ResourceType(ResourceType.COLLECTION));
- // Windows XP support
- properties.add(new DefaultDavProperty(DavPropertyName.ISCOLLECTION, "1"));
- } else {
- properties.add(new ResourceType(ResourceType.DEFAULT_RESOURCE));
- // Windows XP support
- properties.add(new DefaultDavProperty(DavPropertyName.ISCOLLECTION, "0"));
- }
- // todo: add etag
-
- // default last modified
- setModificationTime(new Date().getTime());
- // default creation time
- properties.add(new DefaultDavProperty(DavPropertyName.CREATIONDATE, DavConstants.creationDateFormat.format(new Date(0))));
-
- // supported lock property
- properties.add(supportedLock);
-
- // set current lock information. If no lock is applied to this resource,
- // an empty lockdiscovery will be returned in the response.
- properties.add(new LockDiscovery(getLocks()));
-
- // observation resource
- SubscriptionDiscovery subsDiscovery = subsMgr.getSubscriptionDiscovery(this);
- properties.add(subsDiscovery);
-
- properties.add(new SupportedMethodSetProperty(getSupportedMethods().split(",\\s")));
-
- // DeltaV properties
- properties.add(supportedReports);
- // creator-displayname, comment: not value available from jcr
- properties.add(new DefaultDavProperty(DeltaVConstants.CREATOR_DISPLAYNAME, null, true));
- properties.add(new DefaultDavProperty(DeltaVConstants.COMMENT, null, true));
-
- // 'workspace' property as defined by RFC 3253
- String workspaceHref = getWorkspaceHref();
- if (workspaceHref != null) {
- properties.add(new HrefProperty(DeltaVConstants.WORKSPACE, workspaceHref, true));
- }
- // TODO: required supported-live-property-set
- }
-
- /**
- * Create a new DavResource from the given locator.
- * @param loc
- * @return new DavResource
- */
- protected DavResource createResourceFromLocator(DavResourceLocator loc)
- throws DavException {
- DavResource res = factory.createResource(loc, session);
- if (res instanceof AbstractResource) {
- ((AbstractResource)res).transactionId = this.transactionId;
- }
- return res;
- }
-
- /**
- * Build a DavResourceLocator from the given resource path.
- *
- * @param resourcePath
- * @return a new DavResourceLocator
- * @see DavLocatorFactory#createResourceLocator(String, String, String)
- */
- protected DavResourceLocator getLocatorFromResourcePath(String resourcePath) {
- DavResourceLocator loc = locator.getFactory().createResourceLocator(locator.getPrefix(), locator.getWorkspacePath(), resourcePath);
- return loc;
- }
-
- /**
- * Retrieve the name/label of a repository item from the given href by
- * splitting of the part after the last slash. If the removeIndex
- * flag is set to true, any trailing index (e.g. '[1]') will be removed.
- *
- * @param resourceHref
- * @param removeIndex
- * @return the name of the item
- */
- protected static String getResourceName(String resourceHref, boolean removeIndex) {
- if (resourceHref == null) {
- return resourceHref;
- }
-
- // cut the extension
- int pos = resourceHref.lastIndexOf('.');
- if (pos > 0) {
- resourceHref = resourceHref.substring(pos+1);
- } else if (resourceHref.endsWith("/")) {
- resourceHref = resourceHref.substring(0, resourceHref.length()-1);
- }
-
- // retrieve the last part of the path
- String name = Text.getLabel(resourceHref);
- // remove index
- if (removeIndex) {
- if (name.endsWith("]")) {
- name = name.substring(0, name.lastIndexOf('['));
- }
- }
- return name;
- }
-
- /**
- * Shortcut for getSession().getRepositorySession()
- *
- * @return repository session present in the {@link #session}.
- */
- protected Session getRepositorySession() {
- return getSession().getRepositorySession();
- }
-
- /**
- * Define the set of locks supported by this resource.
- *
- * @see org.apache.jackrabbit.webdav.lock.SupportedLock
- */
- abstract protected void initLockSupport();
-
- /**
- * Define the set of reports supported by this resource.
- *
- * @see org.apache.jackrabbit.webdav.version.report.SupportedReportSetProperty
- */
- abstract protected void initSupportedReports();
-
- /**
- * Retrieve the href of the workspace the current session belongs to.
- *
- * @return href of the workspace
- */
- abstract protected String getWorkspaceHref();
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DavLocatorFactoryImpl.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DavLocatorFactoryImpl.java
deleted file mode 100644
index c32008f6275..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DavLocatorFactoryImpl.java
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.DavResourceLocator;
-import org.apache.jackrabbit.webdav.DavLocatorFactory;
-
-/**
- * DavLocatorFactoryImpl...
- */
-public class DavLocatorFactoryImpl implements DavLocatorFactory {
-
- private static Logger log = Logger.getLogger(DavLocatorFactoryImpl.class);
-
- private final String pathPrefix;
-
- /**
- * Create a new factory
- *
- * @param pathPrefix Prefix, that needs to be removed in order to retrieve
- * the path of the repository item from a given DavResourceLocator.
- */
- public DavLocatorFactoryImpl(String pathPrefix) {
- this.pathPrefix = pathPrefix;
- }
-
- /**
- * Create a new DavResourceLocator. Any leading
- * path-prefix (as defined with the constructor) and trailing '/' with
- * the request handle is removed. The first label of the remaining handle is
- * treated as workspace name. The remaining part of the given request handle
- * is said to be the resource handle ("/" if an empty string remains).
- * If the request handle does neither provide workspace name nor resource
- * handle both values are set to null; the path object then
- * represents the root resource that has no corresponding item in the JCR
- * repository.
- *
- * @param prefix
- * @param requestHandle
- * @return a new DavResourceLocator
- * @throws IllegalArgumentException if the request handle is null
- */
- public DavResourceLocator createResourceLocator(String prefix, String requestHandle) {
- if (requestHandle == null) {
- throw new IllegalArgumentException("Request handle must not be null.");
- }
-
- StringBuffer b = new StringBuffer("");
- if (prefix != null) {
- b.append(prefix);
- if (pathPrefix != null && !prefix.endsWith(pathPrefix)) {
- b.append(pathPrefix);
- }
- }
- String rlPrefix = b.toString();
-
- // remove path-prefix defined with the servlet that may preceed the
- // the requestHandle
- if (pathPrefix != null && requestHandle.startsWith(pathPrefix)) {
- requestHandle = requestHandle.substring(pathPrefix.length());
- }
-
- // remove trailing "/" that is present with collections
- if (requestHandle.endsWith("/")) {
- requestHandle = requestHandle.substring(0, requestHandle.length()-1);
- }
-
- String resourcePath;
- String workspacePath;
-
- // an empty requestHandle (after removal of the "/") signifies a request
- // to the root that does not represent a repository item.
- if ("".equals(requestHandle)) {
- resourcePath = null;
- workspacePath = null;
- } else {
- // look for the first slash ignoring the leading one
- int pos = requestHandle.indexOf('/', 1);
- if (pos == -1) {
- // request to a 'workspace' resource that in the same time
- // represent the root node of the repository.
- workspacePath = requestHandle;
- resourcePath = ItemResourceConstants.ROOT_ITEM_PATH;
- } else {
- // separate the workspace name from the path of the repository
- // item.
- workspacePath = requestHandle.substring(0, pos);
- resourcePath = requestHandle.substring(pos);
- }
- }
-
- return new DavResourceLocatorImpl(rlPrefix, workspacePath, resourcePath, this);
- }
-
- /**
- * Create a new DavResourceLocator from the specified prefix,
- * workspace path and resource path, whithout modifying the specified Strings.
- *
- * @param prefix
- * @param workspacePath
- * @param resourcePath
- * @return a new DavResourceLocator
- * @see DavLocatorFactory#createResourceLocator(String, String, String)
- */
- public DavResourceLocator createResourceLocator(String prefix, String workspacePath, String resourcePath) {
- return new DavResourceLocatorImpl(prefix, workspacePath, resourcePath, this);
- }
-
- /**
- * Private inner class DavResourceLocatorImpl implementing
- * the DavResourceLocator interface.
- */
- private class DavResourceLocatorImpl implements DavResourceLocator {
-
- private final String prefix;
- private final String workspacePath;
- private final String resourcePath;
- private final DavLocatorFactory factory;
-
- /**
- * Create a new DavResourceLocatorImpl.
- *
- * @param prefix
- * @param workspacePath
- * @param resourcePath
- */
- DavResourceLocatorImpl(String prefix, String workspacePath, String resourcePath, DavLocatorFactory factory) {
- this.prefix = prefix;
- this.workspacePath = workspacePath;
- this.resourcePath = resourcePath;
- this.factory = factory;
- }
-
- /**
- * Return the prefix used to build the href String. This includes the initial
- * hrefPrefix as well a the path prefix.
- *
- * @return prefix String used to build the href.
- */
- public String getPrefix() {
- return prefix;
- }
-
- /**
- * Return the resource path of null if this locator object
- * represents the '/' request handle. To a request handle specifying a
- * workspace name only the '/' resource path is assigned, which represents
- * the root node of the repository.
- *
- * @return resource path or null
- * @see org.apache.jackrabbit.webdav.DavResourceLocator#getResourcePath()
- */
- public String getResourcePath() {
- return resourcePath;
- }
-
- /**
- * Return the workspace path or null if this locator object
- * represents the '/' request handle.
- *
- * @return workspace path or null
- * @see org.apache.jackrabbit.webdav.DavResourceLocator#getWorkspacePath()
- */
- public String getWorkspacePath() {
- return workspacePath;
- }
-
- /**
- * Return the workspace name or null if this locator object
- * represents the '/' request handle.
- *
- * @return workspace name or null
- * @see org.apache.jackrabbit.webdav.DavResourceLocator#getWorkspaceName()
- */
- public String getWorkspaceName() {
- if (workspacePath != null) {
- return workspacePath.substring(1);
- }
- return null;
- }
-
- /**
- * Returns true if the specified locator object refers to a resource within
- * the same workspace.
- *
- * @param locator
- * @return true if the workspace name is equal to this workspace name.
- * @see DavResourceLocator#isSameWorkspace(org.apache.jackrabbit.webdav.DavResourceLocator)
- */
- public boolean isSameWorkspace(DavResourceLocator locator) {
- return (locator == null) ? false : isSameWorkspace(locator.getWorkspaceName());
- }
-
- /**
- * Returns true if the specified string equals to this workspace name or
- * if this workspace name is null.
- *
- * @param workspaceName
- * @return true if the workspace name is equal to this workspace name.
- * @see DavResourceLocator#isSameWorkspace(String)
- */
- public boolean isSameWorkspace(String workspaceName) {
- if (getWorkspaceName() == null) {
- return true;
- } else {
- return getWorkspaceName().equals(workspaceName);
- }
- }
-
- /**
- * Builds the 'href' from the prefix, the workspace name and the
- * resource path present and assures a trailing '/' in case the href
- * is used for collection.
- *
- * @param isCollection
- * @return href String representing the text of the href element
- * @see org.apache.jackrabbit.webdav.DavConstants#XML_HREF
- * @see DavResourceLocator#getHref(boolean)
- */
- public String getHref(boolean isCollection) {
- StringBuffer href = new StringBuffer(prefix);
- if (workspacePath != null) {
- href.append(workspacePath);
- }
- if (resourcePath != null) {
- href.append(resourcePath);
- }
- if (isCollection && href.charAt(href.length()-1) != '/') {
- href.append("/");
- }
- return href.toString();
- }
-
- /**
- * Returns true if the 'workspaceName' field is null.
- *
- * @return true if the 'workspaceName' field is null.
- * @see org.apache.jackrabbit.webdav.DavResourceLocator#isRootLocation()
- */
- public boolean isRootLocation() {
- return workspacePath == null;
- }
-
- /**
- * Return the factory that created this locator.
- *
- * @return factory
- * @see org.apache.jackrabbit.webdav.DavResourceLocator#getFactory()
- */
- public DavLocatorFactory getFactory() {
- return factory;
- }
-
- /**
- * Computes the hash code using the prefix, the workspace name and the
- * resource path.
- *
- * @return the hash code
- */
- public int hashCode() {
- int hashCode = prefix.hashCode();
- if (workspacePath != null) {
- hashCode += workspacePath.hashCode();
- }
- if (resourcePath != null) {
- hashCode += resourcePath.hashCode();
- }
- return hashCode % Integer.MAX_VALUE;
- }
-
- /**
- * Equality of locators is achieved if prefix and resource path
- * are equal.
- *
- * @param obj the object to compare to
- * @return true if the 2 objects are equal;
- * false otherwise
- */
- public boolean equals(Object obj) {
- if (obj instanceof DavResourceLocatorImpl) {
- DavResourceLocatorImpl locator = (DavResourceLocatorImpl) obj;
- boolean equalWsName = (workspacePath == null) ? locator.workspacePath == null : workspacePath.equals(locator.workspacePath);
- boolean equalRPath = (resourcePath == null) ? locator.resourcePath == null : resourcePath.equals(locator.resourcePath);
-
- return prefix.equals(locator.prefix) && equalWsName && equalRPath;
- }
- return false;
- }
- }
-}
-
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DavResourceFactoryImpl.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DavResourceFactoryImpl.java
deleted file mode 100644
index 13907788470..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DavResourceFactoryImpl.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.transaction.TransactionResource;
-import org.apache.jackrabbit.webdav.transaction.TransactionDavServletRequest;
-import org.apache.jackrabbit.webdav.observation.SubscriptionManager;
-import org.apache.jackrabbit.webdav.observation.ObservationResource;
-import org.apache.jackrabbit.webdav.version.DeltaVServletRequest;
-import org.apache.jackrabbit.webdav.version.VersionControlledResource;
-import org.apache.jackrabbit.webdav.spi.version.VersionItemCollection;
-import org.apache.jackrabbit.webdav.spi.version.VersionHistoryItemCollection;
-import org.apache.jackrabbit.webdav.spi.transaction.TxLockManagerImpl;
-
-import javax.jcr.*;
-import javax.jcr.version.Version;
-import javax.jcr.version.VersionHistory;
-
-/**
- * DavResourceFactoryImpl...
- */
-public class DavResourceFactoryImpl implements DavResourceFactory {
-
- private static Logger log = Logger.getLogger(DavResourceFactoryImpl.class);
-
- private final TxLockManagerImpl txMgr;
- private final SubscriptionManager subsMgr;
-
- /**
- * Create a new DavResourceFactoryImpl.
- *
- * @param txMgr
- * @param subsMgr
- */
- public DavResourceFactoryImpl(TxLockManagerImpl txMgr, SubscriptionManager subsMgr) {
- this.txMgr = txMgr;
- this.subsMgr = subsMgr;
- }
-
- /**
- * Create a new DavResource from the specified locator and request
- * objects. Note, that in contrast to
- * {@link #createResource(DavResourceLocator, DavSession)} the locator may
- * point to a non-existing resource.
- *
- * If the request contains a {@link org.apache.jackrabbit.webdav.version.DeltaVServletRequest#getLabel()
- * Label header}, the resource is build from the indicated
- * {@link org.apache.jackrabbit.webdav.version.VersionResource version} instead.
- *
- * @param locator
- * @param request
- * @param response
- * @return
- * @see DavResourceFactory#createResource(org.apache.jackrabbit.webdav.DavResourceLocator, org.apache.jackrabbit.webdav.DavServletRequest, org.apache.jackrabbit.webdav.DavServletResponse)
- */
- public DavResource createResource(DavResourceLocator locator,
- DavServletRequest request,
- DavServletResponse response) throws DavException {
-
- DavResource resource = null;
- DavSession session = request.getDavSession();
-
- if (locator.isRootLocation()) {
- resource = new RootCollection(locator, session, this);
- }
-
- if (resource == null) {
- try {
- resource = createResourceForItem(locator, session);
- } catch (RepositoryException e) {
- // create the default resources if no such item exists
-
- // MKCOL request forces a collection-resource even if there already
- // exists a repository-property with the given path. the MKCOL will
- // in that particular case fail with a 405 (method not allowed).
- if (DavMethods.getMethodCode(request.getMethod()) == DavMethods.DAV_MKCOL) {
- resource = new VersionControlledItemCollection(locator, session, this);
- } else {
- resource = new DefaultItemResource(locator, session, this);
- }
- }
-
- // if the created resource is version-controlled and the request
- // contains a Label header, the corresponding Version must be used
- // instead.
- if (request instanceof DeltaVServletRequest && isVersionControlled(resource)) {
- String labelHeader = ((DeltaVServletRequest)request).getLabel();
- if (labelHeader != null && DavMethods.isMethodAffectedByLabel(request.getMethod())) {
- try {
- Item item = session.getRepositorySession().getItem(locator.getResourcePath());
- Version v = ((Node)item).getVersionHistory().getVersionByLabel(labelHeader);
- DavResourceLocator vloc = locator.getFactory().createResourceLocator(locator.getPrefix(), locator.getWorkspacePath(), v.getPath());
- resource = new VersionItemCollection(vloc, session, this);
- } catch (RepositoryException e) {
- log.error("Failed to build version resource from "+locator.getHref(true)+" and label "+labelHeader);
- throw new JcrDavException(e);
- }
- }
- }
- }
-
- ((TransactionResource)resource).init(txMgr, ((TransactionDavServletRequest)request).getTransactionId());
- ((ObservationResource)resource).init(subsMgr);
-
- return resource;
- }
-
- /**
- * Create a new DavResource from the given locator and session.
- *
- * @param locator
- * @param session
- * @return DavResource representing either a repository item or the {@link RootCollection}.
- * @throws DavException if the given locator does neither refer to a repository item
- * nor does represent the {@link org.apache.jackrabbit.webdav.DavResourceLocator#isRootLocation()
- * root location}.
- */
- public DavResource createResource(DavResourceLocator locator, DavSession session) throws DavException {
- DavResource resource;
- try {
- resource = createResourceForItem(locator, session);
- } catch (RepositoryException e) {
- log.info("Creating resource for non-existing repository item ...");
- if (locator.isRootLocation()) {
- resource = new RootCollection(locator, session, this);
- } else {
- // todo: is this correct?
- resource = new VersionControlledItemCollection(locator, session, this);
- }
- }
-
- resource.addLockManager(txMgr);
- ((ObservationResource)resource).init(subsMgr);
-
- return resource;
- }
-
- /**
- * Tries to retrieve the repository item defined by the locator's resource
- * path and build the corresponding WebDAV resource. The following distinction
- * is made between items: Version nodes, VersionHistory nodes, root node,
- * unspecified nodes and finally property items.
- *
- * @param locator
- * @param session
- * @return DavResource representing a repository item.
- * @throws RepositoryException if {@link Session#getItem(String)} fails.
- */
- private DavResource createResourceForItem(DavResourceLocator locator, DavSession session) throws RepositoryException {
- DavResource resource;
- Item item = session.getRepositorySession().getItem(locator.getResourcePath());
- if (item.isNode()) {
- // create special resources for Version and VersionHistory
- if (item instanceof Version) {
- resource = new VersionItemCollection(locator, session, this);
- } else if (item instanceof VersionHistory) {
- resource = new VersionHistoryItemCollection(locator, session, this);
- } else if (ItemResourceConstants.ROOT_ITEM_PATH.equals(locator.getResourcePath())) {
- resource = new RootItemCollection(locator, session, this);
- } else{
- resource = new VersionControlledItemCollection(locator, session, this);
- }
- } else {
- resource = new DefaultItemResource(locator, session, this);
- }
- return resource;
- }
-
- /**
- * Returns true, if the specified resource is a {@link VersionControlledResource}
- * and has a version history.
- *
- * @param resource
- * @return true if the specified resource is version-controlled.
- */
- private boolean isVersionControlled(DavResource resource) {
- boolean vc = false;
- if (resource instanceof VersionControlledResource) {
- try {
- vc = ((VersionControlledResource)resource).getVersionHistory() != null;
- } catch (DavException e) {
- log.debug("Resource '" + resource.getHref() + "' is not version-controlled.");
- }
- }
- return vc;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DefaultItemCollection.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DefaultItemCollection.java
deleted file mode 100644
index 438865eac8d..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DefaultItemCollection.java
+++ /dev/null
@@ -1,729 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.property.*;
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.spi.lock.JcrActiveLock;
-import org.apache.jackrabbit.webdav.spi.nodetype.NodeTypeProperty;
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.ordering.*;
-import org.apache.jackrabbit.webdav.util.Text;
-import org.apache.jackrabbit.webdav.lock.*;
-
-import javax.jcr.*;
-import javax.jcr.lock.Lock;
-import javax.jcr.nodetype.NodeType;
-import java.util.*;
-import java.io.*;
-
-/**
- * DefaultItemCollection represents a JCR node item.
- */
-public class DefaultItemCollection extends AbstractItemResource
- implements OrderingResource {
-
- private static Logger log = Logger.getLogger(DefaultItemCollection.class);
-
- private InputStream in;
-
- /**
- * Create a new DefaultItemCollection.
- *
- * @param locator
- * @param session
- */
- protected DefaultItemCollection(DavResourceLocator locator, DavSession session, DavResourceFactory factory) {
- super(locator, session, factory);
- if (exists() && !(item instanceof Node)) {
- throw new IllegalArgumentException("A collection resource can not be constructed from a Property item.");
- }
- }
-
- //----------------------------------------------< DavResource interface >---
- /**
- * @see org.apache.jackrabbit.webdav.DavResource#getComplianceClass()
- */
- public String getComplianceClass() {
- StringBuffer sb = new StringBuffer(super.getComplianceClass());
- sb.append(", ").append(OrderingResource.COMPLIANCE_CLASS);
- return sb.toString();
- }
-
- /**
- * @see org.apache.jackrabbit.webdav.DavResource#getSupportedMethods()
- */
- public String getSupportedMethods() {
- StringBuffer sb = new StringBuffer(super.getSupportedMethods());
- // Ordering
- if (isOrderable()) {
- sb.append(", ").append(OrderingResource.METHODS);
- }
- return sb.toString();
- }
-
- /**
- * Always returns true
- *
- * @return true
- * @see org.apache.jackrabbit.webdav.DavResource#isCollection()
- */
- public boolean isCollection() {
- return true;
- }
-
-
- /**
- * Returns an {@link java.io.InputStream} to the content of this collection.
- *
- * @return
- * @see org.apache.jackrabbit.webdav.DavResource#getStream()
- */
- public InputStream getStream() {
- initProperties();
- return in;
- }
-
- /**
- * This implementation of the DavResource does only allow
- * to set the jcr:mixinnodetypes property. Please note that the existing list of
- * mixin nodetypes will be completely replaces.
- * In order to add / set any other repository property on the underlaying
- * {@link javax.jcr.Node} use addMember(DavResource) or
- * addMember(DavResource, InputStream) or modify the value
- * of the corresponding resource.
- *
- * @param property
- * @throws org.apache.jackrabbit.webdav.DavException
- * @see org.apache.jackrabbit.webdav.DavResource#setProperty(org.apache.jackrabbit.webdav.property.DavProperty)
- * @see #JCR_MIXINNODETYPES
- * @todo undo incomplete modifications...
- */
- public void setProperty(DavProperty property) throws DavException {
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
- if (property.getName().equals(JCR_MIXINNODETYPES)) {
- try {
- Node n = (Node)item;
- NodeType[] existingMixin = n.getMixinNodeTypes();
- NodeTypeProperty mix = new NodeTypeProperty(property);
- Set mixins = mix.getNodeTypeNames();
-
- for (int i = 0; i < existingMixin.length; i++) {
- String name = existingMixin[i].getName();
- if (mixins.contains(name)){
- // do not add existing mixins
- mixins.remove(name);
- } else {
- // remove mixin that are not contained in the new list
- n.removeMixin(name);
- }
- }
-
- // add the remaining mixing types that are not yet set
- Iterator it = mixins.iterator();
- while (it.hasNext()) {
- n.addMixin((String)it.next());
- }
- complete();
-
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- } else {
- // all props except for mixinnodetypes are read-only
- throw new DavException(DavServletResponse.SC_CONFLICT);
- }
- }
-
- /**
- * This implementation of the DavResource does only allow
- * to remove the jcr:mixinnodetypes property.
- *
- * @param propertyName
- * @throws org.apache.jackrabbit.webdav.DavException
- * @see org.apache.jackrabbit.webdav.DavResource#removeProperty(org.apache.jackrabbit.webdav.property.DavPropertyName)
- * @see #JCR_MIXINNODETYPES
- * @todo undo incomplete modifications...
- */
- public void removeProperty(DavPropertyName propertyName) throws DavException {
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
- if (JCR_MIXINNODETYPES.equals(propertyName)) {
- // remove all mixin nodetypes
- try {
- Node n = (Node)item;
- NodeType[] mixins = n.getMixinNodeTypes();
- for (int i = 0; i < mixins.length; i++) {
- n.removeMixin(mixins[i].getName());
- }
- complete();
-
- } catch (RepositoryException e) {
- // NoSuchNodeTypeException, ConstraintViolationException should never occur...
- throw new JcrDavException(e);
- }
- } else {
- // all props except for mixinnodetypes are read-only
- throw new DavException(DavServletResponse.SC_CONFLICT);
- }
- }
-
- /**
- * If the specified resource represents a collection, a new node is {@link Node#addNode(String)
- * added} to the item represented by this resource. If an input stream is specified
- * together with a collection resource {@link Session#importXML(String, java.io.InputStream)}
- * is called instead and this resource path is used as parentAbsPath argument.
- *
- * However, if the specified resource is not of resource type collection a
- * new {@link Property} is set or an existing one is changed by modifying its
- * value.
- * NOTE: with the current implementation it is not possible to create or
- * modify multivalue JCR properties.
- * NOTE: if the JCR property represented by the specified resource has an
- * {@link PropertyType#UNDEFINED undefined} resource type, its value will be
- * changed/set to type {@link PropertyType#BINARY binary}.
- *
- * @param resource
- * @param in
- * @throws org.apache.jackrabbit.webdav.DavException
- * @see org.apache.jackrabbit.webdav.DavResource#addMember(org.apache.jackrabbit.webdav.DavResource, java.io.InputStream)
- * @see Node#addNode(String)
- * @see Node#setProperty(String, java.io.InputStream)
- */
- public void addMember(DavResource resource, InputStream in)
- throws DavException {
-
- /* RFC 2815 states that all 'parents' must exist in order all addition of members */
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_CONFLICT);
- }
-
- try {
- Node n = (Node) item;
- if (resource.isCollection()) {
- if (in == null) {
- // MKCOL without a request body, try if a default-primary-type is defined.
- n.addNode(resource.getDisplayName());
- } else {
- // MKCOL, which is not allowed for existing resources
- getRepositorySession().importXML(getResourcePath(), in);
- }
- } else {
- if (in == null) {
- // PUT: not possible
- throw new DavException(DavServletResponse.SC_BAD_REQUEST, "Cannot create a new non-collection resource without request body.");
- } else {
- // TODO: find a way to create non-binary and multivalue properties
- // PUT : create new or overwrite existing property.
- // NOTE: will fail for multivalue properties.
- n.setProperty(getResourceName(resource.getResourcePath(), true), in);
- }
- }
- complete();
- } catch (ItemExistsException e) {
- // according to RFC 2518: MKCOL only possible on non-existing/deleted resource
- throw new JcrDavException(e, DavServletResponse.SC_METHOD_NOT_ALLOWED);
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- } catch (IOException e) {
- throw new DavException(DavServletResponse.SC_UNPROCESSABLE_ENTITY, e.getMessage());
- }
- }
-
- /**
- * @see org.apache.jackrabbit.webdav.DavResource#addMember(org.apache.jackrabbit.webdav.DavResource)
- */
- public void addMember(DavResource resource) throws DavException {
- addMember(resource, resource.getStream());
- }
-
- /**
- * @see org.apache.jackrabbit.webdav.DavResource#getMembers()
- */
- public DavResourceIterator getMembers() {
- ArrayList memberList = new ArrayList();
- if (exists()) {
- try {
- Node n = (Node)item;
- // add all node members
- NodeIterator it = n.getNodes();
- while (it.hasNext()) {
- Node node = it.nextNode();
- DavResourceLocator loc = getLocatorFromItem(node);
- memberList.add(createResourceFromLocator(loc));
- }
- // add all property members
- PropertyIterator propIt = n.getProperties();
- while (propIt.hasNext()) {
- Property prop = propIt.nextProperty();
- DavResourceLocator loc = getLocatorFromItem(prop);
- memberList.add(createResourceFromLocator(loc));
- }
- } catch (RepositoryException e) {
- // ignore
- log.error(e.getMessage());
- } catch (DavException e) {
- // should never occur.
- log.error(e.getMessage());
- }
- }
- return new DavResourceIteratorImpl(memberList);
- }
-
- /**
- * Removes the repository item represented by the specified member
- * resource.
- *
- * @throws DavException if this resource does not exist or if an error occurs
- * while deleting the underlaying item.
- * @see DavResource#removeMember(DavResource)
- * @see javax.jcr.Item#remove()
- */
- public void removeMember(DavResource member) throws DavException {
- Session session = getRepositorySession();
- if (!exists() || !session.itemExists(member.getResourcePath())) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
- if (!getResourcePath().equals(Text.getRelativeParent(member.getResourcePath(), 1))) {
- throw new DavException(DavServletResponse.SC_CONFLICT, member.getResourcePath() + "is not member of this resource (" + getResourcePath() + ")");
- }
- try {
- session.getItem(member.getResourcePath()).remove();
- complete();
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- }
-
- /**
- * @param type
- * @param scope
- * @return true if a lock with the specified type and scope is present on
- * this resource, false otherwise. If retrieving the corresponding information
- * fails, false is returned.
- * @see org.apache.jackrabbit.webdav.DavResource#hasLock(org.apache.jackrabbit.webdav.lock.Type, org.apache.jackrabbit.webdav.lock.Scope)
- */
- public boolean hasLock(Type type, Scope scope) {
- if (isLockable(type, scope)) {
- if (Type.WRITE.equals(type)) {
- try {
- return ((Node) item).isLocked();
- } catch (RepositoryException e) {
- log.error(e.getMessage());
- }
- } else {
- return super.hasLock(type, scope);
- }
- }
- return false;
- }
-
- /**
- * Retrieve the lock with the specified type and scope.
- *
- * @param type
- * @param scope
- * @return lock with the specified type and scope is present on this
- * resource or null. NOTE: If retrieving the write lock present
- * on the underlaying repository item fails, null is return.
- * @see org.apache.jackrabbit.webdav.DavResource#getLock(org.apache.jackrabbit.webdav.lock.Type, org.apache.jackrabbit.webdav.lock.Scope)
- * @see javax.jcr.Node#getLock() for the write locks.
- */
- public ActiveLock getLock(Type type, Scope scope) {
- ActiveLock lock = null;
- if (isLockable(type, scope)) {
- if (Type.WRITE.equals(type)) {
- try {
- if (!exists()) {
- log.warn("Unable to retrieve lock: no item found at '" + getResourcePath() + "'");
- } else if (((Node) item).isLocked()) {
- Lock jcrLock = ((Node) item).getLock();
- // TODO: find out whether this lock is session-scoped or not!
- lock = new JcrActiveLock(jcrLock);
- }
- } catch (AccessDeniedException e) {
- log.error("Error while accessing resource lock: "+e.getMessage());
- } catch (UnsupportedRepositoryOperationException e) {
- log.error("Error while accessing resource lock: "+e.getMessage());
- } catch (RepositoryException e) {
- log.error("Error while accessing resource lock: "+e.getMessage());
- }
- } else {
- lock = super.getLock(type, scope);
- }
- }
- return lock;
- }
-
- /**
- * Creates a lock on this resource by locking the underlaying
- * {@link javax.jcr.Node node}. Except for the {@link org.apache.jackrabbit.webdav.lock.LockInfo#isDeep()} }
- * all information included in the LockInfo object is ignored.
- * Lock timeout is defined by JCR implementation.
- *
- * @param reqLockInfo
- * @return lock object representing the lock created on this resource.
- * @throws org.apache.jackrabbit.webdav.DavException
- * @see org.apache.jackrabbit.webdav.DavResource#lock(org.apache.jackrabbit.webdav.lock.LockInfo)
- * @see Node#lock(boolean, boolean)
- */
- public ActiveLock lock(LockInfo reqLockInfo) throws DavException {
-
- if (!isLockable(reqLockInfo.getType(), reqLockInfo.getScope())) {
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED);
- }
-
- if (Type.WRITE.equals(reqLockInfo.getType())) {
- if (!exists()) {
- log.warn("Cannot create a write lock for non-existing JCR node (" + getResourcePath() + ")");
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
- try {
- boolean sessionScoped = EXCLUSIVE_SESSION.equals(reqLockInfo.getScope());
- Lock jcrLock = ((Node)item).lock(reqLockInfo.isDeep(), sessionScoped);
- return new JcrActiveLock(jcrLock, sessionScoped);
-
- } catch (RepositoryException e) {
- // UnsupportedRepositoryOperationException should not occur...
- throw new JcrDavException(e);
- }
- } else {
- return super.lock(reqLockInfo);
- }
- }
-
- /**
- * Refreshes the lock on this resource. With this implementation the
- * {@link javax.jcr.lock lock} present on the underlaying {@link javax.jcr.Node node}
- * is refreshed. The timeout indicated by the LockInfo
- * object is ignored.
- *
- * @param reqLockInfo LockInfo as build from the request.
- * @param lockToken
- * @return the updated lock info object.
- * @throws org.apache.jackrabbit.webdav.DavException in case the lock could not be refreshed.
- * @see org.apache.jackrabbit.webdav.DavResource#refreshLock(org.apache.jackrabbit.webdav.lock.LockInfo, String)
- * @see javax.jcr.lock.Lock#refresh()
- */
- public ActiveLock refreshLock(LockInfo reqLockInfo, String lockToken)
- throws DavException {
-
- if (lockToken == null) {
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED);
- }
-
- ActiveLock lock = getWriteLock();
- if (lock != null && lockToken.equals(lock.getToken())) {
- try {
- Lock jcrLock = ((Node) item).getLock();
- jcrLock.refresh();
- return new JcrActiveLock(jcrLock, EXCLUSIVE_SESSION.equals(lock.getScope()));
- } catch (RepositoryException e) {
- /*
- NOTE: LockException is only thrown by Lock.refresh()
- the lock exception thrown by Node.getLock() was circumvented
- by the init test if there is a lock applied...
- NOTE: UnsupportedRepositoryOperationException should not occur
- */
- throw new JcrDavException(e);
- }
- } else {
- return super.refreshLock(reqLockInfo, lockToken);
- }
- }
-
- /**
- * Remove the write lock from this resource by unlocking the underlaying
- * {@link javax.jcr.Node node}.
- *
- * @param lockToken
- * @throws org.apache.jackrabbit.webdav.DavException
- * @see org.apache.jackrabbit.webdav.DavResource#unlock(String)
- * @see javax.jcr.Node#unlock()
- */
- public void unlock(String lockToken) throws DavException {
- ActiveLock lock = getWriteLock();
- if (lock != null && lockToken.equals(lock.getToken())) {
- try {
- ((Node) item).unlock();
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- } else {
- super.unlock(lockToken);
- }
- }
-
- /**
- * Returns the write lock present on this resource or null if
- * no write lock exists. NOTE: that the scope of a write lock may either
- * be {@link org.apache.jackrabbit.webdav.lock.Scope#EXCLUSIVE} or {@link #EXCLUSIVE_SESSION}.
- *
- * @return write lock or null
- * @throws DavException if this resource does not represent a repository item.
- */
- private ActiveLock getWriteLock() throws DavException {
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND, "Unable to retrieve write lock for non existing repository item (" + getResourcePath() + ")");
- }
- ActiveLock writeLock = getLock(Type.WRITE, Scope.EXCLUSIVE);
- if (writeLock == null) {
- writeLock = getLock(Type.WRITE, EXCLUSIVE_SESSION);
- }
- return writeLock;
- }
-
- //-----------------------------------------< OrderingResource interface >---
- /**
- * Returns true if this resource exists and the nodetype defining the
- * underlaying repository node allow to reorder this nodes children.
- *
- * @return true if {@link #orderMembers(OrderPatch)} can be called on this
- * resource.
- * @see org.apache.jackrabbit.webdav.ordering.OrderingResource#isOrderable()
- * @see javax.jcr.nodetype.NodeType#hasOrderableChildNodes()
- */
- public boolean isOrderable() {
- boolean orderable = false;
- if (exists()) {
- try {
- orderable = ((Node) item).getPrimaryNodeType().hasOrderableChildNodes();
- } catch (RepositoryException e) {
- log.warn(e.getMessage());
- }
- }
- return orderable;
- }
-
- /**
- * Reorder the child nodes of the repository item represented by this
- * resource as indicated by the specified {@link OrderPatch} object.
- *
- * @param orderPatch
- * @throws org.apache.jackrabbit.webdav.DavException
- * @see org.apache.jackrabbit.webdav.ordering.OrderingResource#orderMembers(org.apache.jackrabbit.webdav.ordering.OrderPatch)
- * @see Node#orderBefore(String, String)
- */
- public void orderMembers(OrderPatch orderPatch) throws DavException {
- if (!isOrderable()) {
- throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- }
- // only custom ordering is allowed
- if (!OrderingConstants.ORDERING_TYPE_CUSTOM.equalsIgnoreCase(orderPatch.getOrderingType())) {
- throw new DavException(DavServletResponse.SC_UNPROCESSABLE_ENTITY,"Only DAV:custom ordering type supported.");
- }
-
- OrderPatch.Member[] instructions = orderPatch.getOrderInstructions();
- Node n = (Node)item;
- try {
- for (int i = 0; i < instructions.length; i++) {
- String srcRelPath = getResourceName(n.getPath() + instructions[i].getMemberHandle(), false);
- Position pos = instructions[i].getPosition();
- String destRelPath = getRelDestinationPath(pos, n.getNodes());
-
- n.orderBefore(srcRelPath, destRelPath);
- }
- } catch (RepositoryException e) {
- // UnsupportedRepositoryException should not occur
- throw new JcrDavException(e);
- }
- }
-
- /**
- * Retrieve the relative path of the child node that acts as destination.
- * A null destination path is used to place the child node indicated
- * by the source path at the end of the list.
- *
- * @param position
- * @param childNodes
- * @return the relative path of the child node used as destination or null
- * if the source node should be placed at the last position.
- * @throws javax.jcr.RepositoryException
- */
- private String getRelDestinationPath(Position position, NodeIterator childNodes)
- throws RepositoryException {
-
- String destRelPath = null;
- if (position.getType() == Position.TYPE_FIRST) {
- while (childNodes.hasNext()) {
- Node firstChild = childNodes.nextNode();
- destRelPath = firstChild.getPath();
- }
- // no child nodes available > reordering to 'first' position fails.
- if (destRelPath == null) {
- throw new ItemNotFoundException("No 'first' item found for reordering.");
- }
- } else if (position.getType() == Position.TYPE_AFTER) {
- String afterRelPath = getResourceName(position.getSegment(), false);
- boolean found = false;
- while (childNodes.hasNext() && destRelPath == null) {
- String childPath = childNodes.nextNode().getPath();
- if (found) {
- destRelPath = childPath;
- } else {
- found = afterRelPath.equals(Text.getLabel(childPath));
- }
- }
- } else {
- destRelPath = position.getSegment();
- }
-
- if (destRelPath != null) {
- destRelPath = getResourceName(destRelPath, false);
- }
-
- return destRelPath;
- }
-
- //--------------------------------------------------------------------------
- /**
- * Extend the general {@link #supportedLock} field by lock entries specific for this
- * resource: write locks (exclusive or exclusive session-scoped) in case the underlaying
- * node has the node type mix:lockable.
- *
- * @see #MIX_LOCKABLE
- */
- protected void initLockSupport() {
- super.initLockSupport();
- // add exclusive write lock if allowed for the given node
- try {
- if (exists() && ((Node)item).isNodeType(MIX_LOCKABLE)) {
- supportedLock.addEntry(Type.WRITE, Scope.EXCLUSIVE);
- // TODO: do session-scoped lock properly (including session caching and proper scope discovery)
- //supportedLock.addEntry(new SessionScopedLockEntry());
- }
- } catch (RepositoryException e) {
- log.warn(e.getMessage());
- }
- }
-
- /**
- * Fill the property set for this resource.
- */
- protected void initProperties() {
- super.initProperties();
- if (exists()) {
- try {
- String prefix = "_tmp_" + item.getName();
- // create tmpFile in default system-tmp directory
- File tmpfile = File.createTempFile(prefix, null, null);
- tmpfile.deleteOnExit();
- FileOutputStream out = new FileOutputStream(tmpfile);
- getSession().getRepositorySession().exportSysView(item.getPath(), out, false, true);
- out.close();
- in = new FileInputStream(tmpfile);
-
- properties.add(new DefaultDavProperty(DavPropertyName.GETCONTENTLENGTH, new Long(tmpfile.length())));
- properties.add(new DefaultDavProperty(DavPropertyName.GETCONTENTTYPE, "text/xml"));
-
- } catch (IOException e) {
- log.error("Error while property initialization: "+e.getMessage());
- } catch (RepositoryException e) {
- log.error("Error while property initialization: "+e.getMessage());
- }
-
- Node n = (Node)item;
- // overwrite the default modificationtime if possible
- try {
- if (n.hasProperty(PROP_LASTMODIFIED)) {
- setModificationTime(n.getProperty(PROP_LASTMODIFIED).getLong());
- }
- } catch (RepositoryException e) {
- log.warn("Error while accessing jcr:lastModified property");
- }
- // overwrite the default creation date if possible
- try {
- if (n.hasProperty(PROP_CREATED)) {
- long creationTime = n.getProperty(PROP_CREATED).getValue().getLong();
- properties.add(new DefaultDavProperty(DavPropertyName.CREATIONDATE,
- DavConstants.creationDateFormat.format(new Date(creationTime))));
- }
- } catch (RepositoryException e) {
- log.warn("Error while accessing jcr:created property");
- }
-
- // add node-specific resource properties
- try {
- properties.add(new NodeTypeProperty(JCR_PRIMARYNODETYPE, n.getPrimaryNodeType(), false));
- properties.add(new NodeTypeProperty(JCR_MIXINNODETYPES, n.getMixinNodeTypes(), false));
- properties.add(new DefaultDavProperty(JCR_INDEX, new Integer(n.getIndex())));
- addHrefProperty(JCR_REFERENCES, n.getReferences(), false);
- } catch (RepositoryException e) {
- log.error("Failed to retrieve primary nodetype property: " + e.getMessage());
- }
- try {
- Item primaryItem = n.getPrimaryItem();
- addHrefProperty(JCR_PRIMARYITEM, new Item[] {primaryItem}, false);
- } catch (ItemNotFoundException e) {
- log.info("No primary item present on this node '" + getResourcePath() + "'");
- } catch (RepositoryException e) {
- log.error("Error while retrieving primary item: " + e.getMessage());
- }
-
- // property defined by RFC 3648: this resource always has custom ordering!
- if (isOrderable()) {
- properties.add(new OrderingType(OrderingConstants.ORDERING_TYPE_CUSTOM));
- }
- }
- }
-
- /**
- * Add a {@link org.apache.jackrabbit.webdav.property.HrefProperty} with the
- * specified property name and values. Each item present in the specified
- * values array is referenced in the resulting property.
- *
- * @param name
- * @param values
- * @param isProtected
- */
- protected void addHrefProperty(DavPropertyName name, Item[] values, boolean isProtected) {
- if (values == null) {
- return;
- }
- try {
- String[] pHref = new String[values.length];
- for (int i = 0; i < values.length; i++) {
- pHref[i] = this.getLocatorFromResourcePath(values[i].getPath()).getHref(true);
- }
- properties.add(new HrefProperty(name, pHref, isProtected));
- } catch (RepositoryException e) {
- e.getMessage();
- }
- }
-
- /**
- * Add a new {@link HrefProperty href property} to the property set, where
- * all items present in the specifed iterator are referenced in the
- * resulting property.
- *
- * @param name
- * @param itemIterator
- * @param isProtected
- * @see #addHrefProperty(DavPropertyName, Item[], boolean)
- */
- protected void addHrefProperty(DavPropertyName name, Iterator itemIterator,
- boolean isProtected) {
- ArrayList l = new ArrayList();
- while (itemIterator.hasNext()) {
- l.add(itemIterator.next());
- }
- addHrefProperty(name, (Item[]) l.toArray(new Item[l.size()]), isProtected);
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DefaultItemResource.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DefaultItemResource.java
deleted file mode 100644
index 7a615991ad6..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/DefaultItemResource.java
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.property.*;
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.DavResource;
-import org.apache.jackrabbit.webdav.DavResourceIterator;
-import org.apache.jackrabbit.webdav.DavResourceIteratorImpl;
-import org.apache.jackrabbit.webdav.spi.property.ValuesProperty;
-import org.apache.jackrabbit.webdav.spi.property.LengthsProperty;
-import org.apache.jackrabbit.webdav.lock.*;
-import org.apache.jackrabbit.core.util.ValueHelper;
-
-import javax.jcr.*;
-import java.io.*;
-import java.util.*;
-
-/**
- * DefaultItemResource represents JCR property item.
- *
- * @see Property
- */
-public class DefaultItemResource extends AbstractItemResource {
-
- private static Logger log = Logger.getLogger(DefaultItemResource.class);
-
- /**
- * Create a new DefaultItemResource.
- *
- * @param locator
- * @param session
- */
- public DefaultItemResource(DavResourceLocator locator, DavSession session, DavResourceFactory factory) {
- super(locator, session, factory);
- }
-
- //----------------------------------------------< DavResource interface >---
- /**
- * Returns false.
- *
- * @return false
- * @see DavResource#isCollection()
- */
- public boolean isCollection() {
- return false;
- }
-
- /**
- * In case an underlaying repository {@link Property property} exists the following
- * logic is applyed to obtain the stream:
- *
Property is not multivalue: Return the {@link javax.jcr.Value#getStream()
- * stream representation} of the property value.
- *
Property is multivalue: Return stream that provides the system view of
- * that item.
- *
- *
- * @return
- * @see DavResource#getStream()
- */
- public InputStream getStream() {
- InputStream in = null;
- if (exists()) {
- try {
- // NOTE: stream cannot be obtained for multivalue properties
- if (!isMultiple()) {
- in = ((Property)item).getStream();
- }
- } catch (ValueFormatException e) {
- // should not occur
- log.error("Cannot obtain stream from resource: " + e.getMessage());
- } catch (RepositoryException e) {
- log.error("Cannot obtain stream from resource: " + e.getMessage());
- }
- }
- return in;
- }
-
- /**
- * Sets the given property. Note, that {@link #JCR_VALUE} and {@link #JCR_VALUES}
- * are the only resource properties that are allowed to be modified. Any other
- * property is read-only and will throw an exception ('Conflict').
- *
- * @param property
- * @throws DavException
- * @see DavResource#setProperty(org.apache.jackrabbit.webdav.property.DavProperty)
- * @todo undo incomplete modifications...
- */
- public void setProperty(DavProperty property) throws DavException {
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
- try {
- Property prop = (Property) item;
- int type = prop.getType();
- if (property.getName().equals(JCR_VALUE)) {
- Value val = ValueHelper.convert(String.valueOf(property.getValue()), type);
- prop.setValue(val);
- } else if (property.getName().equals(JCR_VALUES)) {
- prop.setValue(new ValuesProperty(property).getValues(prop.getType()));
- } else {
- throw new DavException(DavServletResponse.SC_CONFLICT);
- }
- complete();
-
- } catch (IllegalArgumentException e) {
- throw new DavException(DavServletResponse.SC_BAD_REQUEST, e.getMessage());
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- }
-
- /**
- * Removing properties is not allowed, for a single-value JCR-property without
- * a value does not exist. For multivalue properties an empty {@link Value values array}
- * may be specified with by setting the {@link #JCR_VALUES 'values' webdav property}.
- *
- * @param propertyName
- * @throws DavException
- * @see org.apache.jackrabbit.webdav.DavResource#removeProperty(org.apache.jackrabbit.webdav.property.DavPropertyName)
- */
- public void removeProperty(DavPropertyName propertyName) throws DavException {
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
- throw new DavException(DavServletResponse.SC_FORBIDDEN);
- }
-
- /**
- * Method is not allowed.
- *
- * @see org.apache.jackrabbit.webdav.DavResource#addMember(org.apache.jackrabbit.webdav.DavResource, InputStream)
- */
- public void addMember(DavResource resource, InputStream in) throws DavException {
- throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED, "Cannot add members to a non-collection resource");
- }
-
- /**
- * Method is not allowed.
- *
- * @see DavResource#addMember(DavResource)
- */
- public void addMember(DavResource resource) throws DavException {
- throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED, "Cannot add members to a non-collection resource");
- }
-
- /**
- * Always returns an empty iterator for a non-collection resource might
- * not have internal members.
- *
- * @return an empty iterator
- * @see DavResource#getMembers()
- */
- public DavResourceIterator getMembers() {
- log.warn("A non-collection resource never has internal members.");
- return new DavResourceIteratorImpl(new ArrayList(0));
- }
-
- /**
- * Method is not allowed.
- *
- * @see DavResource#removeMember(DavResource)
- */
- public void removeMember(DavResource member) throws DavException {
- throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED, "Cannot remove members from a non-collection resource");
- }
-
- /**
- * {@link javax.jcr.Property JCR properties} are locked if their
- * parent node is locked; thus this method will always return the
- * {@link ActiveLock lock} object from the collection this resource is
- * internal member of.
- *
- * @param type
- * @param scope
- * @return lock present on this resource or null if this resource
- * has no lock.
- * @see DavResource#getLock(Type, Scope)
- */
- public ActiveLock getLock(Type type, Scope scope) {
- if (Type.WRITE.equals(type)) {
- return getCollection().getLock(type, scope);
- } else {
- return super.getLock(type, scope);
- }
- }
-
- //--------------------------------------------------------------------------
- /**
- * Add resource specific properties.
- */
- protected void initProperties() {
- super.initProperties();
- if (exists()) {
- try {
- Property prop = (Property)item;
- int type = prop.getType();
-
- // set the content type
- String contentType;
- if (!isMultiple()) {
- contentType = (type == PropertyType.BINARY) ? "application/octet-stream" : "text/plain";
- properties.add(new DefaultDavProperty(DavPropertyName.GETCONTENTTYPE, contentType));
- } // else: no contenttype for multivalue properties
-
- // add jcr-specific resource properties
- properties.add(new DefaultDavProperty(JCR_TYPE, PropertyType.nameFromValue(type)));
- if (isMultiple()) {
- properties.add(new ValuesProperty(prop.getValues()));
- properties.add(new LengthsProperty(prop.getLengths()));
- } else {
- properties.add(new DefaultDavProperty(JCR_VALUE, prop.getString()));
- properties.add(new DefaultDavProperty(JCR_LENGTH, String.valueOf(prop.getLength())));
- }
- } catch (RepositoryException e) {
- log.error("Failed to retrieve resource properties: "+e.getMessage());
- }
- }
- }
-
- /**
- * Returns true if the JCR Property represented by this resource is a multi
- * value property. Note: if this resource does not exist or if the definition
- * could not be retrieved false is returned.
- *
- * @return true if the underlaying resource is a multi value property.
- */
- private boolean isMultiple() {
- try {
- if (exists() && ((Property)item).getDefinition().isMultiple()) {
- return true;
- }
- } catch (RepositoryException e) {
- log.error("Error while retrieving property definition: " + e.getMessage());
- }
- return false;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/ItemResourceConstants.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/ItemResourceConstants.java
deleted file mode 100644
index ab61ba606a6..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/ItemResourceConstants.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi;
-
-import org.jdom.Namespace;
-import org.apache.jackrabbit.webdav.property.DavPropertyName;
-import org.apache.jackrabbit.webdav.DavResource;
-import org.apache.jackrabbit.webdav.version.DeltaVResource;
-import org.apache.jackrabbit.webdav.lock.Scope;
-import org.apache.jackrabbit.webdav.search.SearchResource;
-import org.apache.jackrabbit.webdav.observation.ObservationResource;
-
-/**
- * ItemResourceConstants provides constants for any resources
- * representing repository items.
- */
-public interface ItemResourceConstants {
-
- /**
- * Complience classes common to all item resources.
- */
- public static final String COMPLIANCE_CLASS = DavResource.COMPLIANCE_CLASS + ", " +ObservationResource.COMPLIANCE_CLASS + ", " + DeltaVResource.COMPLIANCE_CLASS;
-
- /**
- * Methods common to all item resources.
- */
- public static final String METHODS = DavResource.METHODS + ", " + ObservationResource.METHODS + ", " + SearchResource.METHODS + ", " +DeltaVResource.METHODS;
-
- /**
- * The resource path of the root-item-resource.
- */
- public static final String ROOT_ITEM_PATH = "/";
-
- /**
- * The version storage item resource path.
- */
- public static final String VERSIONSTORAGE_PATH = "/jcr:system/jcr:versionStorage";
-
- /**
- * Constant for the mix:versionable node type name.
- */
- public static final String MIX_VERSIONABLE = "mix:versionable";
-
- /**
- * Constant for the mix:lockable node type name.
- */
- public static final String MIX_LOCKABLE = "mix:lockable";
-
- /**
- * The namespace for all jcr specific extensions.
- */
- public static final Namespace NAMESPACE = Namespace.getNamespace("jcr", "http://www.day.com/jcr/webdav/1.0");
-
- // xml element names
- public static final String XML_PRIMARYNODETYPE = "primarynodetype";
- public static final String XML_VALUE = "value";
- public static final String XML_LENGTH = "length";
- public static final String XML_EXCLUSIVE_SESSION_SCOPED = "exclusive-session-scoped";
-
- // xml elements used to reflect the workspaces ns-registry
- // TODO: to be review...
- public static final String XML_NAMESPACE = "namespace";
- public static final String XML_NSPREFIX = "nsPrefix";
- public static final String XML_NSURI = "nsURI";
-
- /**
- * Extension to the WebDAV 'exclusive' lock, that allows to distinguish
- * the session-scoped and open-scoped locks on a JCR node.
- *
- * @see javax.jcr.Node#lock(boolean, boolean)
- */
- public static final Scope EXCLUSIVE_SESSION = Scope.create(XML_EXCLUSIVE_SESSION_SCOPED, NAMESPACE);
-
- /**
- * The 'removeexisting' element is not defined by RFC 3253. If it is present
- * in the UPDATE request body, uuid conflicts should be solved by removing
- * the existing nodes.
- *
- * @see javax.jcr.Node#restore(javax.jcr.version.Version, boolean)
- * @see javax.jcr.Workspace#restore(javax.jcr.version.Version[], boolean)
- * @see org.apache.jackrabbit.webdav.version.UpdateInfo
- */
- public static final String XML_REMOVEEXISTING = "removeexisting";
-
- /**
- * The 'relpath' element is not defined by RFC 3253. If it is present
- * in the UPDATE request body, the server is forced to used the text contained
- * as 'relPath' argument for the {@link javax.jcr.Node#restore(javax.jcr.version.Version, String, boolean)
- * Node.restore} call.
- *
- * @see javax.jcr.Node#restore(javax.jcr.version.Version, String, boolean)
- * @see org.apache.jackrabbit.webdav.version.UpdateInfo
- */
- public static final String XML_RELPATH = "relpath";
-
- // general property names
- public static final DavPropertyName JCR_NAME = DavPropertyName.create("name", NAMESPACE);
- public static final DavPropertyName JCR_PATH = DavPropertyName.create("path", NAMESPACE);
- public static final DavPropertyName JCR_DEPTH = DavPropertyName.create("depth", NAMESPACE);
- public static final DavPropertyName JCR_ISNEW = DavPropertyName.create("isnew", NAMESPACE);
- public static final DavPropertyName JCR_ISMODIFIED = DavPropertyName.create("ismodified", NAMESPACE);
-
- // property names used for resources representing jcr-nodes
- public static final DavPropertyName JCR_PRIMARYNODETYPE = DavPropertyName.create(XML_PRIMARYNODETYPE, NAMESPACE);
- public static final DavPropertyName JCR_MIXINNODETYPES = DavPropertyName.create("mixinnodetypes", NAMESPACE);
- public static final DavPropertyName JCR_INDEX = DavPropertyName.create("index", NAMESPACE);
- public static final DavPropertyName JCR_REFERENCES = DavPropertyName.create("references", NAMESPACE);
- public static final DavPropertyName JCR_PRIMARYITEM = DavPropertyName.create("primaryitem", NAMESPACE);
-
- // property names used for resources representing jcr-properties
- public static final DavPropertyName JCR_TYPE = DavPropertyName.create("type", NAMESPACE);
- public static final DavPropertyName JCR_VALUE = DavPropertyName.create("value", NAMESPACE);
- public static final DavPropertyName JCR_VALUES = DavPropertyName.create("values", NAMESPACE);
- public static final DavPropertyName JCR_LENGTH = DavPropertyName.create("length", NAMESPACE);
- public static final DavPropertyName JCR_LENGTHS = DavPropertyName.create("lengths", NAMESPACE);
-
- // property names used for resource representing a workspace
- public static final DavPropertyName JCR_NAMESPACES = DavPropertyName.create("namespaces", NAMESPACE);
-
- /**
- * Property name for the jcr:created property present on Version items.
- */
- public static final DavPropertyName CREATED = DavPropertyName.create("created", ItemResourceConstants.NAMESPACE);
-
- // JCR property names
- public static final String PROP_LASTMODIFIED = "jcr:lastModified";
- public static final String PROP_CREATED = "jcr:created";
- public static final String PROP_BASEVERSION = "jcr:baseVersion";
- public static final String PROP_PREDECESSORS = "jcr:predecessors";
- public static final String PROP_MERGEFAILED = "jcr:mergeFailed";
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/JcrDavException.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/JcrDavException.java
deleted file mode 100644
index fbaa9e82073..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/JcrDavException.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.DavException;
-import org.apache.jackrabbit.webdav.DavServletResponse;
-import org.jdom.Element;
-
-import javax.jcr.*;
-import javax.jcr.query.InvalidQueryException;
-import javax.jcr.lock.LockException;
-import javax.jcr.version.VersionException;
-import javax.jcr.nodetype.*;
-
-/**
- * JcrDavException extends the {@link DavException} in order to
- * wrap various repository exceptions.
- */
-public class JcrDavException extends DavException {
-
- private static Logger log = Logger.getLogger(JcrDavException.class);
-
- private Class exceptionClass;
-
- public JcrDavException(Exception e, int errorCode) {
- super(errorCode, e.getMessage());
- exceptionClass = e.getClass();
- }
-
- public JcrDavException(AccessDeniedException e) {
- this(e, DavServletResponse.SC_FORBIDDEN);
- }
-
- public JcrDavException(ConstraintViolationException e) {
- this(e, DavServletResponse.SC_CONFLICT);
- }
-
- public JcrDavException(InvalidItemStateException e) {
- this(e, DavServletResponse.SC_CONFLICT);
- }
-
- public JcrDavException(InvalidSerializedDataException e) {
- this(e, DavServletResponse.SC_BAD_REQUEST);
- }
-
- public JcrDavException(InvalidQueryException e) {
- this(e, DavServletResponse.SC_BAD_REQUEST);
- }
-
- public JcrDavException(ItemExistsException e) {
- this(e, DavServletResponse.SC_CONFLICT);
- }
-
- public JcrDavException(ItemNotFoundException e) {
- this(e, DavServletResponse.SC_FORBIDDEN);
- }
-
- public JcrDavException(LockException e) {
- this(e, DavServletResponse.SC_LOCKED);
- }
-
- public JcrDavException(MergeException e) {
- this(e, DavServletResponse.SC_CONFLICT);
- }
-
- public JcrDavException(NamespaceException e) {
- this(e, DavServletResponse.SC_CONFLICT);
- }
-
- public JcrDavException(NoSuchNodeTypeException e) {
- this(e, DavServletResponse.SC_CONFLICT);
- }
-
- public JcrDavException(NoSuchWorkspaceException e) {
- this(e, DavServletResponse.SC_CONFLICT);
- }
-
- public JcrDavException(PathNotFoundException e) {
- this(e, DavServletResponse.SC_CONFLICT);
- }
-
- public JcrDavException(ReferentialIntegrityException e) {
- this(e, DavServletResponse.SC_CONFLICT);
- }
-
- public JcrDavException(RepositoryException e) {
- this(e, DavServletResponse.SC_FORBIDDEN);
- }
-
- public JcrDavException(UnsupportedRepositoryOperationException e) {
- this(e, DavServletResponse.SC_NOT_IMPLEMENTED);
- }
-
- public JcrDavException(ValueFormatException e) {
- this(e, DavServletResponse.SC_CONFLICT);
- }
-
- public JcrDavException(VersionException e) {
- this(e, DavServletResponse.SC_CONFLICT);
- }
-
- /**
- * Returns a DAV:error Xml element containing the exceptions class and the
- * message as child elements.
- *
- * @return Xml representation of this exception.
- */
- public Element getError() {
- Element error = super.getError();
- Element excep = new Element("exception", ItemResourceConstants.NAMESPACE);
- excep.addContent(new Element("class", ItemResourceConstants.NAMESPACE).setText(exceptionClass.getName()));
- excep.addContent(new Element("message", ItemResourceConstants.NAMESPACE).setText(getMessage()));
- error.addContent(excep);
- return error;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/RootCollection.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/RootCollection.java
deleted file mode 100644
index 4ee1ad8ec4b..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/RootCollection.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.spi.version.report.RegisteredNamespacesReport;
-import org.apache.jackrabbit.webdav.spi.version.report.NodeTypesReport;
-import org.apache.jackrabbit.webdav.version.report.SupportedReportSetProperty;
-import org.apache.jackrabbit.webdav.version.report.ReportType;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import java.util.*;
-import java.io.InputStream;
-
-/**
- * RootCollection represent the WebDAV root resource that does not
- * represent any repository item. A call to getMembers() returns a
- * DavResourceIterator containing only RootItemCollection
- * resources, thus revealing the names of the accessable workspaces.
- */
-public class RootCollection extends AbstractResource implements DavResource {
-
- private static Logger log = Logger.getLogger(RootCollection.class);
-
- /**
- * Create a new RootCollection.
- *
- * @param locator
- * @param session
- */
- protected RootCollection(DavResourceLocator locator, DavSession session, DavResourceFactory factory) {
- super(locator, session, factory);
- setModificationTime(new Date().getTime());
- }
-
- /**
- * Returns a string listing the complieance classes for this resource as it
- * is required for the DAV response header.
- *
- * @return string listing the compliance classes.
- * @see org.apache.jackrabbit.webdav.DavResource#getComplianceClass()
- */
- public String getComplianceClass() {
- return DavResource.COMPLIANCE_CLASS;
- }
-
- /**
- * Returns a string listing the METHODS for this resource as it
- * is required for the "Allow" response header.
- *
- * @return string listing the METHODS allowed
- * @see org.apache.jackrabbit.webdav.DavResource#getSupportedMethods()
- */
- public String getSupportedMethods() {
- StringBuffer sb = new StringBuffer(DavResource.METHODS);
- return sb.toString();
- }
-
- /**
- * Returns true
- *
- * @return true
- * @see org.apache.jackrabbit.webdav.DavResource#exists()
- */
- public boolean exists() {
- return true;
- }
-
- /**
- * Returns true
- *
- * @return true
- * @see org.apache.jackrabbit.webdav.DavResource#isCollection()
- */
- public boolean isCollection() {
- return true;
- }
-
- /**
- * Returns an empty string.
- *
- * @return empty string
- * @see org.apache.jackrabbit.webdav.DavResource#getDisplayName()
- */
- public String getDisplayName() {
- return "";
- }
-
- /**
- * Always returns null
- *
- * @return null for the root resource is not internal member
- * of any resource.
- * @see org.apache.jackrabbit.webdav.DavResource#getCollection()
- */
- public DavResource getCollection() {
- return null;
- }
-
- /**
- * Throws exception: 403 Forbidden.
- * @see DavResource#addMember(DavResource, InputStream)
- */
- public void addMember(DavResource resource, InputStream in) throws DavException {
- throw new DavException(DavServletResponse.SC_FORBIDDEN);
- }
-
- /**
- * Throws exception: 403 Forbidden.
- * @see DavResource#addMember(org.apache.jackrabbit.webdav.DavResource)
- */
- public void addMember(DavResource resource) throws DavException {
- throw new DavException(DavServletResponse.SC_FORBIDDEN);
- }
-
- /**
- * Returns an iterator over the member resources, which are all
- * RootItemCollection resources, revealing
- * the names of all available workspaces.
- *
- * @return members of this collection
- * @see org.apache.jackrabbit.webdav.DavResource#getMembers()
- */
- public DavResourceIterator getMembers() {
- List memberList = new ArrayList();
- try {
- String[] wsNames = getSession().getRepositorySession().getWorkspace().getAccessibleWorkspaceNames();
- for (int i = 0; i < wsNames.length; i++) {
- DavResourceLocator childLoc = getLocator().getFactory().createResourceLocator(getLocator().getPrefix(), "/"+wsNames[i], ItemResourceConstants.ROOT_ITEM_PATH);
- memberList.add(createResourceFromLocator(childLoc));
- }
- } catch (RepositoryException e) {
- log.error(e.getMessage());
- } catch (DavException e) {
- // should never occur
- log.error(e.getMessage());
- }
- return new DavResourceIteratorImpl(memberList);
- }
-
- /**
- * Throws exception: 403 Forbidden.
- * @see DavResource#removeMember(org.apache.jackrabbit.webdav.DavResource)
- */
- public void removeMember(DavResource member) throws DavException {
- throw new DavException(DavServletResponse.SC_FORBIDDEN);
- }
-
- //--------------------------------------------------------------------------
- /**
- * @see AbstractResource#initLockSupport()
- */
- protected void initLockSupport() {
- // no locking supported
- }
-
- /**
- * @see AbstractResource#initSupportedReports()
- */
- protected void initSupportedReports() {
- if (exists()) {
- supportedReports = new SupportedReportSetProperty(new ReportType[] {
- ReportType.EXPAND_PROPERTY,
- NodeTypesReport.NODETYPES_REPORT,
- RegisteredNamespacesReport.REGISTERED_NAMESPACES_REPORT
- });
- }
- }
-
- /**
- * Since the root resource does not represent a repository item and therefore
- * is not member of a workspace resource, the workspace href is calculated
- * from the workspace name retrieved from the underlaying repository session.
- *
- * @return workspace href build from workspace name.
- * @see AbstractResource#getWorkspaceHref()
- */
- protected String getWorkspaceHref() {
- Session session = this.getRepositorySession();
- if (session != null) {
- String workspaceName = session.getWorkspace().getName();
- DavResourceLocator loc = getLocator().getFactory().createResourceLocator(getLocator().getPrefix(), "/"+workspaceName, ItemResourceConstants.ROOT_ITEM_PATH);
- return loc.getHref(true);
- }
- return null;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/RootItemCollection.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/RootItemCollection.java
deleted file mode 100644
index 30219571ae1..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/RootItemCollection.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
-import org.apache.jackrabbit.webdav.property.DavProperty;
-import org.jdom.Element;
-
-import javax.jcr.NamespaceRegistry;
-import javax.jcr.RepositoryException;
-
-/**
- * RootItemCollection represents the root node of the underlaying
- * repository. However, the display name the name of the workspace is returned
- * the root node is located.
- *
- * @todo currently the jcr root node is the same for all workspace resources... this is wrong...
- */
-public class RootItemCollection extends VersionControlledItemCollection {
-
- private static Logger log = Logger.getLogger(RootItemCollection.class);
-
- /**
- * Create a new RootItemCollection.
- *
- * @param locator
- * @param session
- */
- protected RootItemCollection(DavResourceLocator locator, DavSession session, DavResourceFactory factory) {
- super(locator, session, factory);
- }
-
- //----------------------------------------------< DavResource interface >---
- /**
- * Returns the name of the workspace the underlaying root item forms part of.
- *
- * @return The workspace name
- * @see org.apache.jackrabbit.webdav.DavResource#getDisplayName()
- * @see javax.jcr.Workspace#getName()
- */
- public String getDisplayName() {
- return getLocator().getWorkspaceName();
- }
-
- /**
- * Retrieve the collection that has all root item / workspace collections
- * as internal members.
- *
- * @see org.apache.jackrabbit.webdav.DavResource#getCollection()
- */
- public DavResource getCollection() {
- DavResource collection = null;
- // create location with 'null' values for workspace-path and resource-path
- DavResourceLocator parentLoc = getLocator().getFactory().createResourceLocator(getLocator().getPrefix(), null, null);
- try {
- collection = createResourceFromLocator(parentLoc);
- } catch (DavException e) {
- log.error("Unexpected error while retrieving collection: " + e.getMessage());
- }
- return collection;
- }
-
- public void setProperty(DavProperty property) throws DavException {
- if (ItemResourceConstants.JCR_NAMESPACES.equals(property.getName())) {
- // todo: register and unregister namespaces
- } else {
- super.setProperty(property);
- }
- }
-
- //--------------------------------------------------------------------------
- protected void initProperties() {
- super.initProperties();
- try {
- // init workspace specific properties
- NamespaceRegistry nsReg = getRepositorySession().getWorkspace().getNamespaceRegistry();
- String[] prefixes = nsReg.getPrefixes();
- Element[] nsElems = new Element[prefixes.length];
- for (int i = 0; i < prefixes.length; i++) {
- Element elem = new Element(XML_NAMESPACE, NAMESPACE);
- elem.addContent(new Element(XML_NSPREFIX).setText(prefixes[i]));
- elem.addContent(new Element(XML_NSURI)).setText(nsReg.getURI(prefixes[i]));
- nsElems[i] = elem;
- }
- properties.add(new DefaultDavProperty(ItemResourceConstants.JCR_NAMESPACES, nsElems, false));
- } catch (RepositoryException e) {
- log.error("Failed to access NamespaceRegistry from the session/workspace: " + e.getMessage());
- }
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/VersionControlledItemCollection.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/VersionControlledItemCollection.java
deleted file mode 100644
index 34f4ba11fa7..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/VersionControlledItemCollection.java
+++ /dev/null
@@ -1,582 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.property.*;
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.version.*;
-import org.apache.jackrabbit.webdav.version.report.*;
-
-import javax.jcr.*;
-import javax.jcr.observation.*;
-import javax.jcr.observation.EventListener;
-import javax.jcr.version.Version;
-import javax.jcr.version.VersionHistory;
-import java.util.List;
-
-/**
- * VersionControlledItemCollection represents a JCR node item and
- * covers all functionality related to versioning of {@link Node}s.
- *
- * @see Node
- */
-public class VersionControlledItemCollection extends DefaultItemCollection
- implements VersionControlledResource {
-
- private static Logger log = Logger.getLogger(VersionControlledItemCollection.class);
-
- /**
- * Create a new VersionControlledItemCollection.
- *
- * @param locator
- * @param session
- */
- public VersionControlledItemCollection(DavResourceLocator locator, DavSession session, DavResourceFactory factory) {
- super(locator, session, factory);
- if (exists() && !(item instanceof Node)) {
- throw new IllegalArgumentException("A collection resource can not be constructed from a Property item.");
- }
- }
-
- //----------------------------------------------< DavResource interface >---
- /**
- * Return a comma separated string listing the supported method names.
- *
- * @return the supported method names.
- * @see org.apache.jackrabbit.webdav.DavResource#getSupportedMethods()
- */
- public String getSupportedMethods() {
- StringBuffer sb = new StringBuffer(super.getSupportedMethods());
- // Versioning support
- sb.append(", ").append(VersionableResource.METHODS);
- if (this.isVersionControlled()) {
- try {
- if (((Node)item).isCheckedOut()) {
- sb.append(", ").append(VersionControlledResource.methods_checkedOut);
- } else {
- sb.append(", ").append(VersionControlledResource.methods_checkedIn);
- }
- } catch (RepositoryException e) {
- // should not occur.
- log.error(e.getMessage());
- }
- }
- return sb.toString();
- }
-
- //--------------------------------< VersionControlledResource interface >---
- /**
- * Adds version control to this resource. If the resource is already under
- * version control, this method has no effect.
- *
- * @throws org.apache.jackrabbit.webdav.DavException if this resource does not
- * exist yet or if an error occurs while making the underlaying node versionable.
- * @see org.apache.jackrabbit.webdav.version.VersionableResource#addVersionControl()
- */
- public void addVersionControl() throws DavException {
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
- if (!isVersionControlled()) {
- try {
- ((Node)item).addMixin(MIX_VERSIONABLE);
- item.save();
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- } // else: is already version controlled -> ignore
- }
-
- /**
- * Calls {@link javax.jcr.Node#checkin()} on the underlaying repository node.
- *
- * @throws org.apache.jackrabbit.webdav.DavException
- * @see org.apache.jackrabbit.webdav.version.VersionControlledResource#checkin()
- */
- public String checkin() throws DavException {
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
- if (!isVersionControlled()) {
- throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- }
- try {
- Version v = ((Node) item).checkin();
- DavResourceLocator loc = getLocator();
- String versionHref = loc.getFactory().createResourceLocator(loc.getPrefix(), loc.getWorkspacePath(), v.getPath()).getHref(true);
- return versionHref;
- } catch (RepositoryException e) {
- // UnsupportedRepositoryException should not occur
- throw new JcrDavException(e);
- }
- }
-
- /**
- * Calls {@link javax.jcr.Node#checkout()} on the underlaying repository node.
- *
- * @throws org.apache.jackrabbit.webdav.DavException
- * @see org.apache.jackrabbit.webdav.version.VersionControlledResource#checkout()
- */
- public void checkout() throws DavException {
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
- if (!isVersionControlled()) {
- throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- }
- try {
- ((Node) item).checkout();
- } catch (RepositoryException e) {
- // UnsupportedRepositoryException should not occur
- throw new JcrDavException(e);
- }
- }
-
- /**
- * Not implemented. Always throws a DavException with error code
- * {@link org.apache.jackrabbit.webdav.DavServletResponse#SC_NOT_IMPLEMENTED}.
- *
- * @throws org.apache.jackrabbit.webdav.DavException
- * @see org.apache.jackrabbit.webdav.version.VersionControlledResource#uncheckout()
- */
- public void uncheckout() throws DavException {
- throw new DavException(DavServletResponse.SC_NOT_IMPLEMENTED);
- }
-
- /**
- * Perform an update on this resource. Depending on the format of the updateInfo
- * this is translated to one of the following methods defined by the JCR API:
- *
- * Limitation: note that the MultiStatus returned by this method
- * will not list any nodes that have been removed due to an Uuid conflict.
- *
- * @param updateInfo
- * @return
- * @throws org.apache.jackrabbit.webdav.DavException
- * @see org.apache.jackrabbit.webdav.version.VersionControlledResource#update(org.apache.jackrabbit.webdav.version.UpdateInfo)
- * @todo with jcr the node must not be versionable in order to perform Node.update.
- */
- public MultiStatus update(UpdateInfo updateInfo) throws DavException {
- if (updateInfo == null) {
- throw new DavException(DavServletResponse.SC_BAD_REQUEST, "Valid update request body required.");
- }
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
-
- MultiStatus ms = new MultiStatus();
- try {
- Node node = (Node)item;
- boolean removeExisting = updateInfo.getUpdateElement().getChild(XML_REMOVEEXISTING, NAMESPACE) != null;
-
- // register eventListener in order to be able to report the modified resources.
- EventListener el = new EListener(updateInfo.getPropertyNameSet(), ms);
- registerEventListener(el, node.getPath());
-
- // perform the update/restore according to the update info
- if (updateInfo.getVersionHref() != null) {
- VersionHistory vh = node.getVersionHistory();
- String[] hrefs = updateInfo.getVersionHref();
- Version[] versions = new Version[hrefs.length];
- for (int i = 0; i < hrefs.length; i++) {
- versions[i] = vh.getVersion(getResourceName(hrefs[i], true));
- }
- if (versions.length == 1) {
- String relPath = updateInfo.getUpdateElement().getChildText(XML_RELPATH, NAMESPACE);
- if (relPath == null) {
- node.restore(versions[0], removeExisting);
- } else {
- node.restore(versions[0], relPath, removeExisting);
- }
- } else {
- getRepositorySession().getWorkspace().restore(versions, removeExisting);
- }
- } else if (updateInfo.getLabelName() != null) {
- String[] labels = updateInfo.getLabelName();
- if (labels.length == 1) {
- node.restoreByLabel(labels[0], removeExisting);
- } else {
- Version[] vs = new Version[labels.length];
- VersionHistory vh = node.getVersionHistory();
- for (int i = 0; i < labels.length; i++) {
- vs[i] = vh.getVersionByLabel(labels[i]);
- }
- getRepositorySession().getWorkspace().restore(vs, removeExisting);
- }
- } else if (updateInfo.getWorkspaceHref() != null) {
- String workspaceName = getResourceName(updateInfo.getWorkspaceHref(), true);
- node.update(workspaceName);
- } else {
- throw new DavException(DavServletResponse.SC_BAD_REQUEST, "Invalid update request body.");
- }
-
- // unregister the event listener again
- unregisterEventListener(el);
-
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- return ms;
- }
-
- /**
- * Merge the repository node represented by this resource according to the
- * information present in the given {@link MergeInfo} object.
- *
- * @param mergeInfo
- * @return MultiStatus reccording all repository items affected
- * by this merge call.
- * @throws org.apache.jackrabbit.webdav.DavException
- * @see org.apache.jackrabbit.webdav.version.VersionControlledResource#merge(org.apache.jackrabbit.webdav.version.MergeInfo)
- * @see Node#merge(String, boolean)
- * @todo with jcr the node must not be versionable in order to perform Node.merge
- */
- public MultiStatus merge(MergeInfo mergeInfo) throws DavException {
- if (mergeInfo == null) {
- throw new DavException(DavServletResponse.SC_BAD_REQUEST);
- }
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
-
- MultiStatus ms = new MultiStatus();
- try {
- Node node = (Node)item;
-
- // register eventListener in order to be able to report the modifications.
- EventListener el = new EListener(mergeInfo.getPropertyNameSet(), ms);
- registerEventListener(el, node.getPath());
-
- String workspaceName = getResourceName(mergeInfo.getSourceHref(), true);
- node.merge(workspaceName, !mergeInfo.isNoAutoMerge());
-
- // unregister the event listener again
- unregisterEventListener(el);
-
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
-
- return ms;
- }
-
- /**
- * Resolve the merge conflicts according to the value of the {@link #AUTO_MERGE_SET DAV:auto-merge-set}
- * property present in the specified DavPropertySets.
- *
- * @param setProperties
- * @param removePropertyNames
- * @throws org.apache.jackrabbit.webdav.DavException
- * @see VersionControlledResource#resolveMergeConflict(DavPropertySet, DavPropertyNameSet)
- * @see Node#doneMerge(Version)
- * @see Node#cancelMerge(Version)
- */
- public void resolveMergeConflict(DavPropertySet setProperties,
- DavPropertyNameSet removePropertyNames) throws DavException {
-
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
- if (!isVersionControlled()) {
- throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- }
-
- try {
- Node n = (Node)item;
- if (removePropertyNames.contains(AUTO_MERGE_SET)) {
- // retrieve the current jcr:mergeFailed property values
- if (!((Node)item).hasProperty(PROP_MERGEFAILED)) {
- throw new DavException(DavServletResponse.SC_CONFLICT, "Attempt to resolve non-existing merge conflicts.");
- }
- Value[] mergeFailed = ((Node)item).getProperty(PROP_MERGEFAILED).getValues();
-
- // resolve all remaining merge conflicts with 'cancel'
- for (int i = 0; i < mergeFailed.length; i++) {
- n.cancelMerge((Version)getRepositorySession().getNodeByUUID(mergeFailed[i].getString()));
- }
- // adjust removeProperty set
- removePropertyNames.remove(AUTO_MERGE_SET);
-
- } else if (setProperties.contains(AUTO_MERGE_SET) && setProperties.contains(PREDECESSOR_SET)){
- // retrieve the current jcr:mergeFailed property values
- if (!((Node)item).hasProperty(PROP_MERGEFAILED)) {
- throw new DavException(DavServletResponse.SC_CONFLICT, "Attempt to resolve non-existing merge conflicts.");
- }
- Value[] mergeFailed = ((Node)item).getProperty(PROP_MERGEFAILED).getValues();
-
-
- // check which mergeFailed entries have been removed from the
- // auto-merge-set (cancelMerge) and have been moved over to the
- // predecessor set (doneMerge)
- List mergeset = new HrefProperty(setProperties.get(AUTO_MERGE_SET)).getHrefs();
- List predecSet = new HrefProperty(setProperties.get(PREDECESSOR_SET)).getHrefs();
-
- Session session = getRepositorySession();
- for (int i = 0; i < mergeFailed.length; i++) {
- // build version-href from each entry in the jcr:mergeFailed property
- Version version = (Version) session.getNodeByUUID(mergeFailed[i].getString());
- String href = this.getLocatorFromItem(version).getHref(true);
-
- // Test if that version has been removed from the merge-set.
- // thus indicating that the merge-conflict needs to be resolved.
- if (!mergeset.contains(href)) {
- // Test if the 'href' has been moved over to the
- // predecessor-set (thus 'doneMerge' is appropriate) or
- // if it is not present in the predecessor set and the
- // the conflict is resolved by 'cancelMerge'.
- if (predecSet.contains(href)) {
- n.doneMerge(version);
- } else {
- n.cancelMerge(version);
- }
- }
- }
- // adjust setProperty set
- setProperties.remove(AUTO_MERGE_SET);
- setProperties.remove(PREDECESSOR_SET);
- } else {
- // setPropertySet and removePropertySet do not ask for resolving merge conflicts */
- log.debug("setProperties and removeProperties sets do not request for merge conflict resolution.");
- }
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- }
-
- /**
- * Modify the labels present with the versions of this resource.
- *
- * @param labelInfo
- * @throws DavException
- * @see VersionHistory#addVersionLabel(String, String, boolean)
- * @see VersionHistory#removeVersionLabel(String)
- */
- public void label(LabelInfo labelInfo) throws DavException {
- if (labelInfo == null) {
- throw new DavException(DavServletResponse.SC_BAD_REQUEST, "Valid label request body required.");
- }
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
-
- try {
- if (!isVersionControlled() || ((Node)item).isCheckedOut()) {
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED, "A LABEL request may only be applied to a version-controlled, checked-in resource.");
- }
- DavResource[] resArr = this.getReferenceResources(CHECKED_IN);
- if (resArr.length == 1 && resArr[0] instanceof VersionResource) {
- ((VersionResource)resArr[0]).label(labelInfo);
- } else {
- throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR, "DAV:checked-in property on '" + getHref() + "' did not point to a single VersionResource.");
- }
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- }
-
- /**
- * Returns the {@link VersionHistory} associated with the repository node.
- * If the node is not versionable an exception is thrown.
- *
- * @return the {@link VersionHistoryResource} associated with this resource.
- * @throws org.apache.jackrabbit.webdav.DavException
- * @see org.apache.jackrabbit.webdav.version.VersionControlledResource#getVersionHistory()
- * @see javax.jcr.Node#getVersionHistory()
- */
- public VersionHistoryResource getVersionHistory() throws DavException {
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
-
- try {
- VersionHistory vh = ((Node)item).getVersionHistory();
- DavResourceLocator loc = getLocatorFromItem(vh);
- return (VersionHistoryResource) createResourceFromLocator(loc);
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- }
-
- //--------------------------------------------------------------------------
- /**
- * Define the set of reports supported by this resource.
- *
- * @see SupportedReportSetProperty
- */
- protected void initSupportedReports() {
- super.initSupportedReports();
- if (exists()) {
- supportedReports.addReportType(ReportType.LOCATE_BY_HISTORY);
- if (this.isVersionControlled()) {
- supportedReports.addReportType(ReportType.VERSION_TREE);
- }
- }
- }
-
- /**
- * Fill the property set for this resource.
- */
- protected void initProperties() {
- super.initProperties();
- if (exists()) {
- Node n = (Node)item;
- // properties defined by RFC 3253 for version-controlled resources
- if (isVersionControlled()) {
- // workspace property already set in AbstractResource.initProperties()
- try {
- // DAV:version-history (computed)
- String vhHref = getLocatorFromResourcePath(n.getVersionHistory().getPath()).getHref(true);
- properties.add(new HrefProperty(VERSION_HISTORY, vhHref, true));
-
- // DAV:auto-version property: there is no auto version, explicit CHECKOUT is required.
- properties.add(new DefaultDavProperty(AUTO_VERSION, null, false));
-
- String baseVHref = getLocatorFromResourcePath(n.getBaseVersion().getPath()).getHref(true);
- if (n.isCheckedOut()) {
- // DAV:checked-out property (protected)
- properties.add(new HrefProperty(CHECKED_OUT, baseVHref, true));
-
- // DAV:predecessors property
- if (n.hasProperty(PROP_PREDECESSORS)) {
- Value[] predec = n.getProperty(PROP_PREDECESSORS).getValues();
- addHrefProperty(PREDECESSOR_SET, predec, false);
- }
- // DAV:auto-merge-set property. NOTE: the DAV:merge-set
- // never occurs, because merging without bestEffort flag
- // being set results in an exception on failure.
- if (n.hasProperty(PROP_MERGEFAILED)) {
- ReferenceValue[] mergeFailed = (ReferenceValue[]) n.getProperty(PROP_MERGEFAILED).getValues();
- addHrefProperty(AUTO_MERGE_SET, mergeFailed, false);
- }
- // todo: checkout-fork, checkin-fork
- } else {
- // DAV:checked-in property (protected)
- properties.add(new HrefProperty(CHECKED_IN, baseVHref, true));
- }
- } catch (RepositoryException e) {
- log.error(e.getMessage());
- }
- }
- }
- }
-
- /**
- * Add a {@link org.apache.jackrabbit.webdav.property.HrefProperty} with the specified property name and values.
- *
- * @param name
- * @param values Array of {@link ReferenceValue}s.
- * @param isProtected
- * @throws javax.jcr.ValueFormatException
- * @throws IllegalStateException
- * @throws javax.jcr.RepositoryException
- */
- private void addHrefProperty(DavPropertyName name, Value[] values,
- boolean isProtected)
- throws ValueFormatException, IllegalStateException, RepositoryException {
- Node[] nodes = new Node[values.length];
- for (int i = 0; i < values.length; i++) {
- nodes[i] = getRepositorySession().getNodeByUUID(values[i].getString());
- }
- addHrefProperty(name, nodes, isProtected);
- }
-
- /**
- * @return true, if this resource represents an existing repository node
- * that has the mixin nodetype 'mix:versionable' set.
- */
- private boolean isVersionControlled() {
- boolean vc = false;
- if (exists()) {
- try {
- vc = ((Node) item).isNodeType("mix:versionable");
- } catch (RepositoryException e) {
- log.warn(e.getMessage());
- }
- }
- return vc;
- }
-
- /**
- * Register the specified event listener with the observation manager present
- * the repository session.
- *
- * @param listener
- * @param nodePath
- * @throws javax.jcr.RepositoryException
- */
- private void registerEventListener(EventListener listener, String nodePath) throws RepositoryException {
- getRepositorySession().getWorkspace().getObservationManager().addEventListener(listener, EListener.ALL_EVENTS, nodePath, true, null, null, false);
- }
-
- /**
- * Unregister the specified event listener with the observation manager present
- * the repository session.
- *
- * @param listener
- * @throws javax.jcr.RepositoryException
- */
- private void unregisterEventListener(EventListener listener) throws RepositoryException {
- getRepositorySession().getWorkspace().getObservationManager().removeEventListener(listener);
- }
-
- //------------------------------------------------------< inner classes >---
- /**
- * Simple EventListener that creates a new {@link org.apache.jackrabbit.webdav.MultiStatusResponse} object
- * for each event and adds it to the specified {@link org.apache.jackrabbit.webdav.MultiStatus}.
- */
- private class EListener implements EventListener {
-
- private static final int ALL_EVENTS = Event.NODE_ADDED | Event.NODE_REMOVED | Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED | Event.PROPERTY_REMOVED;
-
- private final DavPropertyNameSet propNameSet;
- private MultiStatus ms;
-
- private EListener(DavPropertyNameSet propNameSet, MultiStatus ms) {
- this.propNameSet = propNameSet;
- this.ms = ms;
- }
-
- /**
- * @see EventListener#onEvent(javax.jcr.observation.EventIterator)
- */
- public void onEvent(EventIterator events) {
- while (events.hasNext()) {
- try {
- Event e = events.nextEvent();
- String itemPath = e.getPath();
- DavResourceLocator loc = getLocatorFromResourcePath(itemPath);
- DavResource res = createResourceFromLocator(loc);
- ms.addResponse(new MultiStatusResponse(res, propNameSet));
-
- } catch (DavException e) {
- // should not occur
- log.error("Error while building MultiStatusResponse from Event: " + e.getMessage());
- } catch (RepositoryException e) {
- // should not occur
- log.error("Error while building MultiStatusResponse from Event: " + e.getMessage());
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/lock/JcrActiveLock.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/lock/JcrActiveLock.java
deleted file mode 100644
index 78e3fbb662d..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/lock/JcrActiveLock.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi.lock;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.DavConstants;
-import org.apache.jackrabbit.webdav.spi.ItemResourceConstants;
-import org.apache.jackrabbit.webdav.lock.*;
-
-import javax.jcr.lock.Lock;
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-/**
- * JcrActiveLock wraps a {@link Lock JCR lock} object.
- */
-public class JcrActiveLock extends AbstractActiveLock implements ActiveLock, DavConstants {
-
- private static Logger log = Logger.getLogger(JcrActiveLock.class);
-
- private final Lock lock;
- private final boolean sessionScoped;
-
- /**
- * Create a new ActiveLock object with type '{@link Type#WRITE write}'
- * and scope '{@link Scope#EXCLUSIVE exclusive}'.
- *
- * @param lock
- */
- public JcrActiveLock(Lock lock) {
- this (lock, false);
- }
-
- /**
- * Create a new ActiveLock object with type '{@link Type#WRITE write}'
- * and scope '{@link Scope#EXCLUSIVE exclusive}'.
- *
- * @param lock
- */
- public JcrActiveLock(Lock lock, boolean sessionScoped) {
- if (lock == null) {
- throw new IllegalArgumentException("Can not create a ActiveLock with a 'null' argument.");
- }
- this.lock = lock;
- this.sessionScoped = sessionScoped;
- }
-
- /**
- * Return true if the given lock token equals the token holding that lock.
- *
- * @param lockToken
- * @return true if the given lock token equals this locks token.
- * @see org.apache.jackrabbit.webdav.lock.ActiveLock#isLockedByToken(String)
- */
- public boolean isLockedByToken(String lockToken) {
- if (lockToken != null && lockToken.equals(getToken())) {
- return true;
- }
- return false;
- }
-
- /**
- * @see ActiveLock#isExpired()
- */
- public boolean isExpired() {
- return lock.isLive();
- }
-
- /**
- * Return the lock token if the {@link javax.jcr.Session} that optained the lock
- * is the lock token holder, null otherwise.
- * NOTE: currently the token generated by the underlaying JCR repository
- * is not checked for compliance with RFC 2518 ("OpaqueLockToken-URI = "opaquelocktoken:"
- * UUID [Extension] ; The UUID production is the string representation of a
- * UUID, as defined in [ISO-11578]. Note that white space (LWS) is not allowed
- * between elements of this production.").
- *
- * @see ActiveLock#getToken()
- */
- public String getToken() {
- return lock.getLockToken();
- }
-
- /**
- * @see ActiveLock#getOwner()
- */
- public String getOwner() {
- return lock.getLockOwner();
- }
-
- /**
- * @see ActiveLock#setOwner(String)
- */
- public void setOwner(String owner) {
- throw new UnsupportedOperationException("setOwner is not implemented");
- }
-
- /**
- * Always returns {@link DavConstants#UNDEFINED_TIMEOUT} for the timeout
- * cannot be retrieved from the JCR lock.
- *
- * @see ActiveLock#getTimeout()
- * @see DavConstants#UNDEFINED_TIMEOUT
- */
- public long getTimeout() {
- return UNDEFINED_TIMEOUT;
- }
-
- /**
- * @see ActiveLock#setTimeout(long)
- */
- public void setTimeout(long timeout) {
- throw new UnsupportedOperationException("setTimeout is not implemented");
- }
-
- /**
- * @see ActiveLock#isDeep()
- */
- public boolean isDeep() {
- boolean isDeep = true;
- Node n = lock.getNode();
- try {
- // find out about deepness. if node does not hold the lock its deep anyway
- if (n.holdsLock() && n.hasProperty("jcr:lockIsDeep")) {
- isDeep = n.getProperty("jcr:lockIsDeep").getBoolean();
- }
- } catch (RepositoryException e) {
- // ignore and keep default depth settings
- }
- return isDeep;
- }
-
- /**
- * @see ActiveLock#setIsDeep(boolean)
- */
- public void setIsDeep(boolean isDeep) {
- throw new UnsupportedOperationException("setIsDeep is not implemented");
- }
-
- /**
- * Always returns {@link Type#WRITE}.
- *
- * @return {@link Type#WRITE}
- * @see ActiveLock#getType()
- */
- public Type getType() {
- return Type.WRITE;
- }
-
- /**
- * @return The scope of this lock, which may either by an {@link Scope#EXCLUSIVE exclusive}
- * or {@link ItemResourceConstants#EXCLUSIVE_SESSION exlusive session scoped}
- * lock.
- * @see ActiveLock#getScope()
- */
- public Scope getScope() {
- return (sessionScoped) ? ItemResourceConstants.EXCLUSIVE_SESSION : Scope.EXCLUSIVE;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/lock/SessionScopedLockEntry.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/lock/SessionScopedLockEntry.java
deleted file mode 100644
index 03898e3d252..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/lock/SessionScopedLockEntry.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi.lock;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.lock.LockEntry;
-import org.apache.jackrabbit.webdav.lock.Scope;
-import org.apache.jackrabbit.webdav.lock.Type;
-import org.apache.jackrabbit.webdav.lock.AbstractLockEntry;
-import org.apache.jackrabbit.webdav.spi.ItemResourceConstants;
-
-/**
- * SessionScopedLockEntry represents the 'session-scoped' write
- * lock as defined by JCR.
- */
-public class SessionScopedLockEntry extends AbstractLockEntry {
-
- private static Logger log = Logger.getLogger(SessionScopedLockEntry.class);
-
- /**
- * @return always returns {@link Type#WRITE write}.
- * @see LockEntry#getType()
- */
- public Type getType() {
- return Type.WRITE;
- }
-
- /**
- * @return returns {@link ItemResourceConstants#EXCLUSIVE_SESSION}.
- * @see LockEntry#getScope()
- */
- public Scope getScope() {
- return ItemResourceConstants.EXCLUSIVE_SESSION;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/nodetype/ItemDefImpl.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/nodetype/ItemDefImpl.java
deleted file mode 100644
index f6962c5421d..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/nodetype/ItemDefImpl.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 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.jackrabbit.webdav.spi.nodetype;
-
-import org.apache.log4j.Logger;
-import org.jdom.Element;
-
-import javax.jcr.nodetype.ItemDef;
-import javax.jcr.nodetype.NodeType;
-import javax.jcr.version.OnParentVersionAction;
-
-/**
- * ItemDefImpl...
- */
-abstract public class ItemDefImpl implements ItemDef, NodeTypeConstants {
-
- private static Logger log = Logger.getLogger(ItemDefImpl.class);
-
- private final String name;
- private NodeType declaringNodeType;
- private final boolean isAutoCreated;
- private final boolean isMandatory;
- private final boolean isProtected;
- private final int onParentVersion;
-
- ItemDefImpl(ItemDef definition) {
- if (definition == null) {
- throw new IllegalArgumentException("PropDef argument can not be null");
- }
-
- name = definition.getName();
- declaringNodeType = definition.getDeclaringNodeType();
- isAutoCreated = definition.isAutoCreate();
- isMandatory = definition.isMandatory();
- isProtected = definition.isProtected();
- onParentVersion = definition.getOnParentVersion();
- }
-
- public NodeType getDeclaringNodeType() {
- return declaringNodeType;
- }
-
- public String getName() {
- return name;
- }
-
- public boolean isAutoCreate() {
- return isAutoCreated;
- }
-
- public boolean isMandatory() {
- return isMandatory;
- }
-
- public int getOnParentVersion() {
- return onParentVersion;
- }
-
- public boolean isProtected() {
- return isProtected;
- }
-
- //-------------------------------------< implementation specific method >---
- /**
- * Returns the Xml representation of a {@link ItemDef} object.
- *
- * @return Xml representation of the specified {@link ItemDef def}.
- */
- public Element toXml() {
- Element elem = new Element(getElementName());
- elem.setAttribute(ATTR_NAME, getName());
- elem.setAttribute(ATTR_AUTOCREATE, Boolean.toString(isAutoCreate()));
- elem.setAttribute(ATTR_MANDATORY, Boolean.toString(isMandatory()));
- elem.setAttribute(ATTR_ONPARENTVERSION, OnParentVersionAction.nameFromValue(getOnParentVersion()));
- elem.setAttribute(ATTR_PROTECTED, Boolean.toString(isProtected()));
- return elem;
- }
-
- public abstract String getElementName();
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/nodetype/NodeDefImpl.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/nodetype/NodeDefImpl.java
deleted file mode 100644
index 84f8585f380..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/nodetype/NodeDefImpl.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 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.jackrabbit.webdav.spi.nodetype;
-
-import org.apache.log4j.Logger;
-import org.jdom.Element;
-
-import javax.jcr.nodetype.NodeDef;
-import javax.jcr.nodetype.NodeType;
-
-/**
- * NodeDefImpl...
- */
-public final class NodeDefImpl extends ItemDefImpl implements NodeDef {
-
- private static Logger log = Logger.getLogger(NodeDefImpl.class);
-
- private final NodeType[] requiredPrimaryTypes;
- private final NodeType defaultPrimaryType;
- private final boolean allowSameNameSibs;
-
- private NodeDefImpl(NodeDef definition) {
- super(definition);
-
- requiredPrimaryTypes = definition.getRequiredPrimaryTypes();
- defaultPrimaryType = definition.getDefaultPrimaryType();
- allowSameNameSibs = definition.allowSameNameSibs();
- }
-
- public static NodeDefImpl create(NodeDef definition) {
- if (definition instanceof NodeDefImpl) {
- return (NodeDefImpl) definition;
- } else {
- return new NodeDefImpl(definition);
- }
- }
-
- //--------------------------------------------------< NodeDef interface >---
- public NodeType[] getRequiredPrimaryTypes() {
- return requiredPrimaryTypes;
- }
-
- public NodeType getDefaultPrimaryType() {
- return defaultPrimaryType;
- }
-
- public boolean allowSameNameSibs() {
- return allowSameNameSibs;
- }
-
- //-------------------------------------< implementation specific method >---
- public Element toXml() {
- Element elem = super.toXml();
-
- elem.setAttribute(ATTR_SAMENAMESIBS, Boolean.toString(allowSameNameSibs()));
-
- // defaultPrimaryType can be 'null'
- NodeType defaultPrimaryType = getDefaultPrimaryType();
- if (defaultPrimaryType != null) {
- elem.setAttribute(ATTR_DEFAULTPRIMARYTYPE, defaultPrimaryType.getName());
- }
- // reqPrimaryTypes: minimal set is nt:base.
- NodeType[] nts = getRequiredPrimaryTypes();
- Element reqPrimaryTypes = new Element(XML_REQUIREDPRIMARYTYPES);
- for (int i = 0; i < nts.length; i++) {
- reqPrimaryTypes.addContent(new Element(XML_REQUIREDPRIMARYTYPE).setText(nts[i].getName()));
- }
- elem.addContent(reqPrimaryTypes);
-
- return elem;
- }
-
- public String getElementName() {
- return XML_CHILDNODEDEF;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/nodetype/NodeTypeConstants.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/nodetype/NodeTypeConstants.java
deleted file mode 100644
index 2450e30db2e..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/nodetype/NodeTypeConstants.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi.nodetype;
-
-import org.jdom.Namespace;
-import org.apache.jackrabbit.webdav.spi.ItemResourceConstants;
-
-/**
- * NodeTypeConstants used to represent nodetype definitions in
- * Xml.
- *
- * @see javax.jcr.nodetype.NodeType
- * @todo intercaps only for consistency with jackrabbit... webdav rfcs never use intercaps.
- */
-public interface NodeTypeConstants {
-
- public static final Namespace NAMESPACE = ItemResourceConstants.NAMESPACE;
-
- public static final String XML_NODETYPENAME = "nodetypename";
-
- public static final String XML_REPORT_ALLNODETYPES = "allnodetypes";
- public static final String XML_REPORT_MIXINNODETYPES = "mixinnodetypes";
- public static final String XML_REPORT_PRIMARYNODETYPES = "primarynodetypes";
-
- // report response
- /** Name of the node type definition root element. */
- public static final String XML_NODETYPES = "nodeTypes";
-
- /** Name of the node type definition element. */
- public static final String XML_NODETYPE = "nodeType";
-
- /** Name of the isMixin attribute. */
- public static final String ATTR_ISMIXIN = "isMixin";
-
- /** Name of the hasOrderableChildNodes attribute. */
- public static final String ATTR_HASORDERABLECHILDNODES = "hasOrderableChildNodes";
-
- /** Name of the primary item name attribute. */
- public static final String ATTR_PRIMARYITEMNAME = "primaryItemName";
-
- /** Name of the supertypes element. */
- public static final String XML_SUPERTYPES = "supertypes";
-
- /** Name of the supertype element. */
- public static final String XML_SUPERTYPE = "supertype";
-
- /** Name of the child node definition element. */
- public static final String XML_CHILDNODEDEF = "childNodeDef";
-
- /** Name of the property definition element. */
- public static final String XML_PROPERTYDEF = "propertyDef";
-
- /** Name of the name attribute. */
- public static final String ATTR_NAME = "name";
-
- /** Name of the autoCreate attribute. */
- public static final String ATTR_AUTOCREATE = "autoCreate";
-
- /** Name of the mandatory attribute. */
- public static final String ATTR_MANDATORY = "mandatory";
-
- /** Name of the onParentVersion attribute. */
- public static final String ATTR_ONPARENTVERSION = "onParentVersion";
-
- /** Name of the protected attribute. */
- public static final String ATTR_PROTECTED = "protected";
-
- /** Name of the required type attribute. */
- public static final String ATTR_REQUIREDTYPE = "requiredType";
-
- /** Name of the value constraints element. */
- public static final String XML_VALUECONSTRAINTS = "valueConstraints";
-
- /** Name of the value constraint element. */
- public static final String XML_VALUECONSTRAINT = "valueConstraint";
-
- /** Name of the default values element. */
- public static final String XML_DEFAULTVALUES = "defaultValues";
-
- /** Name of the default value element. */
- public static final String XML_DEFAULTVALUE = "defaultValue";
-
- /** Name of the multiple attribute. */
- public static final String ATTR_MULTIPLE = "multiple";
-
- /** Name of the required primary types element. */
- public static final String XML_REQUIREDPRIMARYTYPES = "requiredPrimaryTypes";
-
- /** Name of the required primary type element. */
- public static final String XML_REQUIREDPRIMARYTYPE = "requiredPrimaryType";
-
- /** Name of the default primary type attribute. */
- public static final String ATTR_DEFAULTPRIMARYTYPE = "defaultPrimaryType";
-
- /** Name of the sameNameSibs attribute. */
- public static final String ATTR_SAMENAMESIBS = "sameNameSibs";
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/nodetype/NodeTypeElement.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/nodetype/NodeTypeElement.java
deleted file mode 100644
index a3a77ab5faa..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/nodetype/NodeTypeElement.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi.nodetype;
-
-import org.apache.log4j.Logger;
-import org.jdom.Element;
-
-import javax.jcr.nodetype.NodeType;
-
-/**
- * NodeTypeElement...
- */
-public class NodeTypeElement extends Element implements NodeTypeConstants {
-
- private static Logger log = Logger.getLogger(NodeTypeElement.class);
-
- public NodeTypeElement(NodeType nt) {
- super(XML_NODETYPE, NodeTypeConstants.NAMESPACE);
- addNodeTypeNameElement(nt.getName());
- }
-
- public NodeTypeElement(Element ntElement) {
- super(XML_NODETYPE, NodeTypeConstants.NAMESPACE);
- if (!XML_NODETYPE.equals(ntElement.getName())) {
- throw new IllegalArgumentException("jcr:nodetype element expected.");
- }
- addNodeTypeNameElement(ntElement.getChildText(XML_NODETYPENAME, NodeTypeConstants.NAMESPACE));
- }
-
- private void addNodeTypeNameElement(String nodeTypeName) {
- if (nodeTypeName != null) {
- addContent(new Element(XML_NODETYPENAME, NodeTypeConstants.NAMESPACE).setText(nodeTypeName));
- }
- }
-
- public String getNodeTypeName() {
- return getChildText(XML_NODETYPENAME, NodeTypeConstants.NAMESPACE);
- }
-
- public static NodeTypeElement[] create(NodeType[] nts) {
- NodeTypeElement[] elems = new NodeTypeElement[nts.length];
- for (int i = 0; i < nts.length; i++) {
- elems[i] = new NodeTypeElement(nts[i]);
- }
- return elems;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/nodetype/NodeTypeProperty.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/nodetype/NodeTypeProperty.java
deleted file mode 100644
index bbb4edbb5bd..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/nodetype/NodeTypeProperty.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi.nodetype;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.property.DavPropertyName;
-import org.apache.jackrabbit.webdav.property.DavProperty;
-import org.apache.jackrabbit.webdav.property.AbstractDavProperty;
-import org.jdom.Element;
-
-import javax.jcr.nodetype.NodeType;
-import java.util.*;
-
-/**
- * NodeTypeProperty...
- */
-public class NodeTypeProperty extends AbstractDavProperty {
-
- private static Logger log = Logger.getLogger(NodeTypeProperty.class);
-
- private final NodeTypeElement[] value;
-
- public NodeTypeProperty(DavPropertyName name, NodeType nodeType, boolean isProtected) {
- super(name, isProtected);
- value = new NodeTypeElement[] {new NodeTypeElement(nodeType)};
- }
-
- public NodeTypeProperty(DavPropertyName name, NodeType[] nodeTypes, boolean isProtected) {
- super(name, isProtected);
- value = NodeTypeElement.create(nodeTypes);
- }
-
- /**
- * Create a new NodeTypeProperty from the specified general
- * DavProperty object.
- *
- * @param property
- * @throws IllegalArgumentException if the content of the specified property
- * contains elements other than {@link NodeTypeConstants#XML_NODETYPE}.
- */
- public NodeTypeProperty(DavProperty property) {
- super(property.getName(), property.isProtected());
-
- if (property.getValue() instanceof List) {
- List ntElemList = new ArrayList();
- Iterator it = ((List) property.getValue()).iterator();
- while (it.hasNext()) {
- Object content = it.next();
- if (content instanceof Element) {
- ntElemList.add(new NodeTypeElement((Element)content));
- }
- }
- value = (NodeTypeElement[]) ntElemList.toArray(new NodeTypeElement[ntElemList.size()]);
- } else if (property.getValue() instanceof Element) {
- NodeTypeElement ntElem = new NodeTypeElement((Element)property.getValue());
- value = new NodeTypeElement [] {ntElem};
- } else {
- value = new NodeTypeElement[0];
- }
- }
-
- /**
- * Return a set of nodetype names present in this property.
- *
- * @return set of nodetype names
- */
- public Set getNodeTypeNames() {
- HashSet names = new HashSet();
- Object val = getValue();
- if (val instanceof NodeTypeElement[]) {
- NodeTypeElement[] elems = (NodeTypeElement[])val;
- for (int i = 0; i < elems.length; i++) {
- String ntName = elems[i].getNodeTypeName();
- if (ntName != null) {
- names.add(ntName);
- }
- }
- }
- return names;
- }
-
- /**
- * Returns the value of this property which is an array of {@link NodeTypeElement}
- * objects.
- *
- * @return an array of {@link NodeTypeElement}s
- */
- public Object getValue() {
- return value;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/nodetype/PropertyDefImpl.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/nodetype/PropertyDefImpl.java
deleted file mode 100644
index c96bce48171..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/nodetype/PropertyDefImpl.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 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.jackrabbit.webdav.spi.nodetype;
-
-import org.apache.log4j.Logger;
-import org.jdom.Element;
-
-import javax.jcr.nodetype.PropertyDef;
-import javax.jcr.Value;
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-
-/**
- * PropertyDefImpl...
- */
-public final class PropertyDefImpl extends ItemDefImpl implements PropertyDef {
-
- private static Logger log = Logger.getLogger(PropertyDefImpl.class);
-
- private final int type;
- private final String[] valueConstraints;
- private final Value[] defaultValues;
- private final boolean isMultiple;
-
- private PropertyDefImpl(PropertyDef definition) {
- super(definition);
-
- type = definition.getRequiredType();
- valueConstraints = definition.getValueConstraints();
- defaultValues = definition.getDefaultValues();
- isMultiple = definition.isMultiple();
- }
-
- public static PropertyDefImpl create(PropertyDef definition) {
- if (definition instanceof PropertyDefImpl) {
- return (PropertyDefImpl)definition;
- } else {
- return new PropertyDefImpl(definition);
- }
- }
-
- public int getRequiredType() {
- return type;
- }
-
- public String[] getValueConstraints() {
- return valueConstraints;
- }
-
- public Value[] getDefaultValues() {
- return defaultValues;
- }
-
- public boolean isMultiple() {
- return isMultiple;
- }
-
- //-------------------------------------< implementation specific method >---
- public Element toXml() {
- Element elem = super.toXml();
-
- elem.setAttribute(ATTR_MULTIPLE, Boolean.toString(isMultiple()));
- elem.setAttribute(ATTR_REQUIREDTYPE, PropertyType.nameFromValue(getRequiredType()));
-
- // default values may be 'null'
- Value[] values = getDefaultValues();
- if (values != null) {
- Element dvElement = new Element(XML_DEFAULTVALUES);
- for (int i = 0; i < values.length; i++) {
- try {
- Element valElem = new Element(XML_DEFAULTVALUE).setText(values[i].getString());
- dvElement.addContent(valElem);
- } catch (RepositoryException e) {
- // should not occur
- log.error(e.getMessage());
- }
- }
- elem.addContent(dvElement);
- }
- // value constraints array is never null.
- Element constrElem = new Element(XML_VALUECONSTRAINTS);
- String[] constraints = getValueConstraints();
- for (int i = 0; i < constraints.length; i++) {
- constrElem.addContent(new Element(XML_VALUECONSTRAINT).setText(constraints[i]));
- }
- elem.addContent(constrElem);
-
- return elem;
- }
-
- public String getElementName() {
- return XML_PROPERTYDEF;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/observation/SubscriptionImpl.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/observation/SubscriptionImpl.java
deleted file mode 100644
index 7ceb4f474b1..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/observation/SubscriptionImpl.java
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi.observation;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.DavResourceLocator;
-import org.apache.jackrabbit.webdav.DavConstants;
-import org.apache.jackrabbit.webdav.observation.*;
-import org.apache.jackrabbit.webdav.util.XmlUtil;
-import org.apache.jackrabbit.core.util.uuid.UUID;
-import org.jdom.Element;
-
-import javax.jcr.observation.*;
-import javax.jcr.observation.EventListener;
-import javax.jcr.RepositoryException;
-import java.util.*;
-
-/**
- * The Subscription class encapsulates a single subscription with
- * the following responsibilities:
- *
Providing access to the subscription info,
- *
Recording events this subscription is interested in,
- *
Providing access to the events.
- *
- */
-public class SubscriptionImpl implements Subscription, ObservationConstants, EventListener {
-
- private static Logger log = Logger.getLogger(SubscriptionImpl.class);
- private static final long DEFAULT_TIMEOUT = 300000; // 5 minutes
-
- private SubscriptionInfo info;
-
- private final DavResourceLocator locator;
- private final String subscriptionId = UUID.randomUUID().toString();
- private final List eventBundles = new ArrayList();
-
- /**
- * Create a new Subscription with the given {@link SubscriptionInfo}
- * and {@link org.apache.jackrabbit.webdav.observation.ObservationResource resource}.
- *
- * @param info
- * @param resource
- */
- public SubscriptionImpl(SubscriptionInfo info, ObservationResource resource) {
- setInfo(info);
- locator = resource.getLocator();
- }
-
- /**
- * Returns the id of this subscription.
- *
- * @return subscriptionId
- */
- public String getSubscriptionId() {
- return subscriptionId;
- }
-
- /**
- * Return the Xml representation of this Subscription as required
- * for the {@link org.apache.jackrabbit.webdav.observation.SubscriptionDiscovery} webdav property that in included
- * in the response body of a sucessful SUBSCRIBE request or as part of a
- * PROPFIND response.
- *
- * @return Xml representation
- */
- public Element toXml() {
- Element subscr = new Element(XML_SUBSCRIPTION, NAMESPACE);
- Element[] elems = info.toXml();
- for (int i = 0; i < elems.length; i++) {
- subscr.addContent(elems[i]);
- }
-
- Element id = new Element(XML_SUBSCRIPTIONID);
- id.addContent(XmlUtil.hrefToXml(subscriptionId));
- subscr.addContent(id);
- return subscr;
- }
-
- /**
- * Modify the {@link SubscriptionInfo} for this subscription.
- *
- * @param info
- */
- void setInfo(SubscriptionInfo info) {
- this.info = info;
- // validate the timeout and adjust value, if it is invalid or missing
- long timeout = info.getTimeOut();
- if (timeout == DavConstants.UNDEFINED_TIMEOUT) {
- info.setTimeOut(DEFAULT_TIMEOUT);
- }
- }
-
- /**
- * @return JCR compliant integer representation of the event types defined
- * for this {@link SubscriptionInfo}.
- */
- int getEventTypes() {
- Iterator xmlTypes = info.getEventTypes().iterator();
- int eventTypes = 0;
- while (xmlTypes.hasNext()) {
- eventTypes |= nametoTypeConstant(((Element)xmlTypes.next()).getName());
- }
- return eventTypes;
- }
-
- /**
- * @return a String array with size > 0 or null
- */
- String[] getUuidFilters() {
- return info.getFilters(XML_UUID);
- }
-
- /**
- * @return a String array with size > 0 or null
- */
- String[] getNodetypeNameFilters() {
- return info.getFilters(XML_NODETYPE_NAME);
- }
-
- /**
- *
- * @return true if a {@link ObservationConstants#XML_NOLOCAL} element
- * is present in the {@link SubscriptionInfo}.
- */
- boolean isNoLocal() {
- return info.isNoLocal();
- }
-
- /**
- * @return true if this subscription is intended to be deep.
- */
- boolean isDeep() {
- return info.isDeep();
- }
-
- /**
- * @return the locator of the {@link ObservationResource resource} this
- * Subscription was requested for.
- */
- DavResourceLocator getLocator() {
- return locator;
- }
-
- /**
- * Returns true if this Subscription matches the given
- * resource.
- *
- * @param resource
- * @return true if this Subscription matches the given
- * resource.
- */
- boolean isSubscribedToResource(ObservationResource resource) {
- return locator.equals(resource.getLocator());
- }
-
- /**
- * Returns true if this Subscription is expired and therefore
- * stopped recording events.
- *
- * @return true if this Subscription is expired
- */
- boolean isExpired() {
- return System.currentTimeMillis() > info.getTimeOut() + System.currentTimeMillis();
- }
-
- /**
- * Returns a {@link org.apache.jackrabbit.webdav.observation.EventDiscovery} object listing all events that were
- * recorded since the last call to this method and clears the list of event
- * bundles.
- *
- * @return object listing all events that were recorded.
- * @see #onEvent(EventIterator)
- */
- synchronized EventDiscovery discoverEvents() {
- EventDiscovery ed = new EventDiscovery();
- Iterator it = eventBundles.iterator();
- while (it.hasNext()) {
- EventBundle eb = (EventBundle) it.next();
- ed.addEventBundle(eb.toXml());
- }
- // clear list
- eventBundles.clear();
- return ed;
- }
-
- //--------------------------------------------< EventListener interface >---
- /**
- * Records the events passed as a new event bundle in order to make them
- * available with the next {@link #discoverEvents()} request.
- *
- * @param events to be recorded.
- * @see EventListener#onEvent(EventIterator)
- * @see #discoverEvents()
- */
- public synchronized void onEvent(EventIterator events) {
- // TODO: correct not to accept events after expiration? without unsubscribing?
- if (!isExpired()) {
- eventBundles.add(new EventBundle(events));
- }
- }
-
- //--------------------------------------------------------------------------
- /**
- * Static utility method in order to convert the types defined by
- * {@link javax.jcr.observation.Event} into their Xml representation.
- *
- * @param jcrEventType
- * @return Xml representation of the event type.
- */
- static Element typeConstantToXml(int jcrEventType) {
- String eventName;
- switch (jcrEventType) {
- case Event.NODE_ADDED:
- eventName = EVENT_NODEADDED;
- break;
- case Event.NODE_REMOVED:
- eventName = EVENT_NODEREMOVED;
- break;
- case Event.PROPERTY_ADDED:
- eventName = EVENT_PROPERTYADDED;
- break;
- case Event.PROPERTY_CHANGED:
- eventName = EVENT_PROPERTYCHANGED;
- break;
- default:
- //Event.PROPERTY_REMOVED:
- eventName = EVENT_PROPERTYREMOVED;
- break;
- }
- return new Element(eventName, NAMESPACE);
- }
-
- /**
- * Static utility method to convert an event type name as present in the
- * Xml request body into the corresponding constant defined by
- * {@link javax.jcr.observation.Event}.
- *
- * @param eventTypeName
- * @return event type as defined by {@link javax.jcr.observation.Event}.
- * @throws IllegalArgumentException if the given element cannot be translated
- * to any of the events defined by {@link javax.jcr.observation.Event}.
- */
- static int nametoTypeConstant(String eventTypeName) {
- int eType;
- if (EVENT_NODEADDED.equals(eventTypeName)) {
- eType = Event.NODE_ADDED;
- } else if (EVENT_NODEREMOVED.equals(eventTypeName)) {
- eType = Event.NODE_REMOVED;
- } else if (EVENT_PROPERTYADDED.equals(eventTypeName)) {
- eType = Event.PROPERTY_ADDED;
- } else if (EVENT_PROPERTYCHANGED.equals(eventTypeName)) {
- eType = Event.PROPERTY_CHANGED;
- } else if (EVENT_PROPERTYREMOVED.equals(eventTypeName)) {
- eType = Event.PROPERTY_REMOVED;
- } else {
- throw new IllegalArgumentException("Invalid event type: "+eventTypeName);
- }
- return eType;
- }
-
- /**
- * Inner class EventBundle encapsulats an event bundle as
- * recorded {@link SubscriptionImpl#onEvent(EventIterator) on event} and
- * provides the possibility to retrieve the Xml representation of the
- * bundle and the events included in order to respond to a POLL request.
- *
- * @see SubscriptionImpl#discoverEvents()
- */
- private class EventBundle {
-
- private final EventIterator events;
-
- private EventBundle(EventIterator events) {
- this.events = events;
- }
-
- private Element toXml() {
- Element bundle = new Element(XML_EVENTBUNDLE, NAMESPACE);
- while (events.hasNext()) {
- Event event = events.nextEvent();
-
- Element eventElem = new Element(XML_EVENT, NAMESPACE);
- // href
- String eHref = "";
- try {
- boolean isCollection = (event.getType() == Event.NODE_ADDED || event.getType() == Event.NODE_REMOVED);
- eHref = locator.getFactory().createResourceLocator(locator.getPrefix(), locator.getWorkspacePath(), event.getPath()).getHref(isCollection);
- } catch (RepositoryException e) {
- // should not occur....
- log.error(e.getMessage());
- }
- eventElem.addContent(XmlUtil.hrefToXml(eHref));
- // eventtype
- Element eType = new Element(XML_EVENTTYPE, NAMESPACE).addContent(typeConstantToXml(event.getType()));
- eventElem.addContent(eType);
- // user id
- Element eUserId = new Element(XML_EVENTUSERID, NAMESPACE).setText(event.getUserId());
- eventElem.addContent(eUserId);
- }
- return bundle;
- }
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/observation/SubscriptionManagerImpl.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/observation/SubscriptionManagerImpl.java
deleted file mode 100644
index 5048c9894fc..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/observation/SubscriptionManagerImpl.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi.observation;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.spi.JcrDavException;
-import org.apache.jackrabbit.webdav.observation.*;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.observation.ObservationManager;
-import java.util.*;
-
-/**
- * SubscriptionManager collects all subscriptions requested, handles
- * the subscription timeout and provides METHODS to discover subscriptions
- * present on a given resource as well as events for an specific subscription.
- *
- * @todo make sure all expired subscriptions are removed!
- */
-public class SubscriptionManagerImpl implements SubscriptionManager {
-
- private static Logger log = Logger.getLogger(SubscriptionManager.class);
-
- /**
- * Map containing all {@link org.apache.jackrabbit.webdav.observation.Subscription subscriptions}.
- */
- private final SubscriptionMap subscriptions = new SubscriptionMap();
-
- /**
- * Retrieve the {@link org.apache.jackrabbit.webdav.observation.SubscriptionDiscovery} object for the given
- * resource. Note, that the discovery object will be empty if there are
- * no subscriptions present.
- *
- * @param resource
- * @todo is it correct to return subscriptions made by another session?
- */
- public SubscriptionDiscovery getSubscriptionDiscovery(ObservationResource resource) {
- Subscription[] subsForResource = subscriptions.getByPath(resource.getLocator());
- return new SubscriptionDiscovery(subsForResource);
- }
-
- /**
- * Create a new Subscription or update an existing Subscription
- * and add it as eventlistener to the {@link javax.jcr.observation.ObservationManager}.
- *
- * @param info
- * @param subscriptionId
- * @param resource
- * @return Subscription that has been added to the {@link javax.jcr.observation.ObservationManager}
- * @throws DavException if the subscription fails
- */
- public Subscription subscribe(SubscriptionInfo info, String subscriptionId,
- ObservationResource resource)
- throws DavException {
-
- SubscriptionImpl subscription;
- DavSession session = resource.getSession();
- if (subscriptionId == null) {
- // new subscription
- subscription = new SubscriptionImpl(info, resource);
- registerSubscription(subscription, session);
-
- // ajust references to this subscription
- subscriptions.put(subscription.getSubscriptionId(), subscription);
- session.addReference(subscription.getSubscriptionId());
- } else {
- // refresh/modify existing one
- subscription = validate(subscriptionId, resource);
- subscription.setInfo(info);
- registerSubscription(subscription, session);
- }
- return subscription;
- }
-
- /**
- * Register the event listener defined by the given subscription to the
- * repository's observation manager.
- *
- * @param subscription
- * @param session
- * @throws DavException
- */
- private void registerSubscription(SubscriptionImpl subscription, DavSession session)
- throws DavException {
- try {
- ObservationManager oMgr = session.getRepositorySession().getWorkspace().getObservationManager();
- oMgr.addEventListener(subscription, subscription.getEventTypes(),
- subscription.getLocator().getResourcePath(), subscription.isDeep(),
- subscription.getUuidFilters(),
- subscription.getNodetypeNameFilters(),
- subscription.isNoLocal());
- } catch (RepositoryException e) {
- log.error("Unable to register eventlistener: "+e.getMessage());
- throw new JcrDavException(e);
- }
- }
-
- /**
- * Unsubscribe the Subscription with the given id and remove it
- * from the {@link javax.jcr.observation.ObservationManager} as well as
- * from the internal map.
- *
- * @param subscriptionId
- * @param resource
- * @throws DavException
- */
- public void unsubscribe(String subscriptionId, ObservationResource resource)
- throws DavException {
-
- SubscriptionImpl subs = validate(subscriptionId, resource);
- unregisterSubscription(subs, resource.getSession());
- }
-
- /**
- * Remove the event listener defined by the specified subscription from
- * the repository's observation manager.
- *
- * @param subscription
- * @param session
- * @throws DavException
- */
- private void unregisterSubscription(SubscriptionImpl subscription,
- DavSession session) throws DavException {
- try {
- session.getRepositorySession().getWorkspace().getObservationManager().removeEventListener(subscription);
- String sId = subscription.getSubscriptionId();
-
- // clean up any references
- subscriptions.remove(sId);
- session.removeReference(sId);
-
- } catch (RepositoryException e) {
- log.error("Unable to remove eventlistener: "+e.getMessage());
- throw new JcrDavException(e);
- }
- }
-
- /**
- * Retrieve all event bundles accumulated since for the subscription specified
- * by the given id.
- *
- * @param subscriptionId
- * @param resource
- * @return object encapsulating the events.
- */
- public EventDiscovery poll(String subscriptionId, ObservationResource resource)
- throws DavException {
-
- SubscriptionImpl subs = validate(subscriptionId, resource);
- return subs.discoverEvents();
- }
-
- /**
- * Validate the given subscription id. The validation will fail under the following
- * conditions:
- *
The subscription with the given id does not exist,
- *
DavResource path does not match the subscription id,
- *
The subscription with the given id is already expired.
- *
- *
- * @param subscriptionId
- * @param resource
- * @return Subscription with the given id.
- * @throws DavException if an error occured while retrieving the Subscription
- */
- private SubscriptionImpl validate(String subscriptionId, ObservationResource resource)
- throws DavException {
-
- SubscriptionImpl subs;
- if (subscriptions.contains(subscriptionId)) {
- subs = (SubscriptionImpl) subscriptions.get(subscriptionId);
- if (!subs.isSubscribedToResource(resource)) {
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED, "Attempt to operate on subscription with invalid resource path.");
- }
- if (subs.isExpired()) {
- unregisterSubscription(subs, resource.getSession());
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED, "Attempt to operate on expired subscription.");
- }
- return subs;
- } else {
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED, "Attempt to modify or to poll for non-existing subscription.");
- }
- }
-
- /**
- * Private inner class SubscriptionMap that allows for quick
- * access by resource path as well as by subscription id.
- */
- private class SubscriptionMap {
-
- private HashMap subscriptions = new HashMap();
- private HashMap paths = new HashMap();
-
- private boolean contains(String subscriptionId) {
- return subscriptions.containsKey(subscriptionId);
- }
-
- private Subscription get(String subscriptionId) {
- return (Subscription) subscriptions.get(subscriptionId);
- }
-
- private void put(String subscriptionId, SubscriptionImpl subscription) {
- subscriptions.put(subscriptionId, subscription);
- DavResourceLocator key = subscription.getLocator();
- Set idSet;
- if (paths.containsKey(key)) {
- idSet = (Set) paths.get(key);
- } else {
- idSet = new HashSet();
- paths.put(key, idSet);
- }
- if (!idSet.contains(subscriptionId)) {
- idSet.add(subscriptionId);
- }
- }
-
- private void remove(String subscriptionId) {
- SubscriptionImpl sub = (SubscriptionImpl) subscriptions.remove(subscriptionId);
- ((Set)paths.get(sub.getLocator())).remove(subscriptionId);
- }
-
- private Subscription[] getByPath(DavResourceLocator locator) {
- Set idSet = (Set) paths.get(locator);
- if (idSet != null && !idSet.isEmpty()) {
- Iterator idIterator = idSet.iterator();
- Subscription[] subsForResource = new Subscription[idSet.size()];
- int i = 0;
- while (idIterator.hasNext()) {
- subsForResource[i] = (Subscription) subscriptions.get(idIterator.next());
- }
- return subsForResource;
- } else {
- return new Subscription[0];
- }
- }
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/package.html b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/package.html
deleted file mode 100644
index 17e97edbf40..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/package.html
+++ /dev/null
@@ -1,3 +0,0 @@
-
-Contains JCR specific implementations.
-
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/property/LengthsProperty.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/property/LengthsProperty.java
deleted file mode 100644
index 7984f7cecb9..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/property/LengthsProperty.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
-* Copyright 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.jackrabbit.webdav.spi.property;
-
-import org.apache.jackrabbit.webdav.property.AbstractDavProperty;
-import org.apache.jackrabbit.webdav.spi.ItemResourceConstants;
-import org.jdom.Element;
-
-/**
- * LengthsProperty extends {@link org.apache.jackrabbit.webdav.property.DavProperty} providing
- * utilities to handle the multiple lengths of the property item represented
- * by this resource.
- */
-public class LengthsProperty extends AbstractDavProperty implements ItemResourceConstants {
-
- private final Element[] value;
-
- /**
- * Create a new LengthsProperty from the given long array.
- *
- * @param lengths as retrieved from the JCR property
- */
- public LengthsProperty(long[] lengths) {
- super(JCR_LENGTHS, false);
-
- Element[] elems = new Element[lengths.length];
- for (int i = 0; i < lengths.length; i++) {
- elems[i] = new Element(XML_LENGTH, ItemResourceConstants.NAMESPACE);
- elems[i].addContent(String.valueOf(lengths[i]));
- }
- this.value = elems;
- }
-
- /**
- * Returns an array of {@link Element}s representing the value of this
- * property.
- *
- * @return an array of {@link Element}s
- */
- public Object getValue() {
- return value;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/property/ValuesProperty.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/property/ValuesProperty.java
deleted file mode 100644
index c580b89bd1f..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/property/ValuesProperty.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
-* Copyright 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.jackrabbit.webdav.spi.property;
-
-import org.apache.jackrabbit.webdav.property.AbstractDavProperty;
-import org.apache.jackrabbit.webdav.property.DavProperty;
-import org.apache.jackrabbit.webdav.spi.ItemResourceConstants;
-import org.apache.jackrabbit.core.util.ValueHelper;
-import org.jdom.Element;
-
-import javax.jcr.Value;
-import javax.jcr.ValueFormatException;
-import javax.jcr.RepositoryException;
-import java.util.List;
-import java.util.Iterator;
-import java.util.ArrayList;
-
-/**
- * ValuesProperty extends {@link org.apache.jackrabbit.webdav.property.DavProperty} providing
- * utilities to handle the multiple values of the property item represented
- * by this resource.
- */
-public class ValuesProperty extends AbstractDavProperty implements ItemResourceConstants {
-
- private final Element[] value;
-
- /**
- * Wrap the specified DavProperty in a new ValuesProperty.
- *
- * @param property
- */
- public ValuesProperty(DavProperty property) {
- super(JCR_VALUES, false);
-
- if (!JCR_VALUES.equals(property.getName())) {
- throw new IllegalArgumentException("ValuesProperty may only be created with a property that has name="+JCR_VALUES.getName());
- }
-
- Element[] elems = new Element[0];
- if (property.getValue() instanceof List) {
- Iterator elemIt = ((List)property.getValue()).iterator();
- ArrayList valueElements = new ArrayList();
- while (elemIt.hasNext()) {
- Object el = elemIt.next();
- /* make sure, only Elements with name 'value' are used for
- * the 'value' field. any other content (other elements, text,
- * comment etc.) is ignored. NO bad-request/conflict error is
- * thrown.
- */
- if (el instanceof Element && "value".equals(((Element)el).getName())) {
- valueElements.add(el);
- }
- }
- /* fill the 'value' with the valid 'value' elements found before */
- elems = (Element[])valueElements.toArray(new Element[valueElements.size()]);
- } else {
- new IllegalArgumentException("ValuesProperty may only be created with a property that has a list of 'value' elements as content.");
- }
- // finally set the value to the DavProperty
- value = elems;
- }
-
- /**
- * Create a new ValuesProperty from the given {@link javax.jcr.Value Value
- * array}.
- *
- * @param values Array of Value objects as obtained from the JCR property.
- */
- public ValuesProperty(Value[] values) throws ValueFormatException, RepositoryException {
- super(JCR_VALUES, false);
-
- Element[] propValue = new Element[values.length];
- for (int i = 0; i < values.length; i++) {
- propValue[i] = new Element(XML_VALUE, ItemResourceConstants.NAMESPACE);
- propValue[i].addContent(values[i].getString());
- }
- // finally set the value to the DavProperty
- value = propValue;
- }
-
- /**
- * Converts the value of this property to a {@link javax.jcr.Value value array}.
- * Please note, that the convertion is done by using the {@link org.apache.jackrabbit.core.util.ValueHelper}
- * class that is not part of the JSR170 API.
- *
- * @return Array of Value objects
- * @throws RepositoryException
- */
- public Value[] getValues(int propertyType) throws ValueFormatException, RepositoryException {
- Element[] propValue = (Element[])getValue();
- Value[] values = new Value[propValue.length];
- for (int i = 0; i < propValue.length; i++) {
- values[i] = ValueHelper.convert(propValue[i].getText(), propertyType);
- }
- return values;
- }
-
- /**
- * Returns an array of {@link Element}s representing the value of this
- * property.
- *
- * @return an array of {@link Element}s
- */
- public Object getValue() {
- return value;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/search/SearchResourceImpl.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/search/SearchResourceImpl.java
deleted file mode 100644
index c9c26228946..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/search/SearchResourceImpl.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi.search;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.search.SearchResource;
-import org.apache.jackrabbit.webdav.search.QueryGrammerSet;
-import org.apache.jackrabbit.webdav.search.SearchRequest;
-import org.apache.jackrabbit.webdav.spi.JcrDavException;
-import org.apache.jackrabbit.webdav.spi.ItemResourceConstants;
-
-import javax.jcr.*;
-import javax.jcr.query.*;
-
-/**
- * SearchResourceImpl...
- */
-public class SearchResourceImpl implements SearchResource, ItemResourceConstants {
-
- private static Logger log = Logger.getLogger(SearchResourceImpl.class);
-
- private final DavSession session;
- private final DavResourceLocator locator;
-
- public SearchResourceImpl(DavResourceLocator locator, DavSession session) {
- this.session = session;
- this.locator = locator;
- }
-
- //-------------------------------------------< SearchResource interface >---
- /**
- * @see SearchResource#getQueryGrammerSet()
- */
- public QueryGrammerSet getQueryGrammerSet() {
- QueryGrammerSet qgs;
- try {
- QueryManager qMgr = session.getRepositorySession().getWorkspace().getQueryManager();
- String[] langs = qMgr.getSupportedQueryLanguages();
- qgs = new QueryGrammerSet(langs);
- } catch (RepositoryException e) {
- qgs = new QueryGrammerSet(new String[0]);
- }
- return qgs;
- }
-
- /**
- * Execute the query defined by the given sRequest.
- *
- * @see SearchResource#search(org.apache.jackrabbit.webdav.search.SearchRequest)
- */
- public MultiStatus search(SearchRequest sRequest) throws DavException {
- try {
- Query q = getQuery(sRequest);
- QueryResult qR = q.execute();
- return queryResultToMultiStatus(qR);
-
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- }
-
- /**
- * Create a query from the information present in the sRequest
- * object. The following JCR specific logic is applied:
- *
- *
If the requested resource represents a node with nodetype nt:query, the
- * request body is ignored and the query defined with the node is executed
- * instead.
- *
If the requested resource does not represent an existing item, the
- * specified query is persisted by calling {@link Query#save(String)}.
- *
- * @param sRequest defining the query to be executed
- * @return Query object.
- * @throws InvalidQueryException if the query defined by sRequest is invalid
- * @throws RepositoryException the query manager cannot be accessed or if
- * another error occurs.
- * @throws DavException if sRequest is null and
- * the underlaying repository item is not an nt:query node or if an error
- * occurs when calling {@link Query#save(String)}/
- */
- private Query getQuery(SearchRequest sRequest)
- throws InvalidQueryException, RepositoryException, DavException {
-
- Node rootNode = session.getRepositorySession().getRootNode();
- QueryManager qMgr = session.getRepositorySession().getWorkspace().getQueryManager();
- String resourcePath = locator.getResourcePath();
-
- // test if query is defined by requested repository node
- if (!rootNode.getPath().equals(resourcePath)) {
- String qNodeRelPath = resourcePath.substring(1);
- if (rootNode.hasNode(qNodeRelPath)) {
- Node qNode = rootNode.getNode(qNodeRelPath);
- if (qNode.isNodeType("nt:query")) {
- return qMgr.getQuery(qNode);
- }
- }
- }
-
- Query q;
- if (sRequest != null) {
- q = qMgr.createQuery(sRequest.getQuery(), sRequest.getLanguageName());
- } else {
- throw new DavException(DavServletResponse.SC_BAD_REQUEST, resourcePath + " is not a nt:query node -> searchRequest body required.");
- }
-
- /* test if resource path does not exist -> thus indicating that
- the query must be made persistent by calling Query.save(String) */
- if (!session.getRepositorySession().itemExists(resourcePath)) {
- try {
- q.save(resourcePath);
- } catch (RepositoryException e) {
- // ItemExistsException should never occur.
- new JcrDavException(e);
- }
- }
- return q;
- }
-
- /**
- * Build a MultiStatus object from the specified query result.
- *
- * @param qResult QueryResult as obtained from {@link javax.jcr.query.Query#execute()}.
- * @return MultiStatus object listing the query result in
- * Webdav compatible form.
- * @throws RepositoryException
- */
- private MultiStatus queryResultToMultiStatus(QueryResult qResult)
- throws RepositoryException {
- MultiStatus ms = new MultiStatus();
-
- String[] propertyNames = qResult.getPropertyNames();
- RowIterator rowIter = qResult.getRows();
- while (rowIter.hasNext()) {
- Row row = rowIter.nextRow();
- Value[] values = row.getValues();
- String nodePath = values[0].getString();
-
- // create a new ms-response for each row of the result set
- DavResourceLocator loc = locator.getFactory().createResourceLocator(locator.getPrefix(), locator.getWorkspacePath(), nodePath);
- String nodeHref = loc.getHref(true);
- MultiStatusResponse resp = new MultiStatusResponse(nodeHref);
- // add a search-result-property for each value column
- for (int i = 0; i < values.length; i++) {
- resp.add(new SearchResultProperty(propertyNames[i], values[i]));
- }
- ms.addResponse(resp);
- }
- return ms;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/search/SearchResultProperty.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/search/SearchResultProperty.java
deleted file mode 100644
index a45b2fdc41f..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/search/SearchResultProperty.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi.search;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.property.DavPropertyName;
-import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
-import org.apache.jackrabbit.webdav.spi.ItemResourceConstants;
-import org.jdom.Element;
-
-import javax.jcr.Value;
-import javax.jcr.RepositoryException;
-
-/**
- * SearchResultProperty...
- */
-public class SearchResultProperty extends DefaultDavProperty {
-
- private static Logger log = Logger.getLogger(SearchResultProperty.class);
-
- public static final DavPropertyName SEARCH_RESULT_PROPERTY = DavPropertyName.create("search-result-property", ItemResourceConstants.NAMESPACE);
-
- private final String propertyName;
-
- /**
- * Creates a new WebDAV property with the given namespace, name and value.
- * If the property is intended to be protected the isProtected flag must
- * be set to true.
- *
- * @param propertyName JCR property name
- * @param value String representation of the property
- */
- public SearchResultProperty(String propertyName, Value value) {
- super(SEARCH_RESULT_PROPERTY, value, true);
- this.propertyName = propertyName;
- }
-
- /**
- * Return the Xml representation.
- *
- *
- * new SearchResultProperty("bli", new StringValue("blivalue")).toXml()
- *
- * returns an element with the following form:
- *
- * <jcr:search-result-property>
- * <jcr:name>bli<jcr:name/>
- * <jcr:value>blivalue<jcr:value/>
- * </jcr:search-result-property>
- *
- *
- * @return the Xml representation
- * @see org.apache.jackrabbit.webdav.property.DavProperty#toXml()
- */
- public Element toXml() {
- Element elem = getName().toXml();
- elem.addContent(ItemResourceConstants.JCR_NAME.toXml().setText(propertyName));
- String valueStr = "";
- if (getValue() != null) {
- Value value = (Value) getValue();
- try {
- valueStr = value.getString();
- } catch (RepositoryException e) {
- log.error(e.getMessage());
- }
- }
- elem.addContent(ItemResourceConstants.JCR_VALUE.toXml().setText(valueStr));
- return elem;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/transaction/TxLockManagerImpl.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/transaction/TxLockManagerImpl.java
deleted file mode 100644
index 8e42d7afeac..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/transaction/TxLockManagerImpl.java
+++ /dev/null
@@ -1,666 +0,0 @@
-/*
- * Copyright 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.jackrabbit.webdav.spi.transaction;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.spi.*;
-import org.apache.jackrabbit.webdav.transaction.*;
-import org.apache.jackrabbit.webdav.util.Text;
-import org.apache.jackrabbit.webdav.lock.*;
-import org.apache.jackrabbit.core.XASession;
-
-import javax.jcr.*;
-import javax.transaction.xa.XAResource;
-import javax.transaction.xa.XAException;
-import javax.transaction.xa.Xid;
-import java.util.*;
-
-/**
- * TxLockManagerImpl manages locks with locktype
- * '{@link TransactionConstants#TRANSACTION jcr:transaction}'.
- *
- * todo: removing all expired locks
- * todo: 'local' and 'global' are not accurate terms in the given context > replace
- * todo: the usage of the 'global' transaction is not according to the JTA specification,
- * which explicitely requires any transaction present on a servlet to be completed before
- * the service method returns. Starting/completing transactions on the session object,
- * which is possible with the jackrabbit implementation is a hack.
- * todo: review of this transaction part is therefore required. Is there a use-case
- * for those 'global' transactions at all...
- */
-public class TxLockManagerImpl implements TxLockManager {
-
- private static Logger log = Logger.getLogger(TxLockManagerImpl.class);
-
- private TransactionMap map = new TransactionMap();
-
- /**
- * Create a new lock.
- *
- * @param lockInfo as present in the request body.
- * @param resource
- * @return the lock
- * @throws DavException if the lock could not be obtained.
- * @throws IllegalArgumentException if the resource is null or
- * does not implement {@link TransactionResource} interface.
- * @see LockManager#createLock(org.apache.jackrabbit.webdav.lock.LockInfo, org.apache.jackrabbit.webdav.DavResource)
- */
- public ActiveLock createLock(LockInfo lockInfo, DavResource resource)
- throws DavException {
- if (resource == null || !(resource instanceof TransactionResource)) {
- throw new IllegalArgumentException("Invalid resource");
- }
- return createLock(lockInfo, (TransactionResource)resource);
- }
-
- /**
- * Create a new lock.
- *
- * @param lockInfo
- * @param resource
- * @return the lock
- * @throws DavException if the request lock has the wrong lock type or if
- * the lock could not be obtained for any reason.
- */
- private synchronized ActiveLock createLock(LockInfo lockInfo, TransactionResource resource)
- throws DavException {
- if (!lockInfo.isDeep() || !TransactionConstants.TRANSACTION.equals(lockInfo.getType())) {
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED);
- }
-
- ActiveLock existing = getLock(lockInfo.getType(), lockInfo.getScope(), resource);
- if (existing != null) {
- throw new DavException(DavServletResponse.SC_LOCKED);
- }
- // TODO: check for locks on member resources is required as well for lock is always deep!
-
- Transaction tx = createTransaction(resource.getLocator(), lockInfo);
- tx.start(resource);
-
- // keep references to this lock
- addReferences(tx, getMap(resource), resource);
-
- return tx.getLock();
- }
-
- /**
- * Build the transaction object associated by the lock.
- *
- * @param locator
- * @param lockInfo
- * @return
- */
- private Transaction createTransaction(DavResourceLocator locator, LockInfo lockInfo) {
- if (TransactionConstants.GLOBAL.equals(lockInfo.getScope())) {
- return new GlobalTransaction(locator, new TxActiveLock(lockInfo));
- } else {
- return new LocalTransaction(locator, new TxActiveLock(lockInfo));
- }
- }
-
- /**
- * Refresh the lock indentified by the given lock token.
- *
- * @param lockInfo
- * @param lockToken
- * @param resource
- * @return the lock
- * @throws DavException
- * @throws IllegalArgumentException if the resource is null or
- * does not implement {@link TransactionResource} interface.
- * @see LockManager#refreshLock(org.apache.jackrabbit.webdav.lock.LockInfo, String, org.apache.jackrabbit.webdav.DavResource)
- */
- public ActiveLock refreshLock(LockInfo lockInfo, String lockToken,
- DavResource resource) throws DavException {
- if (resource == null || !(resource instanceof TransactionResource)) {
- throw new IllegalArgumentException("Invalid resource");
- }
- return refreshLock(lockInfo, lockToken, (TransactionResource)resource);
- }
-
- /**
- * Reset the timeout of the lock identified by the given lock token.
- *
- * @param lockInfo
- * @param lockToken
- * @param resource
- * @return
- * @throws DavException if the lockdid not exist or is expired.
- */
- private synchronized ActiveLock refreshLock(LockInfo lockInfo, String lockToken,
- TransactionResource resource) throws DavException {
-
- TransactionMap responsibleMap = getMap(resource);
- Transaction tx = responsibleMap.get(lockToken);
- if (tx == null) {
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED, "No valid transaction lock found for resource '" + resource.getResourcePath()+ "'");
- } else if (tx.getLock().isExpired()) {
- removeExpired(tx, responsibleMap, resource);
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED, "Transaction lock for resource '" + resource.getResourcePath()+ "' was already expired.");
- } else {
- tx.getLock().setTimeout(lockInfo.getTimeout());
- }
- return tx.getLock();
- }
-
- /**
- * Throws UnsupportedOperationException.
- *
- * @param lockToken
- * @param resource
- * @throws DavException
- * @see LockManager#releaseLock(String, org.apache.jackrabbit.webdav.DavResource)
- */
- public void releaseLock(String lockToken, DavResource resource)
- throws DavException {
- throw new UnsupportedOperationException("A transaction lock can only be release with a TransactionInfo object and a lock token.");
- }
-
- /**
- * Release the lock identified by the given lock token.
- *
- * @param lockInfo
- * @param lockToken
- * @param resource
- * @throws DavException
- */
- public synchronized void releaseLock(TransactionInfo lockInfo, String lockToken,
- TransactionResource resource) throws DavException {
- if (resource == null) {
- throw new IllegalArgumentException("Resource must not be null.");
- }
- TransactionMap responsibleMap = getMap(resource);
- Transaction tx = responsibleMap.get(lockToken);
-
- if (tx == null) {
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED, "No transaction lock found for resource '" + resource.getResourcePath()+ "'");
- } else if (tx.getLock().isExpired()) {
- removeExpired(tx, responsibleMap, resource);
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED, "Transaction lock for resource '" + resource.getResourcePath()+ "' was already expired.");
- } else {
- if (TransactionConstants.XML_COMMIT.equals(lockInfo.getStatus())) {
- tx.commit(resource);
- } else {
- tx.rollback(resource);
- }
- removeReferences(tx, responsibleMap, resource);
- }
- }
-
- /**
- * Always returns null
- *
- * @param type
- * @param scope
- * @param resource
- * @return null
- * @see #getLock(Type, Scope, TransactionResource)
- * @see LockManager#getLock(org.apache.jackrabbit.webdav.lock.Type, org.apache.jackrabbit.webdav.lock.Scope, org.apache.jackrabbit.webdav.DavResource)
- */
- public ActiveLock getLock(Type type, Scope scope, DavResource resource) {
- return null;
- }
-
- /**
- * Return the lock applied to the given resource or null
- *
- * @param type
- * @param scope
- * @param resource
- * @return lock applied to the given resource or null
- * @see LockManager#getLock(Type, Scope, DavResource)
- * todo: is it correct to return one that specific lock, the current session is token-holder of?
- */
- public ActiveLock getLock(Type type, Scope scope, TransactionResource resource) {
- ActiveLock lock = null;
- if (TransactionConstants.TRANSACTION.equals(type)) {
- String[] sessionTokens = resource.getSession().getRepositorySession().getLockTokens();
- int i = 0;
- while (lock == null && i < sessionTokens.length) {
- String lockToken = sessionTokens[i];
- lock = getLock(lockToken, scope, resource);
- i++;
- }
- }
- return lock;
- }
-
- /**
- * @param lockToken
- * @param resource
- * @return
- */
- private ActiveLock getLock(String lockToken, Scope scope, DavResource resource) {
- if (!(resource instanceof TransactionResource)) {
- log.info("");
- return null;
- }
-
- ActiveLock lock = null;
- Transaction tx = null;
- TransactionMap m = map;
- // check if main-map contains that txId
- if (m.containsKey(lockToken)) {
- tx = m.get(lockToken);
- } else {
- // look through all the nested tx-maps (i.e. global txs) for the given txId
- Iterator it = m.values().iterator();
- while (it.hasNext() && tx == null) {
- Transaction txMap = (Transaction) it.next();
- if (!txMap.isLocal()) {
- m = ((TransactionMap)txMap);
- if (m.containsKey(lockToken)) {
- tx = ((TransactionMap)txMap).get(lockToken);
- }
- }
- }
- }
-
- if (tx != null) {
- if (tx.getLock().isExpired()) {
- removeExpired(tx, m, (TransactionResource)resource);
- } else if (tx.appliesToResource(resource) && (scope == null || tx.getLock().getScope().equals(scope))) {
- lock = tx.getLock();
- }
- }
- return lock;
- }
-
- /**
- * Returns true if the given lock token belongs to a lock that applies to
- * the given resource, false otherwise. The token may either be retrieved
- * from the {@link DavConstants#HEADER_LOCK_TOKEN Lock-Token header} or
- * from the {@link TransactionConstants#HEADER_TRANSACTIONID TransactionId header}.
- *
- * @param token
- * @param resource
- * @return
- * @see LockManager#hasLock(String token, DavResource resource)
- */
- public boolean hasLock(String token, DavResource resource) {
- return getLock(token, null, resource) != null;
- }
-
- /**
- * Return the map that may contain a transaction lock for the given resource.
- * In case the resource provides a transactionId, the map must be a
- * repository transaction that is identified by the given id and which in
- * turn can act as map.
- *
- * @param resource
- * @return responsible map.
- * @throws DavException if no map could be retrieved.
- */
- private TransactionMap getMap(TransactionResource resource)
- throws DavException {
-
- String txKey = resource.getTransactionId();
- if (txKey == null) {
- return map;
- } else {
- if (!map.containsKey(txKey)) {
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED, "Transaction map '" + map + " does not contain a transaction with TransactionId '" + txKey + "'.");
- }
- Transaction tx = map.get(txKey);
- if (tx.isLocal()) {
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED, "TransactionId '" + txKey + "' points to a local transaction, that cannot act as transaction map");
- } else if (tx.getLock() != null && tx.getLock().isExpired()) {
- removeExpired(tx, map, resource);
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED, "Attempt to retrieve an expired global transaction.");
- }
- // tx is a global transaction that acts as map as well.
- return (TransactionMap)tx;
- }
- }
-
- /**
- * Rollbacks the specified transaction and releases the lock. This includes
- * the removal of all references.
- *
- * @param tx
- * @param responsibleMap
- * @param resource
- */
- private static void removeExpired(Transaction tx, TransactionMap responsibleMap,
- TransactionResource resource) {
- log.info("Removing expired transaction lock " + tx);
- try {
- tx.rollback(resource);
- removeReferences(tx, responsibleMap, resource);
- } catch (DavException e) {
- log.error("Error while removing expired transaction lock: " + e.getMessage());
- }
- }
-
- /**
- * Create the required references to the new transaction specified by tx.
- *
- * @param tx
- * @param responsibleMap
- * @param resource
- * @throws DavException
- */
- private static void addReferences(Transaction tx, TransactionMap responsibleMap,
- TransactionResource resource) throws DavException {
- log.info("Adding transactionId '" + tx.getId() + "' as session lock token.");
- resource.getSession().getRepositorySession().addLockToken(tx.getId());
-
- responsibleMap.put(tx.getId(), tx);
- resource.getSession().addReference(tx.getId());
- }
-
- /**
- * Remove all references to the specified transaction.
- *
- * @param tx
- * @param responsibleMap
- * @param resource
- */
- private static void removeReferences(Transaction tx, TransactionMap responsibleMap,
- TransactionResource resource) {
- log.info("Removing transactionId '" + tx.getId() + "' from session lock tokens.");
- resource.getSession().getRepositorySession().removeLockToken(tx.getId());
-
- responsibleMap.remove(tx.getId());
- resource.getSession().removeReference(tx.getId());
- }
- //------------------------------------------< inner classes, interfaces >---
- /**
- * Internal Transaction interface
- */
- private interface Transaction {
-
- TxActiveLock getLock();
-
- /**
- * @return the id of this transaction.
- */
- String getId();
-
- /**
- * @return path of the lock holding resource
- */
- String getResourcePath();
-
- /**
- * @param resource
- * @return true if the lock defined by this transaction applies to the
- * given resource, either due to the resource holding that lock or due
- * to a deep lock hold by any ancestor resource.
- */
- boolean appliesToResource(DavResource resource);
-
- /**
- * @return true if this transaction is used to allow for transient changes
- * on the underlaying repository, that may be persisted with the final
- * UNLOCK request only.
- */
- boolean isLocal();
-
- /**
- * Start this transaction.
- *
- * @param resource
- * @throws DavException if an error occurs.
- */
- void start(TransactionResource resource) throws DavException ;
-
- /**
- * Commit this transaction
- *
- * @param resource
- * @throws DavException if an error occurs.
- */
- void commit(TransactionResource resource) throws DavException ;
-
- /**
- * Rollback this transaction.
- *
- * @param resource
- * @throws DavException if an error occurs.
- */
- void rollback(TransactionResource resource) throws DavException ;
- }
-
- /**
- * Abstract transaction covering functionally to both implementations.
- */
- private abstract static class AbstractTransaction extends TransactionMap implements Transaction {
-
- private final DavResourceLocator locator;
- private final TxActiveLock lock;
-
- private AbstractTransaction(DavResourceLocator locator, TxActiveLock lock) {
- this.locator = locator;
- this.lock = lock;
- }
-
- /**
- * @see #getLock()
- */
- public TxActiveLock getLock() {
- return lock;
- }
-
- /**
- * @see #getId()
- */
- public String getId() {
- return lock.getToken();
- }
-
- /**
- * @see #getResourcePath()
- */
- public String getResourcePath() {
- return locator.getResourcePath();
- }
-
- /**
- * @see #appliesToResource(DavResource)
- */
- public boolean appliesToResource(DavResource resource) {
- if (locator.isSameWorkspace(resource.getLocator())) {
- String lockResourcePath = getResourcePath();
- String resPath = resource.getResourcePath();
-
- while (!"".equals(resPath)) {
- if (lockResourcePath.equals(resPath)) {
- return true;
- }
- resPath = Text.getRelativeParent(resPath, 1);
- }
- }
- return false;
- }
- }
-
- /**
- *
- */
- private final static class LocalTransaction extends AbstractTransaction {
-
- private LocalTransaction(DavResourceLocator locator, TxActiveLock lock) {
- super(locator, lock);
- }
-
- public boolean isLocal() {
- return true;
- }
-
- public void start(TransactionResource resource) throws DavException {
- // make sure, the given resource represents an existing repository item
- if (!resource.getSession().getRepositorySession().itemExists(getResourcePath())) {
- throw new DavException(DavServletResponse.SC_CONFLICT, "Unable to start local transaction: no repository item present at "+getResourcePath());
- }
- }
-
- public void commit(TransactionResource resource) throws DavException {
- try {
- DavSession session = resource.getSession();
- session.getRepositorySession().getItem(getResourcePath()).save();
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- }
-
- public void rollback(TransactionResource resource) throws DavException {
- try {
- DavSession session = resource.getSession();
- session.getRepositorySession().getItem(getResourcePath()).refresh(false);
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- }
-
- public Transaction put(String key, Transaction value) throws DavException {
- throw new DavException(WebdavResponse.SC_PRECONDITION_FAILED, "Attempt to nest a new transaction into a local one.");
- }
- }
-
- /**
- *
- */
- private static class GlobalTransaction extends AbstractTransaction {
-
- private Xid xid;
-
- private GlobalTransaction(DavResourceLocator locator, TxActiveLock lock) {
- super(locator, lock);
- xid = new XidImpl(lock.getToken());
- }
-
- public boolean isLocal() {
- return false;
- }
-
- public void start(TransactionResource resource) throws DavException {
- XAResource xaRes = getXAResource(resource);
- try {
- xaRes.setTransactionTimeout((int)getLock().getTimeout()/1000);
- xaRes.start(xid, XAResource.TMNOFLAGS);
- } catch (XAException e) {
- throw new DavException(DavServletResponse.SC_FORBIDDEN, e.getMessage());
- }
- }
-
- public void commit(TransactionResource resource) throws DavException {
- XAResource xaRes = getXAResource(resource);
- try {
- xaRes.commit(xid, false);
- removeLocalTxReferences(resource);
- } catch (XAException e) {
- throw new DavException(DavServletResponse.SC_FORBIDDEN, e.getMessage());
- }
- }
-
- public void rollback(TransactionResource resource) throws DavException {
- XAResource xaRes = getXAResource(resource);
- try {
- xaRes.rollback(xid);
- removeLocalTxReferences(resource);
- } catch (XAException e) {
- throw new DavException(DavServletResponse.SC_FORBIDDEN, e.getMessage());
- }
- }
-
- private XAResource getXAResource(TransactionResource resource) throws DavException {
- Session session = resource.getSession().getRepositorySession();
- if (session instanceof XASession) {
- return ((XASession)session).getXAResource();
- } else {
- throw new DavException(DavServletResponse.SC_FORBIDDEN);
- }
- }
-
- private void removeLocalTxReferences(TransactionResource resource) {
- Iterator it = values().iterator();
- while (it.hasNext()) {
- Transaction tx = (Transaction) it.next();
- removeReferences(tx, this, resource);
- }
- }
-
- public Transaction put(String key, Transaction value) throws DavException {
- if (!(value instanceof LocalTransaction)) {
- throw new DavException(WebdavResponse.SC_PRECONDITION_FAILED, "Attempt to nest global transaction into a global one.");
- }
- return (Transaction) super.put(key, value);
- }
- }
-
- /**
- *
- */
- private static class TransactionMap extends HashMap {
-
- public Transaction get(String key) {
- Transaction tx = null;
- if (containsKey(key)) {
- tx = (Transaction) super.get(key);
- }
- return tx;
- }
-
- public Transaction put(String key, Transaction value) throws DavException {
- // any global an local transactions allowed.
- return (Transaction) super.put(key, value);
- }
- }
-
- /**
- * Private class implementing Xid interface.
- */
- private static class XidImpl implements Xid {
-
- private final String id;
-
- /**
- * Create a new Xid
- *
- * @param id
- */
- private XidImpl(String id) {
- this.id = id;
- }
-
- /**
- * @return 1
- * @see javax.transaction.xa.Xid#getFormatId()
- */
- public int getFormatId() {
- // todo: define reasonable format id
- return 1;
- }
-
- /**
- * @return an empty byte array.
- * @see javax.transaction.xa.Xid#getBranchQualifier()
- */
- public byte[] getBranchQualifier() {
- return new byte[0];
- }
-
- /**
- * @return id as byte array
- * @see javax.transaction.xa.Xid#getGlobalTransactionId()
- */
- public byte[] getGlobalTransactionId() {
- return id.getBytes();
- }
- }
-}
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/VersionControlledItemCollection.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/VersionControlledItemCollection.java
deleted file mode 100644
index a4c7c82b144..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/VersionControlledItemCollection.java
+++ /dev/null
@@ -1,584 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi.version;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.property.*;
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.spi.JcrDavException;
-import org.apache.jackrabbit.webdav.spi.DefaultItemCollection;
-import org.apache.jackrabbit.webdav.version.*;
-import org.apache.jackrabbit.webdav.version.report.*;
-
-import javax.jcr.*;
-import javax.jcr.observation.*;
-import javax.jcr.observation.EventListener;
-import javax.jcr.version.Version;
-import javax.jcr.version.VersionHistory;
-import java.util.List;
-
-/**
- * VersionControlledItemCollection represents a JCR node item and
- * covers all functionality related to versioning of {@link Node}s.
- *
- * @see Node
- */
-public class VersionControlledItemCollection extends DefaultItemCollection
- implements VersionControlledResource {
-
- private static Logger log = Logger.getLogger(VersionControlledItemCollection.class);
-
- /**
- * Create a new VersionControlledItemCollection.
- *
- * @param locator
- * @param session
- */
- public VersionControlledItemCollection(DavResourceLocator locator, DavSession session, DavResourceFactory factory) {
- super(locator, session, factory);
- if (exists() && !(item instanceof Node)) {
- throw new IllegalArgumentException("A collection resource can not be constructed from a Property item.");
- }
- }
-
- //----------------------------------------------< DavResource interface >---
- /**
- * Return a comma separated string listing the supported method names.
- *
- * @return the supported method names.
- * @see org.apache.jackrabbit.webdav.DavResource#getSupportedMethods()
- */
- public String getSupportedMethods() {
- StringBuffer sb = new StringBuffer(super.getSupportedMethods());
- // Versioning support
- sb.append(", ").append(VersionableResource.METHODS);
- if (this.isVersionControlled()) {
- try {
- if (((Node)item).isCheckedOut()) {
- sb.append(", ").append(VersionControlledResource.methods_checkedOut);
- } else {
- sb.append(", ").append(VersionControlledResource.methods_checkedIn);
- }
- } catch (RepositoryException e) {
- // should not occur.
- log.error(e.getMessage());
- }
- }
- return sb.toString();
- }
-
- //--------------------------------< VersionControlledResource interface >---
- /**
- * Adds version control to this resource. If the resource is already under
- * version control, this method has no effect.
- *
- * @throws org.apache.jackrabbit.webdav.DavException if this resource does not
- * exist yet or if an error occurs while making the underlaying node versionable.
- * @see org.apache.jackrabbit.webdav.version.VersionableResource#addVersionControl()
- */
- public void addVersionControl() throws DavException {
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
- if (!isVersionControlled()) {
- try {
- ((Node)item).addMixin(MIX_VERSIONABLE);
- item.save();
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- } // else: is already version controlled -> ignore
- }
-
- /**
- * Calls {@link javax.jcr.Node#checkin()} on the underlaying repository node.
- *
- * @throws org.apache.jackrabbit.webdav.DavException
- * @see org.apache.jackrabbit.webdav.version.VersionControlledResource#checkin()
- */
- public String checkin() throws DavException {
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
- if (!isVersionControlled()) {
- throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- }
- try {
- Version v = ((Node) item).checkin();
- DavResourceLocator loc = getLocator();
- String versionHref = loc.getFactory().createResourceLocator(loc.getPrefix(), loc.getWorkspacePath(), v.getPath()).getHref(true);
- return versionHref;
- } catch (RepositoryException e) {
- // UnsupportedRepositoryException should not occur
- throw new JcrDavException(e);
- }
- }
-
- /**
- * Calls {@link javax.jcr.Node#checkout()} on the underlaying repository node.
- *
- * @throws org.apache.jackrabbit.webdav.DavException
- * @see org.apache.jackrabbit.webdav.version.VersionControlledResource#checkout()
- */
- public void checkout() throws DavException {
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
- if (!isVersionControlled()) {
- throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- }
- try {
- ((Node) item).checkout();
- } catch (RepositoryException e) {
- // UnsupportedRepositoryException should not occur
- throw new JcrDavException(e);
- }
- }
-
- /**
- * Not implemented. Always throws a DavException with error code
- * {@link org.apache.jackrabbit.webdav.DavServletResponse#SC_NOT_IMPLEMENTED}.
- *
- * @throws org.apache.jackrabbit.webdav.DavException
- * @see org.apache.jackrabbit.webdav.version.VersionControlledResource#uncheckout()
- */
- public void uncheckout() throws DavException {
- throw new DavException(DavServletResponse.SC_NOT_IMPLEMENTED);
- }
-
- /**
- * Perform an update on this resource. Depending on the format of the updateInfo
- * this is translated to one of the following methods defined by the JCR API:
- *
- *
- * Limitation: note that the MultiStatus returned by this method
- * will not list any nodes that have been removed due to an Uuid conflict.
- *
- * @param updateInfo
- * @return
- * @throws org.apache.jackrabbit.webdav.DavException
- * @see org.apache.jackrabbit.webdav.version.VersionControlledResource#update(org.apache.jackrabbit.webdav.version.UpdateInfo)
- * @todo with jcr the node must not be versionable in order to perform Node.update.
- */
- public MultiStatus update(UpdateInfo updateInfo) throws DavException {
- if (updateInfo == null) {
- throw new DavException(DavServletResponse.SC_BAD_REQUEST, "Valid update request body required.");
- }
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
-
- MultiStatus ms = new MultiStatus();
- try {
- Node node = (Node)item;
- boolean removeExisting = updateInfo.getUpdateElement().getChild(XML_REMOVEEXISTING, NAMESPACE) != null;
-
- // register eventListener in order to be able to report the modified resources.
- EventListener el = new EListener(updateInfo.getPropertyNameSet(), ms);
- registerEventListener(el, node.getPath());
-
- // perform the update/restore according to the update info
- if (updateInfo.getVersionHref() != null) {
- VersionHistory vh = node.getVersionHistory();
- String[] hrefs = updateInfo.getVersionHref();
- Version[] versions = new Version[hrefs.length];
- for (int i = 0; i < hrefs.length; i++) {
- versions[i] = vh.getVersion(getResourceName(hrefs[i], true));
- }
- if (versions.length == 1) {
- String relPath = updateInfo.getUpdateElement().getChildText(XML_RELPATH, NAMESPACE);
- if (relPath == null) {
- node.restore(versions[0], removeExisting);
- } else {
- node.restore(versions[0], relPath, removeExisting);
- }
- } else {
- getRepositorySession().getWorkspace().restore(versions, removeExisting);
- }
- } else if (updateInfo.getLabelName() != null) {
- String[] labels = updateInfo.getLabelName();
- if (labels.length == 1) {
- node.restoreByLabel(labels[0], removeExisting);
- } else {
- Version[] vs = new Version[labels.length];
- VersionHistory vh = node.getVersionHistory();
- for (int i = 0; i < labels.length; i++) {
- vs[i] = vh.getVersionByLabel(labels[i]);
- }
- getRepositorySession().getWorkspace().restore(vs, removeExisting);
- }
- } else if (updateInfo.getWorkspaceHref() != null) {
- String workspaceName = getResourceName(updateInfo.getWorkspaceHref(), true);
- node.update(workspaceName);
- } else {
- throw new DavException(DavServletResponse.SC_BAD_REQUEST, "Invalid update request body.");
- }
-
- // unregister the event listener again
- unregisterEventListener(el);
-
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- return ms;
- }
-
- /**
- * Merge the repository node represented by this resource according to the
- * information present in the given {@link MergeInfo} object.
- *
- * @param mergeInfo
- * @return MultiStatus reccording all repository items affected
- * by this merge call.
- * @throws org.apache.jackrabbit.webdav.DavException
- * @see org.apache.jackrabbit.webdav.version.VersionControlledResource#merge(org.apache.jackrabbit.webdav.version.MergeInfo)
- * @see Node#merge(String, boolean)
- * @todo with jcr the node must not be versionable in order to perform Node.merge
- */
- public MultiStatus merge(MergeInfo mergeInfo) throws DavException {
- if (mergeInfo == null) {
- throw new DavException(DavServletResponse.SC_BAD_REQUEST);
- }
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
-
- MultiStatus ms = new MultiStatus();
- try {
- Node node = (Node)item;
-
- // register eventListener in order to be able to report the modifications.
- EventListener el = new EListener(mergeInfo.getPropertyNameSet(), ms);
- registerEventListener(el, node.getPath());
-
- String workspaceName = getResourceName(mergeInfo.getSourceHref(), true);
- node.merge(workspaceName, !mergeInfo.isNoAutoMerge());
-
- // unregister the event listener again
- unregisterEventListener(el);
-
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
-
- return ms;
- }
-
- /**
- * Resolve the merge conflicts according to the value of the {@link #AUTO_MERGE_SET DAV:auto-merge-set}
- * property present in the specified DavPropertySets.
- *
- * @param setProperties
- * @param removePropertyNames
- * @throws org.apache.jackrabbit.webdav.DavException
- * @see VersionControlledResource#resolveMergeConflict(DavPropertySet, DavPropertyNameSet)
- * @see Node#doneMerge(Version)
- * @see Node#cancelMerge(Version)
- */
- public void resolveMergeConflict(DavPropertySet setProperties,
- DavPropertyNameSet removePropertyNames) throws DavException {
-
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
- if (!isVersionControlled()) {
- throw new DavException(DavServletResponse.SC_METHOD_NOT_ALLOWED);
- }
-
- try {
- Node n = (Node)item;
- if (removePropertyNames.contains(AUTO_MERGE_SET)) {
- // retrieve the current jcr:mergeFailed property values
- if (!((Node)item).hasProperty(PROP_MERGEFAILED)) {
- throw new DavException(DavServletResponse.SC_CONFLICT, "Attempt to resolve non-existing merge conflicts.");
- }
- Value[] mergeFailed = ((Node)item).getProperty(PROP_MERGEFAILED).getValues();
-
- // resolve all remaining merge conflicts with 'cancel'
- for (int i = 0; i < mergeFailed.length; i++) {
- n.cancelMerge((Version)getRepositorySession().getNodeByUUID(mergeFailed[i].getString()));
- }
- // adjust removeProperty set
- removePropertyNames.remove(AUTO_MERGE_SET);
-
- } else if (setProperties.contains(AUTO_MERGE_SET) && setProperties.contains(PREDECESSOR_SET)){
- // retrieve the current jcr:mergeFailed property values
- if (!((Node)item).hasProperty(PROP_MERGEFAILED)) {
- throw new DavException(DavServletResponse.SC_CONFLICT, "Attempt to resolve non-existing merge conflicts.");
- }
- Value[] mergeFailed = ((Node)item).getProperty(PROP_MERGEFAILED).getValues();
-
-
- // check which mergeFailed entries have been removed from the
- // auto-merge-set (cancelMerge) and have been moved over to the
- // predecessor set (doneMerge)
- List mergeset = new HrefProperty(setProperties.get(AUTO_MERGE_SET)).getHrefs();
- List predecSet = new HrefProperty(setProperties.get(PREDECESSOR_SET)).getHrefs();
-
- Session session = getRepositorySession();
- for (int i = 0; i < mergeFailed.length; i++) {
- // build version-href from each entry in the jcr:mergeFailed property
- Version version = (Version) session.getNodeByUUID(mergeFailed[i].getString());
- String href = this.getLocatorFromItem(version).getHref(true);
-
- // Test if that version has been removed from the merge-set.
- // thus indicating that the merge-conflict needs to be resolved.
- if (!mergeset.contains(href)) {
- // Test if the 'href' has been moved over to the
- // predecessor-set (thus 'doneMerge' is appropriate) or
- // if it is not present in the predecessor set and the
- // the conflict is resolved by 'cancelMerge'.
- if (predecSet.contains(href)) {
- n.doneMerge(version);
- } else {
- n.cancelMerge(version);
- }
- }
- }
- // adjust setProperty set
- setProperties.remove(AUTO_MERGE_SET);
- setProperties.remove(PREDECESSOR_SET);
- } else {
- // setPropertySet and removePropertySet do not ask for resolving merge conflicts */
- log.debug("setProperties and removeProperties sets do not request for merge conflict resolution.");
- }
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- }
-
- /**
- * Modify the labels present with the versions of this resource.
- *
- * @param labelInfo
- * @throws DavException
- * @see VersionHistory#addVersionLabel(String, String, boolean)
- * @see VersionHistory#removeVersionLabel(String)
- */
- public void label(LabelInfo labelInfo) throws DavException {
- if (labelInfo == null) {
- throw new DavException(DavServletResponse.SC_BAD_REQUEST, "Valid label request body required.");
- }
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
-
- try {
- if (!isVersionControlled() || ((Node)item).isCheckedOut()) {
- throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED, "A LABEL request may only be applied to a version-controlled, checked-in resource.");
- }
- DavResource[] resArr = this.getReferenceResources(CHECKED_IN);
- if (resArr.length == 1 && resArr[0] instanceof VersionResource) {
- ((VersionResource)resArr[0]).label(labelInfo);
- } else {
- throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR, "DAV:checked-in property on '" + getHref() + "' did not point to a single VersionResource.");
- }
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- }
-
- /**
- * Returns the {@link VersionHistory} associated with the repository node.
- * If the node is not versionable an exception is thrown.
- *
- * @return the {@link VersionHistoryResource} associated with this resource.
- * @throws org.apache.jackrabbit.webdav.DavException
- * @see org.apache.jackrabbit.webdav.version.VersionControlledResource#getVersionHistory()
- * @see javax.jcr.Node#getVersionHistory()
- */
- public VersionHistoryResource getVersionHistory() throws DavException {
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
-
- try {
- VersionHistory vh = ((Node)item).getVersionHistory();
- DavResourceLocator loc = getLocatorFromItem(vh);
- return (VersionHistoryResource) createResourceFromLocator(loc);
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- }
-
- //--------------------------------------------------------------------------
- /**
- * Define the set of reports supported by this resource.
- *
- * @see SupportedReportSetProperty
- */
- protected void initSupportedReports() {
- super.initSupportedReports();
- if (exists()) {
- supportedReports.addReportType(ReportType.LOCATE_BY_HISTORY);
- if (this.isVersionControlled()) {
- supportedReports.addReportType(ReportType.VERSION_TREE);
- }
- }
- }
-
- /**
- * Fill the property set for this resource.
- */
- protected void initProperties() {
- super.initProperties();
- if (exists()) {
- Node n = (Node)item;
- // properties defined by RFC 3253 for version-controlled resources
- if (isVersionControlled()) {
- // workspace property already set in AbstractResource.initProperties()
- try {
- // DAV:version-history (computed)
- String vhHref = getLocatorFromResourcePath(n.getVersionHistory().getPath()).getHref(true);
- properties.add(new HrefProperty(VERSION_HISTORY, vhHref, true));
-
- // DAV:auto-version property: there is no auto version, explicit CHECKOUT is required.
- properties.add(new DefaultDavProperty(AUTO_VERSION, null, false));
-
- String baseVHref = getLocatorFromResourcePath(n.getBaseVersion().getPath()).getHref(true);
- if (n.isCheckedOut()) {
- // DAV:checked-out property (protected)
- properties.add(new HrefProperty(CHECKED_OUT, baseVHref, true));
-
- // DAV:predecessors property
- if (n.hasProperty(PROP_PREDECESSORS)) {
- Value[] predec = n.getProperty(PROP_PREDECESSORS).getValues();
- addHrefProperty(PREDECESSOR_SET, predec, false);
- }
- // DAV:auto-merge-set property. NOTE: the DAV:merge-set
- // never occurs, because merging without bestEffort flag
- // being set results in an exception on failure.
- if (n.hasProperty(PROP_MERGEFAILED)) {
- ReferenceValue[] mergeFailed = (ReferenceValue[]) n.getProperty(PROP_MERGEFAILED).getValues();
- addHrefProperty(AUTO_MERGE_SET, mergeFailed, false);
- }
- // todo: checkout-fork, checkin-fork
- } else {
- // DAV:checked-in property (protected)
- properties.add(new HrefProperty(CHECKED_IN, baseVHref, true));
- }
- } catch (RepositoryException e) {
- log.error(e.getMessage());
- }
- }
- }
- }
-
- /**
- * Add a {@link org.apache.jackrabbit.webdav.property.HrefProperty} with the specified property name and values.
- *
- * @param name
- * @param values Array of {@link ReferenceValue}s.
- * @param isProtected
- * @throws javax.jcr.ValueFormatException
- * @throws IllegalStateException
- * @throws javax.jcr.RepositoryException
- */
- private void addHrefProperty(DavPropertyName name, Value[] values,
- boolean isProtected)
- throws ValueFormatException, IllegalStateException, RepositoryException {
- Node[] nodes = new Node[values.length];
- for (int i = 0; i < values.length; i++) {
- nodes[i] = getRepositorySession().getNodeByUUID(values[i].getString());
- }
- addHrefProperty(name, nodes, isProtected);
- }
-
- /**
- * @return true, if this resource represents an existing repository node
- * that has the mixin nodetype 'mix:versionable' set.
- */
- private boolean isVersionControlled() {
- boolean vc = false;
- if (exists()) {
- try {
- vc = ((Node) item).isNodeType("mix:versionable");
- } catch (RepositoryException e) {
- log.warn(e.getMessage());
- }
- }
- return vc;
- }
-
- /**
- * Register the specified event listener with the observation manager present
- * the repository session.
- *
- * @param listener
- * @param nodePath
- * @throws javax.jcr.RepositoryException
- */
- private void registerEventListener(EventListener listener, String nodePath) throws RepositoryException {
- getRepositorySession().getWorkspace().getObservationManager().addEventListener(listener, EListener.ALL_EVENTS, nodePath, true, null, null, false);
- }
-
- /**
- * Unregister the specified event listener with the observation manager present
- * the repository session.
- *
- * @param listener
- * @throws javax.jcr.RepositoryException
- */
- private void unregisterEventListener(EventListener listener) throws RepositoryException {
- getRepositorySession().getWorkspace().getObservationManager().removeEventListener(listener);
- }
-
- //------------------------------------------------------< inner classes >---
- /**
- * Simple EventListener that creates a new {@link org.apache.jackrabbit.webdav.MultiStatusResponse} object
- * for each event and adds it to the specified {@link org.apache.jackrabbit.webdav.MultiStatus}.
- */
- private class EListener implements EventListener {
-
- private static final int ALL_EVENTS = Event.NODE_ADDED | Event.NODE_REMOVED | Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED | Event.PROPERTY_REMOVED;
-
- private final DavPropertyNameSet propNameSet;
- private MultiStatus ms;
-
- private EListener(DavPropertyNameSet propNameSet, MultiStatus ms) {
- this.propNameSet = propNameSet;
- this.ms = ms;
- }
-
- /**
- * @see EventListener#onEvent(javax.jcr.observation.EventIterator)
- */
- public void onEvent(EventIterator events) {
- while (events.hasNext()) {
- try {
- Event e = events.nextEvent();
- String itemPath = e.getPath();
- DavResourceLocator loc = getLocatorFromResourcePath(itemPath);
- DavResource res = createResourceFromLocator(loc);
- ms.addResponse(new MultiStatusResponse(res, propNameSet));
-
- } catch (DavException e) {
- // should not occur
- log.error("Error while building MultiStatusResponse from Event: " + e.getMessage());
- } catch (RepositoryException e) {
- // should not occur
- log.error("Error while building MultiStatusResponse from Event: " + e.getMessage());
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/VersionHistoryItemCollection.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/VersionHistoryItemCollection.java
deleted file mode 100644
index 3bb743be380..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/VersionHistoryItemCollection.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi.version;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.version.*;
-import org.apache.jackrabbit.webdav.property.HrefProperty;
-import org.apache.jackrabbit.webdav.spi.ItemResourceConstants;
-import org.apache.jackrabbit.webdav.spi.JcrDavException;
-import org.apache.jackrabbit.webdav.spi.DefaultItemCollection;
-import org.apache.jackrabbit.webdav.*;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.version.VersionHistory;
-import javax.jcr.version.VersionIterator;
-import java.util.ArrayList;
-
-/**
- * VersionHistoryItemCollection represents a JCR version history.
- *
- * @see VersionHistory
- */
-public class VersionHistoryItemCollection extends DefaultItemCollection
- implements VersionHistoryResource {
-
- private static Logger log = Logger.getLogger(VersionHistoryItemCollection.class);
-
- /**
- * Create a new VersionHistoryItemCollection resource.
- *
- * @param resourcePath
- * @param session
- * @param factory
- */
- public VersionHistoryItemCollection(DavResourceLocator resourcePath, DavSession session, DavResourceFactory factory) {
- super(resourcePath, session, factory);
- if (item == null || !(item instanceof VersionHistory)) {
- throw new IllegalArgumentException("VersionHistory item expected.");
- }
- }
-
- //----------------------------------------------< DavResource interface >---
- /**
- * @see org.apache.jackrabbit.webdav.DavResource#getSupportedMethods()
- */
- public String getSupportedMethods() {
- StringBuffer sb = new StringBuffer(ItemResourceConstants.METHODS);
- sb.append(", ").append(VersionHistoryResource.METHODS);
- return sb.toString();
- }
-
- /**
- * Removing a version resource is achieved by calling removeVersion
- * on the versionhistory item this version belongs to.
- *
- * @throws DavException if the version does not exist or if an error occurs
- * while deleting.
- * @see DavResource#removeMember(org.apache.jackrabbit.webdav.DavResource)
- */
- public void removeMember(DavResource member) throws DavException {
- if (exists()) {
- VersionHistory versionHistory = (VersionHistory) item;
- try {
- versionHistory.removeVersion(getResourceName(member.getHref(), true));
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- } else {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
- }
- //-----------------------------------< VersionHistoryResource interface >---
- /**
- * Return an array of {@link VersionResource}s representing all versions
- * present in the underlaying JCR version history.
- *
- * @return array of {@link VersionResource}s representing all versions
- * present in the underlaying JCR version history.
- * @throws DavException
- * @see org.apache.jackrabbit.webdav.version.VersionHistoryResource#getVersions()
- */
- public VersionResource[] getVersions() throws DavException {
- try {
- VersionIterator vIter = ((VersionHistory)item).getAllVersions();
- ArrayList l = new ArrayList();
- while (vIter.hasNext()) {
- DavResourceLocator versionLoc = getLocatorFromItem(vIter.nextVersion());
- DavResource vr = createResourceFromLocator(versionLoc);
- l.add(vr);
- }
- return (VersionResource[]) l.toArray(new VersionResource[l.size()]);
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- }
-
- //--------------------------------------------------------------------------
- /**
- * Fill the property set for this resource.
- */
- protected void initProperties() {
- super.initProperties();
-
- // change resourcetype defined by default item collection
- properties.add(new ResourceType(ResourceType.VERSION_HISTORY));
-
- // required root-version property for version-history resource
- try {
- String rootVersionResourcePath = ((VersionHistory)item).getRootVersion().getPath();
- properties.add(new HrefProperty(VersionHistoryResource.ROOT_VERSION, getLocatorFromResourcePath(rootVersionResourcePath).getHref(true), true));
- } catch (RepositoryException e) {
- log.error(e.getMessage());
- }
-
- // required, protected version-set property for version-history resource
- try {
- VersionIterator vIter = ((VersionHistory)item).getAllVersions();
- addHrefProperty(VersionHistoryResource.VERSION_SET, vIter, true);
- } catch (RepositoryException e) {
- log.error(e.getMessage());
- }
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/VersionItemCollection.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/VersionItemCollection.java
deleted file mode 100644
index fba927dbbef..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/VersionItemCollection.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi.version;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.spi.JcrDavException;
-import org.apache.jackrabbit.webdav.spi.ItemResourceConstants;
-import org.apache.jackrabbit.webdav.spi.DefaultItemCollection;
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.property.*;
-import org.apache.jackrabbit.webdav.version.*;
-import org.apache.jackrabbit.webdav.version.report.ReportType;
-import org.jdom.Element;
-
-import javax.jcr.*;
-import javax.jcr.version.Version;
-import javax.jcr.version.VersionHistory;
-import java.util.List;
-import java.util.ArrayList;
-
-/**
- * VersionItemCollection represents a JCR version.
- *
- * @see Version
- */
-public class VersionItemCollection extends DefaultItemCollection
- implements VersionResource {
-
- private static Logger log = Logger.getLogger(VersionItemCollection.class);
-
- /**
- * Create a new VersionItemCollection.
- *
- * @param locator
- * @param session
- * @param factory
- */
- public VersionItemCollection(DavResourceLocator locator, DavSession session, DavResourceFactory factory) {
- super(locator, session, factory);
- if (item == null || !(item instanceof Version)) {
- throw new IllegalArgumentException("Version item expected.");
- }
- }
-
- //----------------------------------------------< DavResource interface >---
- /**
- * @see org.apache.jackrabbit.webdav.DavResource#getSupportedMethods()
- */
- public String getSupportedMethods() {
- StringBuffer sb = new StringBuffer(ItemResourceConstants.METHODS);
- sb.append(", ").append(VersionResource.METHODS);
- return sb.toString();
- }
-
- //------------------------------------------< VersionResource interface >---
- /**
- * Modify the labels defined for the underlaying repository version.
- *
- * @param labelInfo
- * @throws DavException
- * @see VersionResource#label(org.apache.jackrabbit.webdav.version.LabelInfo)
- * @see VersionHistory#addVersionLabel(String, String, boolean)
- * @see VersionHistory#removeVersionLabel(String)
- */
- public void label(LabelInfo labelInfo) throws DavException {
- if (labelInfo == null) {
- throw new DavException(DavServletResponse.SC_BAD_REQUEST, "Valid label request body required.");
- }
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
- try {
- VersionHistory vh = getVersionHistoryItem();
- if (labelInfo.getType() == LabelInfo.TYPE_REMOVE) {
- vh.removeVersionLabel(labelInfo.getLabelName());
- } else if (labelInfo.getType() == LabelInfo.TYPE_ADD) {
- // ADD: only add if not yet existing
- vh.addVersionLabel(item.getName(), labelInfo.getLabelName(), false);
- } else {
- // SET: move label if already existing
- vh.addVersionLabel(item.getName(), labelInfo.getLabelName(), true);
- }
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- }
-
- /**
- * Returns the {@link VersionHistory} associated with the repository version.
- * Note: in contrast to a versionable node, the version history of a version
- * item is always represented by its nearest ancestor.
- *
- * @return the {@link VersionHistoryResource} associated with this resource.
- * @throws org.apache.jackrabbit.webdav.DavException
- * @see org.apache.jackrabbit.webdav.version.VersionResource#getVersionHistory()
- * @see javax.jcr.Item#getParent()
- */
- public VersionHistoryResource getVersionHistory() throws DavException {
- if (!exists()) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- }
-
- try {
- VersionHistory vh = getVersionHistoryItem();
- DavResourceLocator loc = getLocatorFromItem(vh);
- return (VersionHistoryResource) createResourceFromLocator(loc);
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- }
-
- /**
- * Return the nearest ancestor of the underlaying repository item.
- *
- * @return nearest ancestor of the underlaying repository item.
- * @throws RepositoryException
- */
- private VersionHistory getVersionHistoryItem() throws RepositoryException {
- return (VersionHistory) item.getParent();
- }
-
- //--------------------------------------------------------------------------
- /**
- * Define the set of reports supported by this resource.
- *
- * @see org.apache.jackrabbit.webdav.version.report.SupportedReportSetProperty
- */
- protected void initSupportedReports() {
- super.initSupportedReports();
- if (exists()) {
- supportedReports.addReportType(ReportType.VERSION_TREE);
- }
- }
-
- /**
- * Fill the property set for this resource.
- */
- protected void initProperties() {
- super.initProperties();
-
- if (exists()) {
- Version v = (Version)item;
- // created and creationDate properties
- try {
- String creationDate = DavConstants.creationDateFormat.format(v.getCreated().getTime());
- // jcr specific 'created' property
- properties.add(new DefaultDavProperty(CREATED, creationDate));
- // replace dummy creation date from default collection
- properties.add(new DefaultDavProperty(DavPropertyName.CREATIONDATE, creationDate));
-
- // required, protected DAV:version-name property
- properties.add(new DefaultDavProperty(VERSION_NAME, v.getName(), true));
-
- // required, protected DAV:label-name-set property
- String[] labels = getVersionHistoryItem().getVersionLabels(v);
- Element[] labelElems = new Element[labels.length];
- for (int i = 0; i < labels.length; i++) {
- labelElems[i] = new Element(DeltaVConstants.XML_LABEL_NAME, NAMESPACE).setText(labels[i]);
- }
- properties.add(new DefaultDavProperty(LABEL_NAME_SET, labelElems, true));
-
- // required DAV:predecessor-set (protected) and DAV:successor-set (computed) properties
- addHrefProperty(VersionResource.PREDECESSOR_SET, v.getPredecessors(), true);
- addHrefProperty(SUCCESSOR_SET, v.getSuccessors(), true);
-
- // required DAV:version-history (computed) property
- String vhPath = getVersionHistoryItem().getPath();
- properties.add(new HrefProperty(VersionResource.VERSION_HISTORY, getLocatorFromResourcePath(vhPath).getHref(true), true));
-
- // required DAV:checkout-set (computed) property
- PropertyIterator it = v.getReferences();
- List nodeList = new ArrayList();
- while (it.hasNext()) {
- Property p = it.nextProperty();
- if (PROP_BASEVERSION.equals(p.getName())) {
- Node n = p.getParent();
- if (n.isCheckedOut()) {
- nodeList.add(n);
- }
- }
- }
- addHrefProperty(CHECKOUT_SET, (Node[]) nodeList.toArray(new Node[nodeList.size()]), true);
-
- } catch (RepositoryException e) {
- log.error(e.getMessage());
- }
- }
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/package.html b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/package.html
deleted file mode 100644
index aeea3f616a8..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/package.html
+++ /dev/null
@@ -1,9 +0,0 @@
-
-Contains JCR specific implementations for the following interfaces:
-
-
VersionableResource
-
VersionControlledResource
-
VersionResource
-
VersionHistoryResource
-
-
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/report/ExportViewReport.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/report/ExportViewReport.java
deleted file mode 100644
index 6312a68bad8..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/report/ExportViewReport.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi.version.report;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.spi.ItemResourceConstants;
-import org.apache.jackrabbit.webdav.spi.JcrDavException;
-import org.apache.jackrabbit.webdav.version.report.*;
-import org.apache.jackrabbit.webdav.version.DeltaVResource;
-import org.apache.jackrabbit.webdav.DavException;
-import org.apache.jackrabbit.webdav.DavSession;
-import org.apache.jackrabbit.webdav.DavServletResponse;
-import org.apache.jackrabbit.webdav.util.Text;
-import org.jdom.Document;
-import org.jdom.Element;
-import org.jdom.JDOMException;
-import org.jdom.input.SAXBuilder;
-
-import javax.jcr.Session;
-import javax.jcr.RepositoryException;
-import javax.jcr.PathNotFoundException;
-import java.io.*;
-
-/**
- * ExportViewReport handles REPORT requests for the 'exportview'
- * report. The 'exportview' report is used to export
- * {@link Session#exportDocView(String, java.io.OutputStream, boolean, boolean) DocView}
- * and {@link Session#exportSysView(String, java.io.OutputStream, boolean, boolean) SysView}
- * of the {@link javax.jcr.Item item} represented by the requested resource.
- *
- * The request body must contain a jcr:exportview element:
- *
- * If no view type is specified the DocView is generated.
- */
-public class ExportViewReport implements Report {
-
- private static Logger log = Logger.getLogger(ExportViewReport.class);
-
- private static final String REPORT_NAME = "exportview";
-
- /**
- * The exportview report type
- */
- public static final ReportType EXPORTVIEW_REPORT = ReportType.register(REPORT_NAME, ItemResourceConstants.NAMESPACE, ExportViewReport.class);
-
- private String absPath;
- private Session session;
- private ReportInfo info;
-
- /**
- * Returns {@link #EXPORTVIEW_REPORT} report type.
- *
- * @return {@link #EXPORTVIEW_REPORT}
- * @see org.apache.jackrabbit.webdav.version.report.Report#getType()
- */
- public ReportType getType() {
- return EXPORTVIEW_REPORT;
- }
-
- /**
- * @param resource The resource this report is generated from. NOTE: the
- * {@link org.apache.jackrabbit.webdav.DavResource#getResourcePath() resource path}
- * of the resource is used as 'absPath' argument for exporting the specified
- * view.
- * @throws IllegalArgumentException if the resource is null or
- * if the session object provided with the resource is null.
- * @see Report#setResource(org.apache.jackrabbit.webdav.version.DeltaVResource)
- */
- public void setResource(DeltaVResource resource) {
- if (resource == null) {
- throw new IllegalArgumentException("Resource must not be null.");
- }
- DavSession davSession = resource.getSession();
- if (davSession == null || davSession.getRepositorySession() == null) {
- throw new IllegalArgumentException("The resource must provide a non-null session object in order to create the jcr:nodetypes report.");
- }
- session = davSession.getRepositorySession();
- absPath = resource.getResourcePath();
- }
-
- /**
- * @param info
- * @throws IllegalArgumentException if the specified {@link ReportInfo info}
- * object does not contain a jcr:exportview element.
- * @see Report#setInfo(org.apache.jackrabbit.webdav.version.report.ReportInfo)
- */
- public void setInfo(ReportInfo info) {
- if (info == null || !REPORT_NAME.equals(info.getReportElement().getName())) {
- throw new IllegalArgumentException("jcr:exportview element expected.");
- }
- this.info = info;
- }
-
- /**
- * Creates a Xml document from the generated view.
- *
- * @return Xml document representing the output of the specified view.
- * @throws DavException if the report document could not be created.
- * @see org.apache.jackrabbit.webdav.version.report.Report#toXml()
- */
- public Document toXml() throws DavException {
- Element reportElem = info.getReportElement();
- boolean skipBinary = reportElem.getChild("skipbinary", ItemResourceConstants.NAMESPACE) != null;
- boolean noRecurse = reportElem.getChild("norecurse", ItemResourceConstants.NAMESPACE) != null;
-
- try {
- // create tmpFile in default system-tmp directory
- String prefix = "_tmp_" + Text.getLabel(absPath);
- File tmpfile = File.createTempFile(prefix, null, null);
- tmpfile.deleteOnExit();
- FileOutputStream out = new FileOutputStream(tmpfile);
-
- if (reportElem.getChild("sysview", ItemResourceConstants.NAMESPACE) != null) {
- session.exportSysView(absPath, out, skipBinary, noRecurse);
- } else {
- // default is docview
- session.exportDocView(absPath, out, skipBinary, noRecurse);
- }
- out.close();
-
- SAXBuilder builder = new SAXBuilder(false);
- InputStream in = new FileInputStream(tmpfile);
- return builder.build(in);
-
- } catch (FileNotFoundException e) {
- throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR);
- } catch (IOException e) {
- throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR);
- } catch (PathNotFoundException e) {
- throw new DavException(DavServletResponse.SC_NOT_FOUND);
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- } catch (JDOMException e) {
- throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR);
- }
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/report/LocateByUuidReport.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/report/LocateByUuidReport.java
deleted file mode 100644
index 08eeee149e9..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/report/LocateByUuidReport.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi.version.report;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.version.report.*;
-import org.apache.jackrabbit.webdav.version.DeltaVResource;
-import org.apache.jackrabbit.webdav.spi.ItemResourceConstants;
-import org.apache.jackrabbit.webdav.spi.JcrDavException;
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
-import org.jdom.Document;
-
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-
-/**
- * LocateByUuidReport handles REPORT requests for the 'locate-by-uuid'
- * report.
- *
- * The request body must be a 'jcr:locate-by-uuid' XML element:
- *
- * The response to a successful report request will be a Multi-Status response.
- */
-public class LocateByUuidReport implements Report {
-
- private static Logger log = Logger.getLogger(LocateByUuidReport.class);
-
- private static final String REPORT_NAME = "locate-by-uuid";
-
- /**
- * The exportview report type
- */
- public static final ReportType LOCATE_BY_UUID_REPORT = ReportType.register(REPORT_NAME, ItemResourceConstants.NAMESPACE, LocateByUuidReport.class);
-
- private DeltaVResource resource;
- private ReportInfo info;
-
- /**
- * Returns {@link #LOCATE_BY_UUID_REPORT} report type.
- *
- * @return {@link #LOCATE_BY_UUID_REPORT}
- * @see org.apache.jackrabbit.webdav.version.report.Report#getType()
- */
- public ReportType getType() {
- return LOCATE_BY_UUID_REPORT;
- }
-
- /**
- * @param resource
- * @throws IllegalArgumentException if the resource is null or
- * if the session object provided with the resource is null.
- * @see Report#setResource(org.apache.jackrabbit.webdav.version.DeltaVResource)
- */
- public void setResource(DeltaVResource resource) {
- if (resource == null) {
- throw new IllegalArgumentException("Resource must not be null.");
- }
- DavSession davSession = resource.getSession();
- if (davSession == null || davSession.getRepositorySession() == null) {
- throw new IllegalArgumentException("The resource must provide a non-null session object in order to create the jcr:nodetypes report.");
- }
- this.resource = resource;
- }
-
- /**
- * @param info
- * @throws IllegalArgumentException if the specified {@link ReportInfo info}
- * object does not contain a jcr:exportview element.
- * @see Report#setInfo(org.apache.jackrabbit.webdav.version.report.ReportInfo)
- */
- public void setInfo(ReportInfo info) {
- if (info == null || !REPORT_NAME.equals(info.getReportElement().getName())) {
- throw new IllegalArgumentException("jcr:locate-by-uuid element expected.");
- }
- this.info = info;
- }
-
- /**
- * Creates a Xml document from the generated view.
- *
- * @return Xml document representing the output of the specified view.
- * @throws DavException if the report document could not be created.
- * @see org.apache.jackrabbit.webdav.version.report.Report#toXml()
- */
- public Document toXml() throws DavException {
- String uuid = info.getReportElement().getChildText(DavConstants.XML_HREF, DavConstants.NAMESPACE);
- DavPropertyNameSet propNameSet = info.getPropertyNameSet();
-
- try {
- DavSession session = resource.getSession();
- DavResourceLocator resourceLoc = resource.getLocator();
-
- Node n = session.getRepositorySession().getNodeByUUID(uuid);
-
- DavResourceLocator loc = resourceLoc.getFactory().createResourceLocator(resourceLoc.getPrefix(), resourceLoc.getWorkspacePath(), n.getPath());
- DavResource res = resource.getFactory().createResource(loc, session);
-
- MultiStatus ms = new MultiStatus();
- ms.addResourceProperties(res, propNameSet, 0);
- return ms.toXml();
-
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/report/NodeTypesReport.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/report/NodeTypesReport.java
deleted file mode 100644
index 1258a128aa0..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/report/NodeTypesReport.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi.version.report;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.version.report.*;
-import org.apache.jackrabbit.webdav.version.DeltaVResource;
-import org.apache.jackrabbit.webdav.DavException;
-import org.apache.jackrabbit.webdav.DavServletResponse;
-import org.apache.jackrabbit.webdav.DavSession;
-import org.apache.jackrabbit.webdav.spi.nodetype.NodeTypeConstants;
-import org.apache.jackrabbit.webdav.spi.nodetype.PropertyDefImpl;
-import org.apache.jackrabbit.webdav.spi.nodetype.NodeDefImpl;
-import org.apache.jackrabbit.webdav.spi.JcrDavException;
-import org.apache.jackrabbit.core.util.IteratorHelper;
-import org.jdom.Document;
-import org.jdom.Element;
-
-import javax.jcr.nodetype.*;
-import javax.jcr.*;
-import java.util.*;
-
-/**
- * NodeTypesReport allows to retrieve the definition of a single
- * or multiple node types. The request body must be a 'jcr:nodetypes' element:
- *
- *
- * @todo currently the nodetype report is not consistent with the general way of representing nodetype names (with NodetypeElement) in order to be compatible with the jackrabbit nodetype registry...
- * @todo for the same reason, not the complete nodetype-definition, but only the nodetype def as stored is represented.
- * @todo no namespace definition with response (> jackrabbit)... and nodetype element has same name as the one used with dav-properties
- */
-public class NodeTypesReport implements Report, NodeTypeConstants {
-
- private static Logger log = Logger.getLogger(NodeTypesReport.class);
-
- /**
- * The registered type of this report.
- */
- public static final ReportType NODETYPES_REPORT = ReportType.register("nodetypes", NodeTypeConstants.NAMESPACE, NodeTypesReport.class);
-
- private NodeTypeManager ntMgr;
- private ReportInfo info;
-
- /**
- * Returns {@link #NODETYPES_REPORT} type.
- * @return {@link #NODETYPES_REPORT}
- * @see org.apache.jackrabbit.webdav.version.report.Report#getType()
- */
- public ReportType getType() {
- return NODETYPES_REPORT;
- }
-
- /**
- * @param resource
- * @throws IllegalArgumentException if the resource or the session retrieved
- * from the specified resource is null
- * @see Report#setResource(org.apache.jackrabbit.webdav.version.DeltaVResource)
- */
- public void setResource(DeltaVResource resource) {
- if (resource == null) {
- throw new IllegalArgumentException("Resource must not be null.");
- }
- try {
- DavSession session = resource.getSession();
- if (session == null || session.getRepositorySession() == null) {
- throw new IllegalArgumentException("The resource must provide a non-null session object in order to create the jcr:nodetypes report.");
- }
- ntMgr = session.getRepositorySession().getWorkspace().getNodeTypeManager();
- } catch (RepositoryException e) {
- log.error(e.getMessage());
- }
- }
-
- /**
- * @param info
- * @throws IllegalArgumentException if the specified info does not contain
- * a jcr:nodetypes element.
- * @see Report#setInfo(org.apache.jackrabbit.webdav.version.report.ReportInfo)
- */
- public void setInfo(ReportInfo info) {
- if (info == null || !"nodetypes".equals(info.getReportElement().getName())) {
- throw new IllegalArgumentException("jcr:nodetypes element expected.");
- }
- this.info = info;
- }
-
- /**
- * Returns a Xml representation of the node type definition(s) according
- * to the info object.
- *
- * @return Xml representation of the node type definition(s)
- * @throws DavException if the specified nodetypes are not known or if another
- * error occurs while retrieving the nodetype definitions.
- * @see org.apache.jackrabbit.webdav.version.report.Report#toXml()
- */
- public Document toXml() throws DavException {
- if (info == null || ntMgr == null) {
- throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR, "Error while running jcr:nodetypes report");
- }
- try {
- Element report = new Element(XML_NODETYPES);
- NodeTypeIterator ntIter = getNodeTypes();
- while (ntIter.hasNext()) {
- NodeType nt = ntIter.nextNodeType();
- Element ntDef = new Element(XML_NODETYPE);
- ntDef.setAttribute(ATTR_NAME, nt.getName());
- ntDef.setAttribute(ATTR_ISMIXIN, Boolean.toString(nt.isMixin()));
- ntDef.setAttribute(ATTR_HASORDERABLECHILDNODES, Boolean.toString(nt.hasOrderableChildNodes()));
-
- // declared supertypes
- NodeType[] snts = nt.getDeclaredSupertypes();
- Element supertypes = new Element(XML_SUPERTYPES);
- for (int i = 0; i < snts.length; i++) {
- supertypes.addContent(new Element(XML_SUPERTYPE).setText(snts[i].getName()));
- }
- ntDef.addContent(supertypes);
-
- // declared childnode defs
- NodeDef[] cnd = nt.getChildNodeDefs();
- for (int i = 0; i < cnd.length; i++) {
- if (cnd[i].getDeclaringNodeType().getName().equals(nt.getName())) {
- ntDef.addContent(NodeDefImpl.create(cnd[i]).toXml());
- }
- }
-
- // declared propertyDefs
- PropertyDef[] pd = nt.getPropertyDefs();
- for (int i = 0; i < pd.length; i++) {
- if (pd[i].getDeclaringNodeType().getName().equals(nt.getName())) {
- ntDef.addContent(PropertyDefImpl.create(pd[i]).toXml());
- }
- }
-
- String primaryItemName = nt.getPrimaryItemName();
- if (primaryItemName != null) {
- ntDef.setAttribute(ATTR_PRIMARYITEMNAME, primaryItemName);
- }
- report.addContent(ntDef);
- }
-
- Document reportDoc = new Document(report);
- return reportDoc;
- } catch (RepositoryException e) {
- throw new JcrDavException(e);
- }
- }
-
- /**
- * Parse the Xml element in the info object an return an interator over
- * the specified node types.
- *
- * @return
- * @throws RepositoryException
- * @throws DavException
- */
- private NodeTypeIterator getNodeTypes() throws RepositoryException, DavException {
- NodeTypeIterator ntIter = null;
- Iterator it = info.getReportElement().getChildren().iterator();
- while (it.hasNext() && ntIter == null) {
- Element elem = (Element) it.next();
- if (elem.getNamespace().equals(NAMESPACE)) {
- String name = elem.getName();
- if (XML_REPORT_ALLNODETYPES.equals(name)) {
- ntIter = ntMgr.getAllNodeTypes();
- } else if (XML_REPORT_MIXINNODETYPES.equals(name)) {
- ntIter = ntMgr.getMixinNodeTypes();
- } else if (XML_REPORT_PRIMARYNODETYPES.equals(name)) {
- ntIter = ntMgr.getPrimaryNodeTypes();
- }
- }
- }
- // None of the simple types. test if a report for individual nodetypes
- // was request. If not, the request body is not valid.
- if (ntIter == null) {
- List ntList = new ArrayList();
- List elemList = info.getReportElement().getChildren(XML_NODETYPE, NAMESPACE);
- if (elemList.isEmpty()) {
- // throw exception if the request body does not contain a single jcr:nodetype element
- throw new DavException(DavServletResponse.SC_BAD_REQUEST, "NodeTypes report: request body has invalid format.");
- }
- Iterator elemIter = elemList.iterator();
- while (elemIter.hasNext()) {
- String nodetypeName = ((Element)elemIter.next()).getChildText(XML_NODETYPENAME, NAMESPACE);
- if (nodetypeName != null) {
- ntList.add(ntMgr.getNodeType(nodetypeName));
- }
- }
- ntIter = new IteratorHelper(Collections.unmodifiableCollection(ntList));
- }
-
- return ntIter;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/report/RegisteredNamespacesReport.java b/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/report/RegisteredNamespacesReport.java
deleted file mode 100644
index 0ed8fee63f4..00000000000
--- a/contrib/jcr-server/server/src/java/org/apache/jackrabbit/webdav/spi/version/report/RegisteredNamespacesReport.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.spi.version.report;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.version.report.*;
-import org.apache.jackrabbit.webdav.version.DeltaVResource;
-import org.apache.jackrabbit.webdav.DavException;
-import org.apache.jackrabbit.webdav.DavServletResponse;
-import org.apache.jackrabbit.webdav.DavSession;
-import org.apache.jackrabbit.webdav.spi.JcrDavException;
-import org.apache.jackrabbit.webdav.spi.ItemResourceConstants;
-import org.jdom.Document;
-import org.jdom.Element;
-
-import javax.jcr.*;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * NodeTypesReport allows to retrieve the definition of a single
- * or multiple node types. The request body must be a 'jcr:nodetypes' element:
- *
-<%
- Repository rep = RepositoryAccessServlet.getRepository();
-
-%>Powered by <%= rep.getDescriptor(Repository.REP_NAME_DESC)%> version <%= rep.getDescriptor(Repository.REP_VERSION_DESC) %>.
-
-
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/maven.xml b/contrib/jcr-server/webdav/maven.xml
deleted file mode 100644
index ef564ff1229..00000000000
--- a/contrib/jcr-server/webdav/maven.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/contrib/jcr-server/webdav/project.properties b/contrib/jcr-server/webdav/project.properties
deleted file mode 100644
index 0569e85c372..00000000000
--- a/contrib/jcr-server/webdav/project.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-maven.javadoc.links=http://java.sun.com/j2se/1.4.2/docs/api/,http://www.day.com/maven/jsr170/javadocs/jcr-0.16.1-pfd/
-maven.repo.remote = http://www.ibiblio.org/maven/,http://www.day.com/maven/
diff --git a/contrib/jcr-server/webdav/project.xml b/contrib/jcr-server/webdav/project.xml
deleted file mode 100644
index 8c77de0bc07..00000000000
--- a/contrib/jcr-server/webdav/project.xml
+++ /dev/null
@@ -1,119 +0,0 @@
-
-
-
-
-
-
- ${basedir}/../project.xml
- jcr-webdav
- jcr-server
- jar
- JCRWebdavServer Webdav Library
-
-
-
-
-
-
- jsr170
- jcr
- 0.16.2
- http://www.day.com/maven/jsr170/jars/jcr-0.16.2.jar
-
-
- jackrabbit
- 0.16.2-dev
-
-
- jdom
- 1.0
-
-
- log4j
- 1.2.8
-
-
- servletapi
- 2.3
-
-
- jcr-rmi
- 0.16.2
-
-
-
-
-
-
-
-
-
- ${basedir}/src/java
-
-
- src/java
-
- **/*.xml
- **/*.xsd
- **/*.properties
- **/*.dtd
-
-
-
-
-
-
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavConstants.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavConstants.java
deleted file mode 100644
index 0017fb855d3..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavConstants.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav;
-
-import org.jdom.Namespace;
-
-import java.text.SimpleDateFormat;
-
-/**
- * DavConstants provide constants for request and response
- * headers, Xml elements and property names defined by
- * RFC 2518. In addition
- * common date formats (creation date and modification time) are included.
- */
-public interface DavConstants {
-
- /**
- * Request and response headers and some value constants
- */
- //-------------------------------------------------------------- Headers ---
- public static final String HEADER_DAV = "DAV";
- public static final String HEADER_DESTINATION = "Destination";
- public static final String HEADER_IF = "If";
- public static final String HEADER_AUTHORIZATION = "Authorization";
-
- //---------------------------------------------------- Lock-Token header ---
- public static final String HEADER_LOCK_TOKEN = "Lock-Token";
- public static final String OPAQUE_LOCK_TOKEN_PREFIX = "opaquelocktoken:";
-
- //------------------------------------------------------- Timeout header ---
- public static final String HEADER_TIMEOUT = "Timeout";
- public static final String TIMEOUT_INFINITE = "Infinite";
- public static final long INFINITE_TIMEOUT = Long.MAX_VALUE;
- public static final long UNDEFINED_TIMEOUT = Long.MIN_VALUE;
-
- //----------------------------------------------------- Overwrite header ---
- public static final String HEADER_OVERWRITE = "Overwrite";
- public static final String NO_OVERWRITE = "T";
-
- //--------------------------------------------------------- Depth header ---
- public static final String HEADER_DEPTH = "Depth";
- public static final String DEPTH_INFINITY_S = "infinity";
- public static final int DEPTH_INFINITY = Integer.MAX_VALUE;
- public static final int DEPTH_0 = 0;
- public static final int DEPTH_1 = 1;
-
- /**
- * Default Namespace constant
- */
- public static final Namespace NAMESPACE = Namespace.getNamespace("D", "DAV:");
-
- /**
- * Xml element names used for response and request body
- */
- public static final String XML_ALLPROP = "allprop";
- public static final String XML_COLLECTION = "collection";
- public static final String XML_DST = "dst";
- public static final String XML_HREF = "href";
- public static final String XML_KEEPALIVE = "keepalive";
- public static final String XML_LINK = "link";
- public static final String XML_MULTISTATUS = "multistatus";
- public static final String XML_OMIT = "omit";
- public static final String XML_PROP = "prop";
- public static final String XML_PROPERTYBEHAVIOR = "propertybehavior";
- public static final String XML_PROPERTYUPDATE = "propertyupdate";
- public static final String XML_PROPFIND = "propfind";
- public static final String XML_PROPNAME = "propname";
- public static final String XML_PROPSTAT = "propstat";
- public static final String XML_REMOVE = "remove";
- public static final String XML_RESPONSE = "response";
- public static final String XML_RESPONSEDESCRIPTION = "responsedescription";
- public static final String XML_SET = "set";
- public static final String XML_SOURCE = "source";
- public static final String XML_STATUS = "status";
-
- /**
- * XML element names related to locking
- */
- public static final String XML_ACTIVELOCK = "activelock";
- public static final String XML_DEPTH = "depth";
- public static final String XML_LOCKTOKEN = "locktoken";
- public static final String XML_TIMEOUT = "timeout";
- public static final String XML_LOCKSCOPE = "lockscope";
- public static final String XML_EXCLUSIVE = "exclusive";
- public static final String XML_SHARED = "shared";
- public static final String XML_LOCKENTRY = "lockentry";
- public static final String XML_LOCKINFO = "lockinfo";
- public static final String XML_LOCKTYPE = "locktype";
- public static final String XML_WRITE = "write";
- public static final String XML_OWNER = "owner";
-
- /**
- * Webdav property names as defined by RFC 2518
- * Note: Microsoft webdav clients as well as Webdrive request additional
- * property (e.g. href, name, owner, isRootLocation, isCollection) within the
- * default namespace, which are are ignored by this implementation, except
- * for the 'isCollection' property, needed for XP built-in clients.
- */
- public static final String PROPERTY_CREATIONDATE = "creationdate";
- public static final String PROPERTY_DISPLAYNAME = "displayname";
- public static final String PROPERTY_GETCONTENTLANGUAGE = "getcontentlanguage";
- public static final String PROPERTY_GETCONTENTLENGTH = "getcontentlength";
- public static final String PROPERTY_GETCONTENTTYPE = "getcontenttype";
- public static final String PROPERTY_GETETAG = "getetag";
- public static final String PROPERTY_GETLASTMODIFIED = "getlastmodified";
- public static final String PROPERTY_LOCKDISCOVERY = "lockdiscovery";
- public static final String PROPERTY_RESOURCETYPE = "resourcetype";
- public static final String PROPERTY_SOURCE = "source";
- public static final String PROPERTY_SUPPORTEDLOCK = "supportedlock";
-
- //--------------------------------------------------- Propfind constants ---
- public static final int PROPFIND_BY_PROPERTY = 0;
- public static final int PROPFIND_ALL_PROP = 1;
- public static final int PROPFIND_PROPERTY_NAMES = 2;
-
- //--------------------------------------------------------- date formats ---
- /**
- * modificationDate date format per RFC 1123
- */
- public static SimpleDateFormat modificationDateFormat =
- new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz");
-
- /**
- * Simple date format for the creation date ISO representation (partial).
- */
- public static SimpleDateFormat creationDateFormat =
- new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
-}
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavException.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavException.java
deleted file mode 100644
index 7ebb01220b1..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavException.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav;
-
-import org.apache.log4j.Logger;
-import org.jdom.Element;
-
-import java.util.Properties;
-import java.io.IOException;
-
-/**
- * DavException extends the {@link Exception} class in order
- * to simplify handling of exceptional situations occuring during processing
- * of WebDAV requests and provides possibility to retrieve an Xml representation
- * of the error.
- */
-public class DavException extends Exception {
-
- private static Logger log = Logger.getLogger(DavException.class);
- private static Properties statusPhrases = new Properties();
- static {
- try {
- statusPhrases.load(DavException.class.getResourceAsStream("statuscode.properties"));
- } catch (IOException e) {
- log.error("Failed to load status properties: "+ e.getMessage());
- }
- }
-
- private static final String XML_ERROR = "error";
-
- private int errorCode = DavServletResponse.SC_INTERNAL_SERVER_ERROR;
- private Element conditionElement;
-
- /**
- * Create a new DavException.
- *
- * @param errorCode integer specifying any of the status codes defined by
- * {@link DavServletResponse}.
- * @param message Human readable error message.
- */
- public DavException(int errorCode, String message) {
- super(message);
- this.errorCode = errorCode;
- log.debug("DavException: (" + errorCode + ") " + message);
- }
-
- /**
- * Create a new DavException.
- *
- * @param errorCode integer specifying any of the status codes defined by
- * {@link DavServletResponse}.
- */
- public DavException(int errorCode) {
- this(errorCode, statusPhrases.getProperty(String.valueOf(errorCode)));
- }
-
- /**
- * Create a new DavException.
- *
- * @param errorCode integer specifying any of the status codes defined by
- * {@link DavServletResponse}.
- * @param message
- * @param conditionElement
- */
- public DavException(int errorCode, String message, Element conditionElement) {
- this(errorCode, message);
- this.conditionElement = conditionElement;
- log.debug("DavException: (" + errorCode + ") " + conditionElement.toString());
- }
-
- /**
- * Return the error code attached to this DavException.
- *
- * @return errorCode
- */
- public int getErrorCode() {
- return errorCode;
- }
-
- /**
- * Returns the Xml representation of this DavException. In case
- * no {@link Element} has been passed to the constructor, an empty DAV:error
- * element is returned.
- *
- * @return Xml representation of this exception.
- */
- public Element getError() {
- Element error = new Element(XML_ERROR, DavConstants.NAMESPACE);
- if (conditionElement != null) {
- error.addContent(conditionElement);
- }
- return error;
- }
-
- /**
- * Return the status phrase corresponding to the error code attached to
- * this DavException.
- *
- * @return status phrase corresponding to the error code.
- * @see #getErrorCode()
- */
- public String getStatusPhrase() {
- return getStatusPhrase(errorCode);
- }
-
- /**
- * Returns the status phrase for the given error code.
- *
- * @param errorCode
- * @return status phrase corresponding to the given error code.
- */
- public static String getStatusPhrase(int errorCode) {
- return statusPhrases.getProperty(errorCode+"");
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavLocatorFactory.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavLocatorFactory.java
deleted file mode 100644
index fd1217045fa..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavLocatorFactory.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav;
-
-/**
- * DavLocatorFactory...
- */
-public interface DavLocatorFactory {
-
- /**
- * Create a new DavResourceLocator.
- *
- * @param prefix
- * @param requestHandle
- * @return
- */
- public DavResourceLocator createResourceLocator(String prefix, String requestHandle);
-
- /**
- * Create a new DavResourceLocator.
- *
- * @param prefix
- * @param workspacePath
- * @param resourcePath
- * @return
- */
- public DavResourceLocator createResourceLocator(String prefix, String workspacePath, String resourcePath);
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavMethods.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavMethods.java
deleted file mode 100644
index 2cc0e4ca831..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavMethods.java
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav;
-
-import org.apache.log4j.Logger;
-
-import java.util.HashMap;
-
-/**
- * DavMethods defines constants for the WebDAV METHODS.
- */
-public class DavMethods {
-
- private static Logger log = Logger.getLogger(DavMethods.class);
-
- /**
- * A hashmap of webdav METHODS
- */
- private static HashMap methodMap = new HashMap();
-
- /**
- * An array of method codes that are affected by a Label header
- * @see org.apache.jackrabbit.webdav.version.DeltaVConstants#HEADER_LABEL
- */
- private static int[] labelMethods;
-
- /**
- * The webdav OPTIONS method and public constant
- */
- public static final int DAV_OPTIONS = 1;
- public static final String METHOD_OPTIONS = "OPTIONS";
-
- /**
- * The webdav GET method and public constant
- */
- public static final int DAV_GET = DAV_OPTIONS + 1;
- public static final String METHOD_GET = "GET";
-
- /**
- * The webdav HEAD method and public constant
- */
- public static final int DAV_HEAD = DAV_GET + 1;
- public static final String METHOD_HEAD = "HEAD";
-
-
- /**
- * The webdav POST method and public constant
- */
- public static final int DAV_POST = DAV_HEAD + 1;
- private static final String METHOD_POST = "POST";
-
-
- /** The webdav DELETE method and public constant */
- public static final int DAV_DELETE = DAV_POST + 1;
- public static final String METHOD_DELETE = "DELETE";
-
-
- /** The webdav PUT method and public constant */
- public static final int DAV_PUT = DAV_DELETE + 1;
- public static final String METHOD_PUT = "PUT";
-
-
- /**
- * The webdav PROPFIND method and public constant as defined by
- * RFC 2518.
- */
- public static final int DAV_PROPFIND = DAV_PUT + 1;
- public static final String METHOD_PROPFIND = "PROPFIND";
-
-
- /**
- * The webdav PROPPATCH method and public constant as defined by
- * RFC 2518
- */
- public static final int DAV_PROPPATCH = DAV_PROPFIND + 1;
- public static final String METHOD_PROPPATCH = "PROPPATCH";
-
-
- /**
- * The webdav MKCOL (make collection) method and public constant as defined by
- * RFC 2518
- */
- public static final int DAV_MKCOL = DAV_PROPPATCH + 1;
- public static final String METHOD_MKCOL = "MKCOL";
-
-
- /**
- * The webdav COPY method and public constant as defined by
- * RFC 2518
- */
- public static final int DAV_COPY = DAV_MKCOL + 1;
- public static final String METHOD_COPY = "COPY";
-
-
- /**
- * The webdav MOVE method and public constant as defined by
- * RFC 2518
- */
- public static final int DAV_MOVE = DAV_COPY + 1;
- public static final String METHOD_MOVE = "MOVE";
-
-
- /**
- * The webdav LOCK method and public constant as defined by
- * RFC 2518
- */
- public static final int DAV_LOCK = DAV_MOVE + 1;
- public static final String METHOD_LOCK = "LOCK";
-
-
- /**
- * The webdav UNLOCK method and public constant as defined by
- * RFC 2518
- */
- public static final int DAV_UNLOCK = DAV_LOCK + 1;
- public static final String METHOD_UNLOCK = "UNLOCK";
-
-
- /**
- * The webdav ORDERPATCH method and public constant
- * defined by RFC 3648.
- */
- public static final int DAV_ORDERPATCH = DAV_UNLOCK + 1;
- public static final String METHOD_ORDERPATCH = "ORDERPATCH";
-
-
- /**
- * The webdav SUBSCRIBE method and public constant.
- * NOTE: This method is not defined by any of the Webdav RFCs
- */
- public static final int DAV_SUBSCRIBE = DAV_ORDERPATCH + 1;
- public static final String METHOD_SUBSCRIBE = "SUBSCRIBE";
-
-
- /**
- * The webdav UNSUBSCRIBE method and public constant
- * NOTE: This method is not defined by any of the Webdav RFCs
- */
- public static final int DAV_UNSUBSCRIBE = DAV_SUBSCRIBE + 1;
- public static final String METHOD_UNSUBSCRIBE = "UNSUBSCRIBE";
-
-
- /**
- * The webdav POLL method and public constant
- * NOTE: This method is not defined by any of the Webdav RFCs
- */
- public static final int DAV_POLL = DAV_UNSUBSCRIBE + 1;
- public static final String METHOD_POLL = "POLL";
-
-
- /**
- * The webdav SEARCH method and public constant as defined by the
- * Webdav Search internet draft.
- */
- public static final int DAV_SEARCH = DAV_POLL + 1;
- public static final String METHOD_SEARCH = "SEARCH";
-
-
- /**
- * The webdav REPORT method and public constant defined by
- * RFC 3253
- */
- public static final int DAV_REPORT = DAV_SEARCH + 1;
- public static final String METHOD_REPORT = "REPORT";
-
-
- /**
- * The webdav VERSION-CONTROL method and public constant defined by
- * RFC 3253
- */
- public static final int DAV_VERSION_CONTROL = DAV_REPORT + 1;
- public static final String METHOD_VERSION_CONTROL = "VERSION-CONTROL";
-
- /**
- * The webdav CHECKIN method and public constant defined by
- * RFC 3253
- */
- public static final int DAV_CHECKIN = DAV_VERSION_CONTROL + 1;
- public static final String METHOD_CHECKIN = "CHECKIN";
-
- /**
- * The webdav CHECKOUT method and public constant defined by
- * RFC 3253
- */
- public static final int DAV_CHECKOUT = DAV_CHECKIN + 1;
- public static final String METHOD_CHECKOUT = "CHECKOUT";
-
- /**
- * The webdav UNCHECKOUT method and public constant defined by
- * RFC 3253
- */
- public static final int DAV_UNCHECKOUT = DAV_CHECKOUT + 1;
- public static final String METHOD_UNCHECKOUT = "UNCHECKOUT";
-
- /**
- * The webdav LABEL method and public constant defined by
- * RFC 3253
- */
- public static final int DAV_LABEL = DAV_UNCHECKOUT + 1;
- public static final String METHOD_LABEL = "LABEL";
-
- /**
- * The webdav MERGE method and public constant defined by
- * RFC 3253
- */
- public static final int DAV_MERGE = DAV_LABEL + 1;
- public static final String METHOD_MERGE = "MERGE";
-
- /**
- * The webdav UPDATE method and public constant defined by
- * RFC 3253
- */
- public static final int DAV_UPDATE = DAV_MERGE + 1;
- public static final String METHOD_UPDATE = "UPDATE";
-
- /**
- * The webdav MKWORKSPACE method and public constant defined by
- * RFC 3253
- */
- public static final int DAV_MKWORKSPACE = DAV_UPDATE + 1;
- public static final String METHOD_MKWORKSPACE = "MKWORKSPACE";
-
- /**
- * Returns webdav method type code, error result <= 0
- * Valid type codes > 0
- */
- public static int getMethodCode(String method) {
- Integer code = (Integer) methodMap.get(method.toUpperCase());
- if (code != null) {
- return code.intValue();
- }
- return 0;
- }
-
- /**
- * Static intializer for methodTable hashmap
- */
- private static void addMethodCode(String method, int code) {
- methodMap.put(method, new Integer(code));
- }
-
- /**
- * Webdav Method table
- */
- static {
- addMethodCode(METHOD_OPTIONS, DAV_OPTIONS);
- addMethodCode(METHOD_GET, DAV_GET);
- addMethodCode(METHOD_HEAD, DAV_HEAD);
- addMethodCode(METHOD_POST, DAV_POST);
- addMethodCode(METHOD_PUT, DAV_PUT);
- addMethodCode(METHOD_DELETE, DAV_DELETE);
- addMethodCode(METHOD_PROPFIND, DAV_PROPFIND);
- addMethodCode(METHOD_PROPPATCH, DAV_PROPPATCH);
- addMethodCode(METHOD_MKCOL, DAV_MKCOL);
- addMethodCode(METHOD_COPY, DAV_COPY);
- addMethodCode(METHOD_MOVE, DAV_MOVE);
- addMethodCode(METHOD_LOCK, DAV_LOCK);
- addMethodCode(METHOD_UNLOCK, DAV_UNLOCK);
- addMethodCode(METHOD_ORDERPATCH, DAV_ORDERPATCH);
- addMethodCode(METHOD_SUBSCRIBE, DAV_SUBSCRIBE);
- addMethodCode(METHOD_UNSUBSCRIBE, DAV_UNSUBSCRIBE);
- addMethodCode(METHOD_POLL, DAV_POLL);
- addMethodCode(METHOD_SEARCH, DAV_SEARCH);
- addMethodCode(METHOD_REPORT, DAV_REPORT);
- addMethodCode(METHOD_VERSION_CONTROL, DAV_VERSION_CONTROL);
- addMethodCode(METHOD_CHECKIN, DAV_CHECKIN);
- addMethodCode(METHOD_CHECKOUT, DAV_CHECKOUT);
- addMethodCode(METHOD_UNCHECKOUT, DAV_UNCHECKOUT);
- addMethodCode(METHOD_LABEL, DAV_LABEL);
- addMethodCode(METHOD_MERGE, DAV_MERGE);
- addMethodCode(METHOD_UPDATE, DAV_UPDATE);
- addMethodCode(METHOD_MKWORKSPACE, DAV_MKWORKSPACE);
-
- labelMethods = new int[] { DAV_GET, DAV_HEAD, DAV_OPTIONS, DAV_PROPFIND,
- DAV_LABEL, DAV_COPY };
- }
-
- public static boolean isMethodAffectedByLabel(String method) {
- int code = getMethodCode(method);
- for (int i = 0; i < labelMethods.length; i++) {
- if (code == labelMethods[i]) {
- return true;
- }
- }
- return false;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavResource.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavResource.java
deleted file mode 100644
index 6a3c2f084ac..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavResource.java
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav;
-
-import org.apache.jackrabbit.webdav.property.*;
-import org.apache.jackrabbit.webdav.lock.*;
-
-import java.io.InputStream;
-
-/**
- * DavResource provides standard WebDAV functionality as specified
- * by RFC 2518.
- */
-public interface DavResource {
-
- /**
- * Constant for WebDAV 1 and 2 compliance class as is represented by this
- * resource.
- */
- public static final String COMPLIANCE_CLASS = "1, 2";
-
- /**
- * String constant representing the WebDAV 1 and 2 method set.
- */
- public static final String METHODS = "OPTIONS, GET, HEAD, POST, TRACE, PROPFIND, PROPPATCH, COPY, PUT, DELETE, MOVE, LOCK, UNLOCK";
-
- /**
- * Constant indicating the undefined modification time.
- */
- public static final long UNDEFINED_MODIFICATIONTIME = -1;
-
- /**
- * Returns a comma separted list of all compliance classes the given
- * resource is fulfilling.
- *
- * @return compliance classes
- */
- public String getComplianceClass();
-
- /**
- * Returns a comma separated list of all METHODS supported by the given
- * resource.
- *
- * @return METHODS supported by this resource.
- */
- public String getSupportedMethods();
-
- /**
- * Returns true if this webdav resource represents an existing repository item.
- *
- * @return true, if the resource represents an existing repository item.
- */
- public boolean exists();
-
- /**
- * Returns true if this webdav resource has the resourcetype 'collection'.
- *
- * @return true if the resource represents a collection resource.
- */
- public boolean isCollection();
-
- /**
- * Returns the display name of this resource.
- *
- * @return display name.
- */
- public String getDisplayName();
-
- /**
- * Returns the {@link DavResourceLocator locator} object for this webdav resource,
- * which encapsulates the information for building the complete 'href'.
- *
- * @return the locator for this resource.
- * @see #getResourcePath()
- * @see #getHref()
- */
- public DavResourceLocator getLocator();
-
- /**
- * Returns the path of the hierarchy element defined by this DavResource.
- * This method is a shortcut for DavResource.getLocator().getResourcePath().
- *
- * @return path of the element defined by this DavResource.
- */
- public String getResourcePath();
-
- /**
- * Returns the absolute href of this resource as returned in the
- * multistatus response body.
- *
- * @return href
- */
- public String getHref();
-
- /**
- * Return the time of the last modification or -1 if the modification time
- * could not be retrieved.
- *
- * @return time of last modification or -1.
- */
- public long getModificationTime();
-
- /**
- * Returns a stream to the resource content in order to respond to a 'GET'
- * request.
- *
- * @return stream to the resource content.
- */
- public InputStream getStream();
-
- /**
- * Returns an array of all {@link DavPropertyName property names} available
- * on this resource.
- *
- * @return an array of property names.
- */
- public DavPropertyName[] getPropertyNames();
-
- /**
- * Return the webdav property with the specified name.
- *
- * @param name name of the webdav property
- * @return the {@link DavProperty} with the given name or null
- * if the property does not exist.
- */
- public DavProperty getProperty(DavPropertyName name);
-
- /**
- * Returns all webdav properties present on this resource.
- *
- * @return a {@link DavPropertySet} containing all webdav property
- * of this resource.
- */
- public DavPropertySet getProperties();
-
- /**
- * Add/Set the specified property on this resource.
- *
- * @param property
- * @throws DavException if an error occurs
- */
- public void setProperty(DavProperty property) throws DavException;
-
- /**
- * Remove the specified property from this resource.
- *
- * @param propertyName
- * @throws DavException if an error occurs
- */
- public void removeProperty(DavPropertyName propertyName) throws DavException;
-
- /**
- * Retrieve the resource this resource is internal member of.
- *
- * @return resource this resource is an internal member of. In case this resource
- * is the root null is returned.
- */
- public DavResource getCollection();
-
- /**
- * Add the given resource as an internal member to this resource.
- *
- * @param resource {@link DavResource} to be added as internal member.
- * @param in {@link java.io.InputStream} providing the content for the
- * internal member.
- * @throws DavException
- */
- public void addMember(DavResource resource, InputStream in)
- throws DavException;
-
- /**
- * Add the given resource as an internal member to this resource.
- *
- * @param resource webdav resource to be added as member.
- * @throws DavException
- */
- public void addMember(DavResource resource) throws DavException;
-
- /**
- * Returns an iterator over all internal members.
- *
- * @return a {@link DavResourceIterator) over all internal members.
- */
- public DavResourceIterator getMembers();
-
- /**
- * Removes the specified member from this resource.
- *
- * @throws DavException
- */
- public void removeMember(DavResource member) throws DavException;
-
- /**
- * Move this DavResource to the given destination resource
- *
- * @param destination
- * @throws DavException
- */
- public void move(DavResource destination) throws DavException;
-
- /**
- * Copy this DavResource to the given destination resource
- *
- * @param destination
- * @param shallow
- * @throws DavException
- */
- public void copy(DavResource destination, boolean shallow) throws DavException;
-
- /**
- * Returns true, if the this resource allows locking. NOTE, that this method
- * does not define, whether a lock/unlock can be successfully executed.
- *
- * @return true, if this resource supports any locking.
- * @param type
- * @param scope
- */
- public boolean isLockable(Type type, Scope scope);
-
- /**
- * Returns true if a lock applies to this resource. This may be either a
- * lock on this resource itself or a deep lock inherited from a collection
- * above this resource.
- * Note, that true is returned whenever a lock applies to that resource even
- * if the lock is expired or not effective due to the fact that the request
- * provides the proper lock token.
- *
- * @return true if a lock applies to this resource.
- * @param type
- */
- public boolean hasLock(Type type, Scope scope);
-
- /**
- * Return the lock present on this webdav resource or null
- * if the resource is either not locked or not lockable at all. Note, that
- * a resource may have a lock that is inherited by a deep lock inforced on
- * one of its 'parent' resources.
- *
- * @return lock information of this resource or null if this
- * resource has no lock applying it. If an error occurs while retrieving the
- * lock information null is returned as well.
- * @param type
- */
- public ActiveLock getLock(Type type, Scope scope) ;
-
- /**
- * Returns an array of all locks applied to the given resource.
- *
- * @return array of locks. The array is empty if there are no locks applied
- * to this resource.
- */
- public ActiveLock[] getLocks();
-
- /**
- * Lock this webdav resource with the information retrieve from the request
- * and return the resulting lockdiscovery object.
- *
- * @param reqLockInfo lock info as retrieved from the request.
- * @return lockdiscovery object to be returned in the response. If the lock
- * could not be obtained a DavException is thrown.
- * @throws DavException if the lock could not be obtained.
- */
- public ActiveLock lock(LockInfo reqLockInfo) throws DavException;
-
- /**
- * Refresh an existing lock by resetting the timeout.
- *
- * @param reqLockInfo lock info as retrieved from the request.
- * @param lockToken identifying the lock to be refreshed.
- * @return lockdiscovery object to be returned in the response body. If the lock
- * could not be refreshed a DavException is thrown.
- * @throws DavException if the lock could not be refreshed.
- */
- public ActiveLock refreshLock(LockInfo reqLockInfo, String lockToken) throws DavException;
-
- /**
- * Remove the lock indentified by the included lock token from this resource.
- * This method will return false if the unlocking did not succeed.
- *
- * @param lockToken indentifying the lock to be removed.
- * @throws DavException if the lock could not be removed.
- */
- public void unlock(String lockToken) throws DavException;
-
- /**
- * Add an external {@link LockManager} to this resource. This method may
- * throw {@link UnsupportedOperationException} if the resource does handle
- * locking itself.
- *
- * @param lockmgr
- * @see LockManager
- */
- public void addLockManager(LockManager lockmgr);
-
- /**
- * Return the DavResourceFactory that created this resource.
- *
- * @return the factory that created this resource.
- */
- public DavResourceFactory getFactory();
-}
-
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavResourceFactory.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavResourceFactory.java
deleted file mode 100644
index 74f43b9bd16..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavResourceFactory.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav;
-
-/**
- * DavResourceFactory interface defines a single method for creating
- * {@link DavResource} objects.
- */
-public interface DavResourceFactory {
-
- /**
- * Create a {@link DavResource} object from the given locator, request and response
- * objects.
- *
- * @param locator locator of the resource
- * @param request
- * @param response
- * @return a new DavResource object.
- * @throws DavException
- */
- public DavResource createResource(DavResourceLocator locator, DavServletRequest request, DavServletResponse response) throws DavException;
-
- /**
- * Create a new {@link DavResource} object from the given locator and session.
- *
- * @param locator
- * @param session
- * @return a new DavResource object.
- * @throws DavException
- */
- public DavResource createResource(DavResourceLocator locator, DavSession session) throws DavException;
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavResourceIterator.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavResourceIterator.java
deleted file mode 100644
index 2d337b8816e..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavResourceIterator.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav;
-
-import java.util.Iterator;
-
-/**
- * DavResourceIterator extends the Iterator interface. Additional
- * METHODS allow to retrieve the next {@link DavResource} from the iterator
- * and the iterators size.
- */
-public interface DavResourceIterator extends Iterator {
-
- /**
- * Returns the next {@link DavResource} in the iterator
- * @return the next {@link DavResource}
- */
- public DavResource nextResource();
-
- /**
- * Return the number of {@link DavResource}s in the iterator.
- * @return number of elements in the iterator.
- */
- public int size();
-}
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavResourceIteratorImpl.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavResourceIteratorImpl.java
deleted file mode 100644
index d99edb031fa..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavResourceIteratorImpl.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav;
-
-import org.apache.log4j.Logger;
-
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * DavResourceIteratorImpl implementation of the {@link DavResourceIterator}
- * interface.
- * NOTE: {@link #remove()} is not implemented.
- */
-public class DavResourceIteratorImpl implements DavResourceIterator {
-
- private static Logger log = Logger.getLogger(DavResourceIteratorImpl.class);
-
- private Iterator it;
- private int size;
-
- /**
- * Create a new DavResourceIterator from the specified list.
- * @param list
- */
- public DavResourceIteratorImpl(List list) {
- it = list.iterator();
- size = list.size();
- }
-
- /**
- * @see DavResourceIterator#hasNext()
- */
- public boolean hasNext() {
- return it.hasNext();
- }
-
- /**
- * @see DavResourceIterator#next()
- */
- public Object next() {
- return it.next();
- }
-
- /**
- * @see DavResourceIterator#nextResource()
- */
- public DavResource nextResource() {
- return (DavResource) next();
- }
-
- /**
- * Returns the size of the initial list.
- *
- * @see DavResourceIterator#size()
- */
- public int size() {
- return size;
- }
-
- /**
- * @see DavResourceIterator#remove()
- */
- public void remove() {
- throw new UnsupportedOperationException("Remove not allowed with DavResourceIteratorImpl");
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavResourceLocator.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavResourceLocator.java
deleted file mode 100644
index a62bd00a500..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavResourceLocator.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav;
-
-/**
- * DavResourceLocator...
- */
-public interface DavResourceLocator {
-
- /**
- * Return the prefix used to build the complete href of the resource as
- * required for the {@link DavConstants#XML_HREF href Xml} element.
- * This includes scheme and host information as well as constant prefixes.
- * However, this must not include workspace prefix.
- *
- * @return prefix needed in order to build the href from a resource path.
- * @see #getResourcePath()
- */
- public String getPrefix();
-
- /**
- * Return the resource path.
- *
- * @return resource path
- */
- public String getResourcePath();
-
- /**
- * Return the path of the workspace the resource identified by this
- * locator is member of.
- *
- * @return path of the workspace
- */
- public String getWorkspacePath();
-
- /**
- * Return the name of the workspace the resource identified by this
- * locator is member of.
- *
- * @return workspace name
- */
- public String getWorkspaceName();
-
- /**
- * Returns true if the specified locator refers to a resource within the
- * same workspace.
- *
- * @param locator
- * @return true if both paths are in the same workspace.
- */
- public boolean isSameWorkspace(DavResourceLocator locator);
-
- /**
- * Returns true if the specified workspace name equals to the workspace
- * name defined with this locator.
- *
- * @param workspaceName
- * @return true if workspace names are equal.
- */
- public boolean isSameWorkspace(String workspaceName);
-
- /**
- * Return the 'href' representation of this locator object.
- *
- * @param isCollection
- * @return 'href' representation of this path
- * @see DavConstants#XML_HREF
- * @see DavResource#getHref()
- */
- public String getHref(boolean isCollection);
-
- /**
- * Returns true if this DavResourceLocator represents the root
- * locator that would be requested with 'hrefPrefix'+'pathPrefix' with or
- * without a trailing '/'.
- *
- * @return true if this locator object belongs to the root resource.
- */
- public boolean isRootLocation();
-
- /**
- * Return the locator factory that created this locator.
- *
- * @return the locator factory
- */
- public DavLocatorFactory getFactory();
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavServletRequest.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavServletRequest.java
deleted file mode 100644
index 5223d4e49f1..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavServletRequest.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav;
-
-import org.apache.jackrabbit.webdav.property.DavPropertySet;
-import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
-import org.apache.jackrabbit.webdav.lock.LockInfo;
-import org.jdom.Document;
-
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * DavServletRequest extends the HttpServletRequest by Webdav
- * specific METHODS.
- */
-public interface DavServletRequest extends HttpServletRequest {
-
- /**
- * Sets the DavSession to this request.
- *
- * @param session
- */
- public void setDavSession(DavSession session);
-
- /**
- * Returns the {@link DavSession} created for this request.
- *
- * @return session for this resource
- */
- public DavSession getDavSession();
-
- /**
- * Return the locator of the requested {@link DavResource resource}.
- *
- * @return locator of the requested {@link DavResource resource}.
- */
- public DavResourceLocator getRequestLocator();
-
- /**
- * Parse the {@link DavConstants#HEADER_DESTINATION Destination header}
- * and return the locator of the corresponding {@link DavResource resource}.
- *
- * @return locator of the resource specified with the Destination header.
- * @see DavConstants#HEADER_DESTINATION
- */
- public DavResourceLocator getDestinationLocator();
-
- /**
- * Returns true if the {@link DavConstants#HEADER_OVERWRITE Overwrite header}
- * is set to 'T' thus instructing the server to overwrite the state of a
- * non-null destination resource during a COPY or MOVE. A Overwrite header
- * value of 'F' will return false.
- *
- * @return true if the Overwrite header is set to 'T', false if it is set
- * to 'F'.
- * @see DavConstants#HEADER_OVERWRITE
- */
- public boolean isOverwrite();
-
- /**
- * Return the integer representation of the given {@link DavConstants#HEADER_DEPTH
- * Depth header}. 'Infinity' is represented by {@link DavConstants#DEPTH_INFINITY}.
- *
- * @return integer representation of the {@link DavConstants#HEADER_DEPTH
- * Depth header}.
- * @see DavConstants#HEADER_DEPTH
- */
- public int getDepth();
-
- /**
- * Returns the integer representation of the {@link DavConstants#HEADER_DEPTH
- * Depth header} or the given defaultValue, if the Depth header is missing.
- *
- * @param defaultValue to be returned if no Depth header is present.
- * @return integer representation of the {@link DavConstants#HEADER_DEPTH
- * Depth header} or the given defaultValue.
- * @see DavConstants#HEADER_DEPTH
- */
- public int getDepth(int defaultValue);
-
- /**
- * Returns the token present in the {@link DavConstants#HEADER_LOCK_TOKEN
- * Lock-Token Header} or null if no such header is available.
- * Note: The 'Lock-Token' header is sent with UNLOCK requests and with
- * lock responses only. For any other request that may be affected by a lock
- * the 'If' header field is responsible.
- *
- * @return the token present in the Lock-Token header.
- * @see DavConstants#HEADER_LOCK_TOKEN
- */
- public String getLockToken();
-
- /**
- * Return the timeout requested in the {@link DavConstants#HEADER_TIMEOUT
- * Timeout header} as long. The representation of the
- * 'Infinite' timeout is left to the implementation.
- *
- * @return long value representation of the Timeout header.
- * @see DavConstants#HEADER_TIMEOUT
- * @see DavConstants#TIMEOUT_INFINITE
- */
- public long getTimeout();
-
- /**
- * Parse the Xml request body and return a {@link org.jdom.Document}.
- * If the request body can not be parsed null is returned.
- *
- * @return Document representing the Xml request body or null.
- */
- public Document getRequestDocument();
-
- /**
- * Return the type of PROPFIND request as indicated by the PROPFIND request
- * body.
- *
- * @return type of PROPFIND request
- * @see DavConstants#PROPFIND_ALL_PROP
- * @see DavConstants#PROPFIND_BY_PROPERTY
- * @see DavConstants#PROPFIND_PROPERTY_NAMES
- */
- public int getPropFindType();
-
- /**
- * Return the set of properties the client requested with a PROPFIND request
- * or an empty set if the type of PROPFIND request was {@link DavConstants#PROPFIND_ALL_PROP}
- * or {@link DavConstants#PROPFIND_PROPERTY_NAMES}.
- *
- * @return set of properties the client requested with a PROPFIND request
- */
- public DavPropertyNameSet getPropFindProperties();
-
- /**
- * Return the set of properties the client wanted to modify / create with a
- * PROPPATCH request, i.e. all entries in the <propertyupdate> element
- * of the request body with name <set>.
- *
- * @return set of properties the client wanted to modify / create with a
- * PROPPATCH request.
- */
- public DavPropertySet getPropPatchSetProperties();
-
- /**
- * Return the set of property names the client wanted to remove with a
- * PROPPATCH request, i.e. all entries in the <propertyupdate> element
- * of the request body with name <remove>.
- * Note, that in constrast to the <set> Xml element, all the XML
- * elements in a prop XML element inside of a remove XML element must be
- * empty, as only the names of properties to be removed are required. Therefore
- * a DavPropertyNameSet is returned and not a DavPropertySet
- *
- * @return set of property names the client wanted to remove with a
- * PROPPATCH request.
- */
- public DavPropertyNameSet getPropPatchRemoveProperties();
-
- /**
- * Return the parsed 'lockinfo' request body, the {@link DavConstants#HEADER_TIMEOUT
- * Timeout header} and the {@link DavConstants#HEADER_DEPTH Depth header}
- * of a LOCK request as LockInfo object.
- *
- * @return LockInfo object encapsulating the information
- * present in the LOCK request.
- * @see DavConstants#HEADER_TIMEOUT
- * @see DavConstants#HEADER_DEPTH
- * @see DavConstants#XML_LOCKINFO
- */
- public LockInfo getLockInfo();
-
- /**
- * Returns true, if the {@link DavConstants#HEADER_IF If header} present
- * with the request matches the given resource.
- *
- * @param resource
- * @return true, if the test is successful, false otherwise.
- */
- public boolean matchesIfHeader(DavResource resource);
-
- /**
- * Returns true, if the {@link DavConstants#HEADER_IF If header} present
- * with the request matches to the given href, token and eTag.
- *
- * @param href
- * @param token
- * @param eTag
- * @return true, if the test is successful, false otherwise.
- */
- public boolean matchesIfHeader(String href, String token, String eTag);
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavServletResponse.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavServletResponse.java
deleted file mode 100644
index 5266e4dcd38..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavServletResponse.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav;
-
-import org.apache.jackrabbit.webdav.lock.ActiveLock;
-import org.jdom.Document;
-
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-
-/**
- * WebdavResponse extends the HttpServletResponse by
- * Webdav specific status codes and METHODS.
- */
-public interface DavServletResponse extends HttpServletResponse {
-
- /**
- * The 102 (Processing) status code is an interim response used to
- * inform the client that the server has accepted the complete request,
- * but has not yet completed it.
- */
- int SC_PROCESSING = 102;
-
- /**
- * Status code (207) indicating that the response requires
- * providing status for multiple independent operations.
- */
- int SC_MULTI_STATUS = 207;
-
- /**
- * Status code (422) indicating the entity body submitted with
- * the PATCH method was not understood by the resource.
- */
- int SC_UNPROCESSABLE_ENTITY = 422;
-
- /**
- * Status code (423) indicating the destination resource of a
- * method is locked, and either the request did not contain a
- * valid Lock-Info header, or the Lock-Info header identifies
- * a lock held by another principal.
- */
- int SC_LOCKED = 423;
-
- /**
- * Status code (424) incidating that the method could not be
- * performed on the resource, because the requested action depended
- * on another action which failed.
- */
- int SC_FAILED_DEPENDENCY = 424;
-
- /**
- * Status code (507) indicating that the resource does not have
- * sufficient space to record the state of the resource after the
- * execution of this method.
- */
- int SC_INSUFFICIENT_SPACE_ON_RESOURCE = 507;
-
- /**
- * Send a response body given more detailed information about the error
- * occured.
- *
- * @param error
- * @throws IOException
- */
- public void sendErrorResponse(DavException error) throws IOException;
-
- /**
- * Send the multistatus response to the client. A multistatus response
- * is returned in response to a successful PROPFIND and PROPPATCH request.
- * In addition multistatus response is required response in case a COPY,
- * MOVE, DELETE, LOCK or PROPPATCH request fails.
- *
- * @param multistatus
- * @throws IOException
- * @see #SC_MULTI_STATUS
- */
- public void sendMultiStatusResponse(MultiStatus multistatus) throws IOException;
-
- /**
- * Send the lock response for a successful LOCK request. The given ActiveLock
- * object is included in the lockdiscovery property of the response
- * body as required by RFC 2518.
- *
- * @param lock
- * @throws IOException
- * @see DavConstants#PROPERTY_LOCKDISCOVERY
- */
- public void sendLockResponse(ActiveLock lock) throws IOException;
-
- /**
- * Send the lock response for a successful LOCK request, that was intended
- * to refresh an existing lock. The locks array must contain at least
- * a single element; the ActiveLock objects are then
- * included in the lockdiscovery property of the response body as required
- * by RFC 2518.
- *
- * @param locks
- * @throws IOException
- * @see DavConstants#PROPERTY_LOCKDISCOVERY
- */
- public void sendRefreshLockResponse(ActiveLock[] locks) throws IOException;
-
- /**
- * Generic method to return an Xml response body.
- *
- * @param xmlDoc Xml document representing the response body.
- * @param status Status code to be used with {@link #setStatus(int)}.
- * @throws IOException
- */
- public void sendXmlResponse(Document xmlDoc, int status) throws IOException;
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavSession.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavSession.java
deleted file mode 100644
index 78d8e672689..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavSession.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav;
-
-import javax.jcr.Session;
-
-/**
- * DavSession wraps a {@link Session repository session}
- * object, that is obtained on
- * {@link javax.jcr.Repository#login(javax.jcr.Credentials, String) login} to
- * the underlaying repository.
- */
-public interface DavSession {
-
- /**
- * Adds a reference to this DavSession indicating that
- * the underlaying {@link Session} object is needed for actions spanning over
- * multiple requests.
- *
- * @param reference to be added.
- */
- public void addReference(Object reference);
-
- /**
- * Releasing a reference to this DavSession. If no more
- * references are present, the underlaying {@link Session} may be discarded
- * (e.g by calling {@link Session#logout()}.
- *
- * @param reference to be removed.
- */
- public void removeReference(Object reference);
-
- /**
- * Unwrap the {@link Session repository session} object.
- *
- * @return the session object wrapped by this DavSession
- */
- public Session getRepositorySession();
-
- /**
- * Adds a lock token to this DavSession.
- *
- * @param token
- */
- public void addLockToken(String token);
-
- /**
- * Returns the lock tokens of this DavSession.
- *
- * @return
- */
- public String[] getLockTokens();
-
- /**
- * Removes a lock token from this DavSession.
- *
- * @param token
- */
- public void removeLockToken(String token);
-
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavSessionProvider.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavSessionProvider.java
deleted file mode 100644
index 7d02360dcfe..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/DavSessionProvider.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav;
-
-/**
- * DavSessionProvider is an interface for components that
- * can initiate and complete {@link DavSession}s. A provider is
- * responsible for supplying references from a {@link WebdavRequest}
- * to a {@link DavSession} when acquired and removing the references
- * when released.
-
- */
-public interface DavSessionProvider {
-
- /**
- * Acquires a DavSession. Upon success, the WebdavRequest will
- * reference that session.
- *
- * A session will not be available if credentials can not be found
- * in the request (meaning that the request has not been
- * authenticated).
- *
- * @param request
- * @throws DavException if a problem occurred while obtaining the
- * session
- */
- public void acquireSession(WebdavRequest request) throws DavException;
-
- /**
- * Releases the reference from the request to the session.
- *
- * @param request
- */
- public void releaseSession(WebdavRequest request);
-}
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/MultiStatus.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/MultiStatus.java
deleted file mode 100644
index 861b6a0e525..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/MultiStatus.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav;
-
-import org.jdom.Document;
-import org.jdom.Element;
-import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-
-/**
- * MultiStatus representing the content of a multistatus response body and
- * allows to retrieve the Xml representation.
- */
-public class MultiStatus {
-
- private ArrayList responses = new ArrayList();
-
- /**
- * Add response(s) to this multistatus, in order to build a multistatus for
- * responding to a PROPFIND request.
- *
- * @param resource The resource to add property from
- * @param propNameSet The requested property names of the PROPFIND request
- * @param propFindType
- * @param depth
- */
- public void addResourceProperties(DavResource resource, DavPropertyNameSet propNameSet,
- int propFindType, int depth) {
- addResponse(new MultiStatusResponse(resource, propNameSet, propFindType));
- if (depth > 0) {
- DavResourceIterator iter = resource.getMembers();
- while (iter.hasNext()) {
- addResourceProperties(iter.nextResource(), propNameSet, propFindType, depth-1);
- }
- }
- }
-
- /**
- * Add response(s) to this multistatus, in order to build a multistatus e.g.
- * in order to respond to a PROPFIND request. Please note, that in terms
- * of PROPFIND, this method would correspond to a
- * {@link DavConstants#PROPFIND_BY_PROPERTY} propfind type.
- *
- * @param resource The resource to add property from
- * @param propNameSet The requested property names of the PROPFIND request
- * @param depth
- * @see #addResourceProperties(DavResource, DavPropertyNameSet, int, int) for
- * the corresponding method that allows to specify the type explicitely.
- */
- public void addResourceProperties(DavResource resource, DavPropertyNameSet propNameSet,
- int depth) {
- addResourceProperties(resource, propNameSet, DavConstants.PROPFIND_BY_PROPERTY, depth);
- }
-
- /**
- * Add response(s) to this multistatus, in order to build a multistatus
- * as returned for failed COPY, MOVE, LOCK or DELETE requests
- *
- * @param resource
- * @param status
- * @param depth
- */
- public void addResourceStatus(DavResource resource, int status, int depth) {
- addResponse(new MultiStatusResponse(resource.getHref(), status));
- if (depth > 0) {
- DavResourceIterator iter = resource.getMembers();
- while (iter.hasNext()) {
- addResourceStatus(iter.nextResource(), status, depth-1);
- }
- }
- }
-
- /**
- * Add a MultiStatusResponse element to this MultiStatus
- *
- * @param response
- */
- public void addResponse(MultiStatusResponse response) {
- responses.add(response);
- }
-
- /**
- * Return the Xml representation of this MultiStatus.
- *
- * @return Xml document
- */
- public Document toXml() {
- Element multistatus = new Element(DavConstants.XML_MULTISTATUS, DavConstants.NAMESPACE);
- Iterator it = responses.iterator();
- while(it.hasNext()) {
- multistatus.addContent(((MultiStatusResponse)it.next()).toXml());
- }
- return new Document(multistatus);
- }
-}
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/MultiStatusResponse.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/MultiStatusResponse.java
deleted file mode 100644
index 601cb18cb68..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/MultiStatusResponse.java
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav;
-
-import org.jdom.Element;
-import org.apache.jackrabbit.webdav.property.*;
-import org.apache.jackrabbit.webdav.util.XmlUtil;
-
-import java.util.HashMap;
-import java.util.Iterator;
-
-/**
- * The WebdavMultistatusResponse class implements a structure that
- * hold a WebDAV multistatus response. Properties can be added to this response
- * with the respective error/status code.
- */
-public class MultiStatusResponse implements DavConstants {
-
- /**
- * The content the 'href' element for this response
- */
- private final String href;
-
- /**
- * The '200' set (since this is used very often)
- */
- private final Element status200;
-
- /**
- * The '404' set (since this is used very often)
- */
- private final Element status404;
-
- /**
- * Hashmap containing all status
- */
- private final HashMap statusMap = new HashMap();
-
- /**
- * An optional response description.
- */
- private String responseDescription;
-
- /**
- * Constructs an empty WebDAV multistatus response
- */
- public MultiStatusResponse(String href) {
- this.href = href;
- status200 = new Element(XML_PROP, NAMESPACE);
- status404 = new Element(XML_PROP, NAMESPACE);
- statusMap.put(new Integer(DavServletResponse.SC_OK), status200);
- statusMap.put(new Integer(DavServletResponse.SC_NOT_FOUND), status404);
- }
-
- /**
- * Constucts a WebDAV multistatus response and retrieves the resource properties
- * according to the given DavPropertyNameSet.
- *
- * @param resource
- * @param propNameSet
- */
- public MultiStatusResponse(DavResource resource, DavPropertyNameSet propNameSet) {
- this(resource, propNameSet, PROPFIND_BY_PROPERTY);
- }
-
- /**
- * Constucts a WebDAV multistatus response and retrieves the resource properties
- * according to the given DavPropertyNameSet. It adds all known
- * property to the '200' set, while unknown properties are added to the '404' set.
- *
- * Note, that the set of property names is ignored in case of a {@link #PROPFIND_ALL_PROP}
- * and {@link #PROPFIND_PROPERTY_NAMES} propFindType.
- *
- * @param resource The resource to retrieve the property from
- * @param propNameSet The property name set as obtained from the request body.
- * @param propFindType any of the following values: {@link #PROPFIND_ALL_PROP},
- * {@link #PROPFIND_BY_PROPERTY}, {@link #PROPFIND_PROPERTY_NAMES}
- */
- public MultiStatusResponse(DavResource resource, DavPropertyNameSet propNameSet,
- int propFindType) {
- this(resource.getHref());
-
- // only property names requested
- if (propFindType == PROPFIND_PROPERTY_NAMES) {
- DavPropertyName[] propNames = resource.getPropertyNames();
- for (int i = 0; i < propNames.length; i++) {
- status200.addContent(propNames[i].toXml());
- }
- // all or a specified set of property and their values requested.
- } else {
- // clone set of property, since several resources could use this again
- propNameSet = new DavPropertyNameSet(propNameSet);
- // Add requested properties or all non-protected properties
- DavPropertyIterator iter = resource.getProperties().iterator();
- while (iter.hasNext()) {
- DavProperty wdp = iter.nextProperty();
- if ((propFindType == PROPFIND_ALL_PROP && !wdp.isProtected()) || propNameSet.remove(wdp.getName())) {
- status200.addContent(wdp.toXml());
- }
- }
-
- if (propFindType != PROPFIND_ALL_PROP) {
- Iterator iter1 = propNameSet.iterator();
- while (iter1.hasNext()) {
- DavPropertyName propName = (DavPropertyName) iter1.next();
- status404.addContent(propName.toXml());
- }
- }
- }
- }
-
- /**
- * Constructs an WebDAV multistatus response for a given resource. This
- * would be used by COPY, MOVE, DELETE, LOCK, UNLOCK that require a multistatus
- * in case of failure.
- */
- public MultiStatusResponse(String href, int status) {
- this(href);
- statusMap.put(new Integer(status), new Element(null));
- }
-
- /**
- * Adds a JDOM element to this response
- *
- * @param prop the property to add
- * @param status the status of the response set to select
- */
- private void add(Element prop, int status) {
- Integer statusKey = new Integer(status);
- Element propsContainer = (Element) statusMap.get(statusKey);
- if (propsContainer == null) {
- propsContainer = new Element(XML_PROP, NAMESPACE);
- statusMap.put(statusKey, propsContainer);
- }
- propsContainer.addContent(prop);
- }
-
- /**
- * Adds a property to this response '200' propstat set.
- *
- * @param prop the property to add
- */
- public void add(DavProperty prop) {
- status200.addContent(prop.toXml());
- }
-
- /**
- * Adds a property name to this response '200' propstat set.
- *
- * @param name the property name to add
- */
- public void add(DavPropertyName name) {
- status200.addContent(name.toXml());
- }
-
- /**
- * Adds a property to this response
- *
- * @param prop the property to add
- * @param status the status of the response set to select
- */
- public void add(DavProperty prop, int status) {
- add(prop.toXml(), status);
- }
-
- /**
- * Adds a property name to this response
- *
- * @param name the property name to add
- * @param status the status of the response set to select
- */
- public void add(DavPropertyName name, int status) {
- add(name.toXml(), status);
- }
-
- /**
- * Set the content of the optional response description element, which is
- * intended to contain a message that can be displayed to the user
- * explaining the nature of this response.
- *
- * @param responseDescription
- */
- public void setResponseDescription(String responseDescription) {
- this.responseDescription = responseDescription;
- }
-
- /**
- * Creates the JDOM element for this reponse.
- *
- * @return A JDOM element of this response
- */
- public Element toXml() {
- // don't create empty 'href' responses
- if ("".equals(href)) {
- return null;
- }
-
- Element response= new Element(XML_RESPONSE, NAMESPACE);
-
- // add ''
- response.addContent(XmlUtil.hrefToXml(href));
-
- // add '' elements or a single '' element
- Iterator iter = statusMap.keySet().iterator();
- while (iter.hasNext()) {
- Integer statusKey = (Integer) iter.next();
- Element prop = (Element) statusMap.get(statusKey);
- if (prop != null) {
- Element status = new Element(XML_STATUS, NAMESPACE);
- status.setText("HTTP/1.1 " + statusKey + " " + DavException.getStatusPhrase(statusKey.intValue()));
-
- if (XML_PROP.equals(prop.getName())) {
- // do not add empty propstat elements
- if (prop.getContentSize() > 0) {
- Element propstat = new Element(XML_PROPSTAT, NAMESPACE);
- propstat.addContent(prop);
- propstat.addContent(status);
- response.addContent(propstat);
- }
- } else {
- response.addContent(status);
- }
- }
- }
- // add the optional '' element
- if (responseDescription != null) {
- Element desc = new Element(XML_RESPONSEDESCRIPTION, NAMESPACE);
- desc.setText(responseDescription);
- response.addContent(desc);
- }
- return response;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/WebdavRequest.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/WebdavRequest.java
deleted file mode 100644
index 9e5bba7163d..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/WebdavRequest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav;
-
-import org.apache.jackrabbit.webdav.observation.ObservationDavServletRequest;
-import org.apache.jackrabbit.webdav.ordering.OrderingDavServletRequest;
-import org.apache.jackrabbit.webdav.transaction.TransactionDavServletRequest;
-import org.apache.jackrabbit.webdav.version.DeltaVServletRequest;
-
-/**
- * The empty WebdavRequest interface collects the functionality
- * defined by {@link org.apache.jackrabbit.webdav.DavServletRequest} encapsulting
- * the core Webdav specification (RFC 2518) as well as the various extensions
- * used for observation and transaction support, ordering of collections, search
- * and versioning.
- */
-public interface WebdavRequest extends DavServletRequest,
- ObservationDavServletRequest, OrderingDavServletRequest,
- TransactionDavServletRequest, DeltaVServletRequest {
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/WebdavRequestImpl.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/WebdavRequestImpl.java
deleted file mode 100644
index 1f7ec9df5c1..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/WebdavRequestImpl.java
+++ /dev/null
@@ -1,908 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.util.Text;
-import org.apache.jackrabbit.webdav.lock.LockInfo;
-import org.apache.jackrabbit.webdav.lock.Type;
-import org.apache.jackrabbit.webdav.lock.Scope;
-import org.apache.jackrabbit.webdav.property.*;
-import org.apache.jackrabbit.webdav.transaction.*;
-import org.apache.jackrabbit.webdav.observation.*;
-import org.apache.jackrabbit.webdav.version.*;
-import org.apache.jackrabbit.webdav.version.report.ReportInfo;
-import org.apache.jackrabbit.webdav.ordering.*;
-import org.apache.jackrabbit.webdav.header.DepthHeader;
-import org.jdom.input.SAXBuilder;
-import org.jdom.JDOMException;
-import org.jdom.Document;
-import org.jdom.Element;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpSession;
-import javax.servlet.ServletInputStream;
-import javax.servlet.RequestDispatcher;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.io.BufferedReader;
-import java.util.*;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.security.Principal;
-
-/**
- * WebdavRequestImpl...
- */
-public class WebdavRequestImpl implements WebdavRequest, DavConstants {
-
- private static Logger log = Logger.getLogger(WebdavRequestImpl.class);
-
- private final HttpServletRequest httpRequest;
- private final DavLocatorFactory factory;
- private final IfHeader ifHeader;
- private final String hrefPrefix;
-
- private DavSession session;
-
- private int propfindType = PROPFIND_ALL_PROP;
- private DavPropertyNameSet propfindProps;
- private DavPropertySet proppatchSet;
- private DavPropertyNameSet proppatchRemove;
-
- /**
- * Creates a new DavServletRequest with the given parameters.
- *
- * @param httpRequest
- * @param factory
- */
- public WebdavRequestImpl(HttpServletRequest httpRequest, DavLocatorFactory factory) {
- this.httpRequest = httpRequest;
- this.factory = factory;
- this.ifHeader = new IfHeader(httpRequest);
-
- String host = getHeader("Host");
- String scheme = getScheme();
- hrefPrefix = scheme + "://" + host + getContextPath();
- }
-
- /**
- * Sets the session field and adds all lock tokens present with either the
- * Lock-Token header or the If header to the given session object.
- *
- * @param session
- * @see DavServletRequest#setDavSession(DavSession)
- */
- public void setDavSession(DavSession session) {
- this.session = session;
- // set lock-tokens from header to the current session
- if (session != null && session.getRepositorySession() != null) {
- String lt = getLockToken();
- if (lt != null) {
- session.addLockToken(lt);
- }
- // add all token present in the the If header to the session as well.
- Iterator it = ifHeader.getAllTokens();
- while (it.hasNext()) {
- String ifHeaderToken = (String)it.next();
- session.addLockToken(ifHeaderToken);
- }
- }
- }
-
- /**
- * @see DavServletRequest#getDavSession()
- */
- public DavSession getDavSession() {
- return session;
- }
-
- /**
- * Return a DavResourceLocator representing the request handle.
- *
- * @return locator of the requested resource
- * @see DavServletRequest#getRequestLocator()
- */
- public DavResourceLocator getRequestLocator() {
- String path = getPathInfo();
- if (path == null) {
- path = getServletPath();
- }
- return factory.createResourceLocator(hrefPrefix, path);
- }
-
- /**
- * Parse the destination header field and return the path of the destination
- * resource.
- *
- * @return path of the destination resource.
- * @see #HEADER_DESTINATION
- * @see DavServletRequest#getDestinationLocator
- */
- public DavResourceLocator getDestinationLocator() {
- String destination = httpRequest.getHeader(HEADER_DESTINATION);
- if (destination != null) {
- try {
- URI uri = new URI(destination);
- if (uri.getAuthority().equals(httpRequest.getHeader("Host"))) {
- destination = Text.unescape(uri.getPath());
- }
- } catch (URISyntaxException e) {
- log.debug("Destination is path is not a valid URI ("+e.getMessage()+".");
- int pos = destination.lastIndexOf(":");
- if (pos > 0) {
- destination = destination.substring(destination.indexOf("/",pos));
- log.debug("Tried to retrieve resource destination path from invalid URI: "+destination);
- }
- }
-
- // cut off the context path
- String contextPath = httpRequest.getContextPath();
- if (destination.startsWith(contextPath)) {
- destination = destination.substring(contextPath.length());
- }
- }
- return factory.createResourceLocator(hrefPrefix, destination);
- }
-
- /**
- * Return true if the overwrite header does not inhibit overwriting.
- *
- * @return true if the overwrite header requests 'overwriting'
- * @see #HEADER_OVERWRITE
- * @see DavServletRequest#isOverwrite()
- */
- public boolean isOverwrite() {
- boolean doOverwrite = true;
- String overwriteHeader = httpRequest.getHeader(HEADER_OVERWRITE);
- if (overwriteHeader != null && !overwriteHeader.equalsIgnoreCase(NO_OVERWRITE)){
- doOverwrite = false;
- }
- return doOverwrite;
- }
-
- /**
- * @see DavServletRequest#getDepth(int)
- */
- public int getDepth(int defaultValue) {
- return DepthHeader.parse(httpRequest.getHeader(HEADER_DEPTH), defaultValue).getDepth();
- }
-
- /**
- * @see DavServletRequest#getDepth()
- */
- public int getDepth() {
- return getDepth(DEPTH_INFINITY);
- }
-
- /**
- * Parse the request timeout header and convert the timeout value
- * into a long indicating the number of milliseconds until expiration time
- * is reached.
- * NOTE: If the requested timeout is 'infinite' {@link Long.MAX_VALUE}
- * is returned.
- *
- * @return milliseconds the lock is requested to live.
- * @see DavServletRequest#getTimeout()
- */
- public long getTimeout() {
- String timeoutStr = httpRequest.getHeader(HEADER_TIMEOUT);
- long timeout = UNDEFINED_TIMEOUT;
- if (timeoutStr != null && timeoutStr.length() > 0) {
- int secondsInd = timeoutStr.indexOf("Second-");
- if (secondsInd >= 0) {
- secondsInd += 7; // read over "Second-"
- int i = secondsInd;
- while (i < timeoutStr.length() && Character.isDigit(timeoutStr.charAt(i))) {
- i++;
- }
- try {
- timeout = 1000L * Long.parseLong(timeoutStr.substring(secondsInd, i));
- } catch (NumberFormatException ignore) {
- // ignore an let the lock define the default timeout
- log.error("Invalid timeout format: "+timeoutStr);
- }
- } else if (timeoutStr.equalsIgnoreCase(TIMEOUT_INFINITE)) {
- timeout = INFINITE_TIMEOUT;
- }
- }
- return timeout;
- }
-
- /**
- * Retrive the lock token from the 'Lock-Token' header.
- *
- * @return String representing the lock token sent in the Lock-Token header.
- * @throws IllegalArgumentException If the value has not the correct format.
- * @see #HEADER_LOCK_TOKEN
- * @see DavServletRequest#getLockToken()
- */
- public String getLockToken() {
- return getCodedURLHeader(HEADER_LOCK_TOKEN);
- }
-
- /**
- * @return Xml document
- * @see DavServletRequest#getRequestDocument()
- */
- public Document getRequestDocument() {
- Document requestDocument = null;
- // try to parse the request body
- try {
- InputStream in = httpRequest.getInputStream();
- if (in != null) {
- SAXBuilder builder = new SAXBuilder(false);
- requestDocument = builder.build(in);
- }
- } catch (IOException e) {
- log.warn("Error while reading the request body: " + e.getMessage());
- } catch (JDOMException e) {
- log.warn("Error while building xml document from request body: " + e.getMessage());
- }
- return requestDocument;
- }
-
- /**
- * Returns the type of PROPFIND as indicated by the request body.
- *
- * @return type of the PROPFIND request. Default value is {@link #PROPFIND_ALL_PROP allprops}
- * @see DavServletRequest#getPropFindType()
- */
- public int getPropFindType() {
- if (propfindProps == null) {
- parsePropFindRequest();
- }
- return propfindType;
- }
-
- /**
- * Returns the set of properties requested by the PROPFIND body or an
- * empty set if the {@link #getPropFindType type} is either 'allprop' or
- * 'propname'.
- *
- * @return set of properties requested by the PROPFIND body or an empty set.
- * @see DavServletRequest#getPropFindProperties()
- */
- public DavPropertyNameSet getPropFindProperties() {
- if (propfindProps == null) {
- parsePropFindRequest();
- }
- return propfindProps;
- }
-
- /**
- * Parse the propfind request body in order to determine the type of the propfind
- * and the set of requested property.
- * NOTE: An empty 'propfind' request body will be treated as request for all
- * property according to the specification.
- */
- private void parsePropFindRequest() {
-
- propfindProps = new DavPropertyNameSet();
- Document requestDocument = getRequestDocument();
-
- // propfind httpRequest with empty body or invalid Xml >> retrieve all property
- // TODO: spec requires a 'BAD REQUEST' error code
- if (requestDocument == null) {
- return;
- }
-
- // propfind httpRequest with invalid body >> treat as if empty body
- Element root = requestDocument.getRootElement();
- if (!root.getName().equals(XML_PROPFIND)) {
- log.info("PropFind-Request has no tag.");
- return;
- }
-
- List childList = root.getChildren();
- for (int i = 0; i < childList.size(); i++) {
- Element child = (Element) childList.get(i);
- String nodeName = child.getName();
- if (XML_PROP.equals(nodeName)) {
- propfindType = PROPFIND_BY_PROPERTY;
- propfindProps = new DavPropertyNameSet(child);
- break;
- } else if (XML_PROPNAME.equals(nodeName)) {
- propfindType = PROPFIND_PROPERTY_NAMES;
- break;
- } else if (XML_ALLPROP.equals(nodeName)) {
- propfindType = PROPFIND_ALL_PROP;
- break;
- }
- }
- }
-
- /**
- * Return the list of 'set' entries in the PROPPATCH request body. The list
- * is empty if the request body could not be parsed or if the request body did
- * not contain any 'set' elements.
- *
- * @return the list of 'set' entries in the PROPPATCH request body
- * @see DavServletRequest#getPropPatchSetProperties()
- */
- public DavPropertySet getPropPatchSetProperties() {
- if (proppatchSet == null) {
- parsePropPatchRequest();
- }
- return proppatchSet;
- }
-
- /**
- * Return the list of 'remove' entries in the PROPPATCH request body. The list
- * is empty if the request body could not be parsed or if the request body did
- * not contain any 'remove' elements.
- *
- * @return the list of 'remove' entries in the PROPPATCH request body
- * @see DavServletRequest#getPropPatchRemoveProperties()
- */
- public DavPropertyNameSet getPropPatchRemoveProperties() {
- if (proppatchRemove == null) {
- parsePropPatchRequest();
- }
- return proppatchRemove;
- }
-
- /**
- * Parse the PROPPATCH request body.
- */
- private void parsePropPatchRequest() {
-
- proppatchSet = new DavPropertySet();
- proppatchRemove = new DavPropertyNameSet();
- Document requestDocument = getRequestDocument();
-
- if (requestDocument == null) {
- return;
- }
-
- Element root = requestDocument.getRootElement();
- if (!root.getName().equals(XML_PROPERTYUPDATE)) {
- // we should also check for correct namespace
- log.warn("PropPatch-Request has no tag.");
- return;
- }
-
- List setList = root.getChildren(XML_SET, NAMESPACE);
- if (!setList.isEmpty()) {
- Iterator setIter = setList.iterator();
- while (setIter.hasNext()) {
- Element propElem = ((Element) setIter.next()).getChild(XML_PROP, NAMESPACE);
- Iterator it = propElem.getChildren().iterator();
- while (it.hasNext()) {
- Element propertyElem = (Element) it.next();
- proppatchSet.add(DefaultDavProperty.createFromXml(propertyElem));
- }
- }
- }
-
- // get properties
- List removeList = root.getChildren(XML_REMOVE, NAMESPACE);
- if (!removeList.isEmpty()) {
- Iterator removeIter = removeList.iterator();
- while (removeIter.hasNext()) {
- Element propElem = ((Element) removeIter.next()).getChild(XML_PROP, NAMESPACE);
- Iterator it = propElem.getChildren().iterator();
- while (it.hasNext()) {
- Element propertyElem = (Element) it.next();
- proppatchRemove.add(DavPropertyName.createFromXml(propertyElem));
- }
- }
- }
- }
-
- /**
- * {@link LockInfo} object encapsulating the information passed with a LOCK
- * request if the LOCK request body was valid. If the request body is
- * missing a 'refresh lock' request is assumed. The {@link LockInfo}
- * then only provides timeout and isDeep property and returns true on
- * {@link org.apache.jackrabbit.webdav.lock.LockInfo#isRefreshLock()}
- *
- * @return lock info object or null if an error occured while
- * parsing the request body.
- * @see DavServletRequest#getLockInfo()
- */
- public LockInfo getLockInfo() {
- LockInfo lockInfo = null;
- boolean isDeep = (getDepth(DEPTH_INFINITY) == DEPTH_INFINITY);
- Document requestDocument = getRequestDocument();
- // check if XML request body is present. It SHOULD have one for
- // 'create Lock' request and missing for a 'refresh Lock' request
- if (requestDocument != null) {
- Element root = requestDocument.getRootElement();
- if (root.getName().equals(XML_LOCKINFO)) {
- lockInfo = new LockInfo(root, getTimeout(), isDeep);
- } else {
- log.debug("Lock-Request has no tag.");
- }
- } else {
- lockInfo = new LockInfo(null, getTimeout(), isDeep);
- }
- return lockInfo;
- }
-
- /**
- * MTest if the if header matches the given resource. The comparison is
- * made with the {@link DavResource#getHref()
- * resource href} and the token returned from an exclusive write lock present on
- * the resource. An empty strong ETag is currently assumed.
- * NOTE: If either the If header or the resource is null or if
- * the resource has not applied an exclusive write lock the preconditions are met.
- * If in contrast the lock applied to the given resource returns a
- * null lock token (e.g. for security reasons) or a lock token
- * that does not match, the method will return false.
- *
- * @param resource Webdav resources being operated on
- * @return true if the test is successful and the preconditions for the
- * request processing are fulfilled.
- * @param resource
- * @return
- * @see DavServletRequest#matchesIfHeader(DavResource)
- * @see IfHeader#matches(String, String, String)
- * @see DavResource#hasLock(org.apache.jackrabbit.webdav.lock.Type, org.apache.jackrabbit.webdav.lock.Scope)
- * @see org.apache.jackrabbit.webdav.lock.ActiveLock#getToken()
- */
- public boolean matchesIfHeader(DavResource resource) {
- // no ifheader, no resource or no write lock on resource
- // >> preconditions ok so far
- if (ifHeader == null || resource == null || !resource.hasLock(Type.WRITE, Scope.EXCLUSIVE)) {
- return true;
- }
-
- boolean isMatching = false;
- String lockToken = resource.getLock(Type.WRITE, Scope.EXCLUSIVE).getToken();
- if (lockToken != null) {
- // TODO: strongETag is missing
- isMatching = matchesIfHeader(resource.getHref(), lockToken, "");
- } // else: lockToken is null >> the if-header will not match.
-
- return isMatching;
- }
-
- /**
- * @see DavServletRequest#matchesIfHeader(String, String, String)
- * @see IfHeader#matches(String, String, String)
- */
- public boolean matchesIfHeader(String href, String token, String eTag) {
- return ifHeader.matches(href, token, eTag);
- }
-
- /**
- * Retrieve the header with the given header name and parse the CodedURL
- * value included.
- *
- * @param headerName
- * @return token present in the CodedURL header or null if
- * the header is not present.
- */
- private String getCodedURLHeader(String headerName) {
- String headerValue = null;
- String header = httpRequest.getHeader(headerName);
- if (header != null) {
- int p1 = header.indexOf('<');
- if (p1<0) {
- throw new IllegalArgumentException("Invalid CodedURL header value:"+header);
- }
- int p2 = header.indexOf('>', p1);
- if (p2<0) {
- throw new IllegalArgumentException("Invalid CodedURL header value:"+header);
- }
- headerValue = header.substring(p1+1, p2);
- }
- return headerValue;
- }
-
- //-----------------------------< TransactionDavServletRequest Interface >---
- /**
- *
- * @return
- * @see org.apache.jackrabbit.webdav.transaction.TransactionDavServletRequest#getTransactionId()
- */
- public String getTransactionId() {
- return getCodedURLHeader(TransactionConstants.HEADER_TRANSACTIONID);
- }
-
- /**
- *
- * @return
- * @see org.apache.jackrabbit.webdav.transaction.TransactionDavServletRequest#getTransactionInfo()
- */
- public TransactionInfo getTransactionInfo() {
- Document requestDocument = getRequestDocument();
- if (requestDocument != null) {
- try {
- return new TransactionInfo(requestDocument.getRootElement());
- } catch (IllegalArgumentException e) {
- log.error(e.getMessage());
- }
- }
- return null;
- }
-
- //-----------------------------< ObservationDavServletRequest Interface >---
- /**
- *
- * @return
- * @see org.apache.jackrabbit.webdav.observation.ObservationDavServletRequest#getSubscriptionId()
- */
- public String getSubscriptionId() {
- return getCodedURLHeader(ObservationConstants.HEADER_SUBSCRIPTIONID);
- }
-
- /**
- *
- * @return
- * @see org.apache.jackrabbit.webdav.observation.ObservationDavServletRequest#getSubscriptionInfo()
- */
- public SubscriptionInfo getSubscriptionInfo() {
- Document requestDocument = getRequestDocument();
- if (requestDocument != null) {
- Element root = requestDocument.getRootElement();
- if (ObservationConstants.XML_SUBSCRIPTIONINFO.equals(root.getName())) {
- int depth = getDepth(DEPTH_0);
- return new SubscriptionInfo(root, getTimeout(), depth == DEPTH_INFINITY);
- }
- }
- return null;
- }
-
- //--------------------------------< OrderingDavServletRequest Interface >---
- /**
- *
- * @return
- * @see org.apache.jackrabbit.webdav.ordering.OrderingDavServletRequest#getOrderingType()
- */
- public String getOrderingType() {
- return getHeader(OrderingConstants.HEADER_ORDERING_TYPE);
- }
-
- /**
- *
- * @return
- * @see org.apache.jackrabbit.webdav.ordering.OrderingDavServletRequest#getPosition()
- */
- public Position getPosition() {
- String h = getHeader(OrderingConstants.HEADER_POSITION);
- Position pos = null;
- if (h != null) {
- String[] typeNSegment = h.split("\\s");
- if (typeNSegment.length == 2) {
- try {
- pos = new Position(typeNSegment[0], typeNSegment[1]);
- } catch (IllegalArgumentException e) {
- log.error("Cannot parse Position header: "+e.getMessage());
- }
- }
- }
- return pos;
- }
-
- /**
- *
- * @return OrderPatch object representing the orderpatch request
- * body or null if the
- * @see org.apache.jackrabbit.webdav.ordering.OrderingDavServletRequest#getOrderPatch()
- */
- public OrderPatch getOrderPatch() {
- OrderPatch op = null;
- Document requestDocument = getRequestDocument();
- if (requestDocument != null) {
- Element root = requestDocument.getRootElement();
- if (!OrderingConstants.XML_ORDERPATCH.equals(root.getName()) ||
- root.getChild(OrderingConstants.XML_ORDERING_TYPE) == null) {
- log.error("ORDERPATH request body must start with an 'orderpatch' element, which must contain an 'ordering-type' child element.");
- return op;
- }
-
- try {
- op = new OrderPatch(root);
- } catch (IllegalArgumentException e) {
- log.error(e.getMessage());
- }
- } else {
- log.error("Error while building xml document from ORDERPATH request body.");
- }
- return op;
- }
-
- //-------------------------------------< DeltaVServletRequest interface >---
- /**
- * @see org.apache.jackrabbit.webdav.version.DeltaVServletRequest#getLabel()
- */
- public String getLabel() {
- String label = getHeader(DeltaVConstants.HEADER_LABEL);
- if (label != null) {
- label = Text.unescape(label);
- }
- return label;
- }
-
- /**
- * @see org.apache.jackrabbit.webdav.version.DeltaVServletRequest#getLabelInfo()
- */
- public LabelInfo getLabelInfo() {
- LabelInfo lInfo = null;
- Document requestDocument = getRequestDocument();
- if (requestDocument != null) {
- Element root = requestDocument.getRootElement();
- int depth = getDepth(DEPTH_0);
- try {
- lInfo = new LabelInfo(root, depth);
- } catch (IllegalArgumentException e) {
- log.error(e.getMessage());
- }
- }
- return lInfo;
- }
-
- /**
- * @see org.apache.jackrabbit.webdav.version.DeltaVServletRequest#getMergeInfo()
- */
- public MergeInfo getMergeInfo() {
- MergeInfo mInfo = null;
- Document requestDocument = getRequestDocument();
- if (requestDocument != null) {
- try {
- mInfo = new MergeInfo(requestDocument.getRootElement());
- } catch (IllegalArgumentException e) {
- log.error(e.getMessage());
- }
- }
- return mInfo;
- }
-
- /**
- * @see org.apache.jackrabbit.webdav.version.DeltaVServletRequest#getUpdateInfo()
- */
- public UpdateInfo getUpdateInfo() {
- UpdateInfo uInfo = null;
- Document requestDocument = getRequestDocument();
- if (requestDocument != null) {
- try {
- uInfo = new UpdateInfo(requestDocument.getRootElement());
- } catch (IllegalArgumentException e) {
- log.error(e.getMessage());
- }
- }
- return uInfo;
- }
-
- /**
- * @see org.apache.jackrabbit.webdav.version.DeltaVServletRequest#getReportInfo()
- */
- public ReportInfo getReportInfo() {
- ReportInfo rInfo = null;
- Document requestDocument = getRequestDocument();
- if (requestDocument != null) {
- rInfo = new ReportInfo(requestDocument.getRootElement(), getDepth(DEPTH_0));
- }
- return rInfo;
- }
-
- /**
- * @see org.apache.jackrabbit.webdav.version.DeltaVServletRequest#getOptionsInfo()
- */
- public OptionsInfo getOptionsInfo() {
- OptionsInfo info = null;
- Document requestDocument = getRequestDocument();
- if (requestDocument != null) {
- info = new OptionsInfo(requestDocument.getRootElement());
- }
- return info;
- }
-
- //---------------------------------------< HttpServletRequest interface >---
- public String getAuthType() {
- return httpRequest.getAuthType();
- }
-
- public Cookie[] getCookies() {
- return httpRequest.getCookies();
- }
-
- public long getDateHeader(String s) {
- return httpRequest.getDateHeader(s);
- }
-
- public String getHeader(String s) {
- return httpRequest.getHeader(s);
- }
-
- public Enumeration getHeaders(String s) {
- return httpRequest.getHeaders(s);
- }
-
- public Enumeration getHeaderNames() {
- return httpRequest.getHeaderNames();
- }
-
- public int getIntHeader(String s) {
- return httpRequest.getIntHeader(s);
- }
-
- public String getMethod() {
- return httpRequest.getMethod();
- }
-
- public String getPathInfo() {
- return httpRequest.getPathInfo();
- }
-
- public String getPathTranslated() {
- return httpRequest.getPathTranslated();
- }
-
- public String getContextPath() {
- return httpRequest.getContextPath();
- }
-
- public String getQueryString() {
- return httpRequest.getQueryString();
- }
-
- public String getRemoteUser() {
- return httpRequest.getRemoteUser();
- }
-
- public boolean isUserInRole(String s) {
- return httpRequest.isUserInRole(s);
- }
-
- public Principal getUserPrincipal() {
- return httpRequest.getUserPrincipal();
- }
-
- public String getRequestedSessionId() {
- return httpRequest.getRequestedSessionId();
- }
-
- public String getRequestURI() {
- return httpRequest.getRequestURI();
- }
-
- public StringBuffer getRequestURL() {
- return httpRequest.getRequestURL();
- }
-
- public String getServletPath() {
- return httpRequest.getServletPath();
- }
-
- public HttpSession getSession(boolean b) {
- return httpRequest.getSession(b);
- }
-
- public HttpSession getSession() {
- return httpRequest.getSession();
- }
-
- public boolean isRequestedSessionIdValid() {
- return httpRequest.isRequestedSessionIdValid();
- }
-
- public boolean isRequestedSessionIdFromCookie() {
- return httpRequest.isRequestedSessionIdFromCookie();
- }
-
- public boolean isRequestedSessionIdFromURL() {
- return httpRequest.isRequestedSessionIdFromURL();
- }
-
- public boolean isRequestedSessionIdFromUrl() {
- return httpRequest.isRequestedSessionIdFromUrl();
- }
-
- public Object getAttribute(String s) {
- return httpRequest.getAttribute(s);
- }
-
- public Enumeration getAttributeNames() {
- return httpRequest.getAttributeNames();
- }
-
- public String getCharacterEncoding() {
- return httpRequest.getCharacterEncoding();
- }
-
- public void setCharacterEncoding(String s) throws UnsupportedEncodingException {
- httpRequest.setCharacterEncoding(s);
- }
-
- public int getContentLength() {
- return httpRequest.getContentLength();
- }
-
- public String getContentType() {
- return httpRequest.getContentType();
- }
-
- public ServletInputStream getInputStream() throws IOException {
- return httpRequest.getInputStream();
- }
-
- public String getParameter(String s) {
- return httpRequest.getParameter(s);
- }
-
- public Enumeration getParameterNames() {
- return httpRequest.getParameterNames();
- }
-
- public String[] getParameterValues(String s) {
- return httpRequest.getParameterValues(s);
- }
-
- public Map getParameterMap() {
- return httpRequest.getParameterMap();
- }
-
- public String getProtocol() {
- return httpRequest.getProtocol();
- }
-
- public String getScheme() {
- return httpRequest.getScheme();
- }
-
- public String getServerName() {
- return httpRequest.getServerName();
- }
-
- public int getServerPort() {
- return httpRequest.getServerPort();
- }
-
- public BufferedReader getReader() throws IOException {
- return httpRequest.getReader();
- }
-
- public String getRemoteAddr() {
- return httpRequest.getRemoteAddr();
- }
-
- public String getRemoteHost() {
- return httpRequest.getRemoteHost();
- }
-
- public void setAttribute(String s, Object o) {
- httpRequest.setAttribute(s, o);
- }
-
- public void removeAttribute(String s) {
- httpRequest.removeAttribute(s);
- }
-
- public Locale getLocale() {
- return httpRequest.getLocale();
- }
-
- public Enumeration getLocales() {
- return httpRequest.getLocales();
- }
-
- public boolean isSecure() {
- return httpRequest.isSecure();
- }
-
- public RequestDispatcher getRequestDispatcher(String s) {
- return httpRequest.getRequestDispatcher(s);
- }
-
- public String getRealPath(String s) {
- return httpRequest.getRealPath(s);
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/WebdavResponse.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/WebdavResponse.java
deleted file mode 100644
index 815fb04892c..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/WebdavResponse.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav;
-
-import org.apache.jackrabbit.webdav.observation.ObservationDavServletResponse;
-
-/**
- * The empty WebdavResponse interface collects the functionality
- * defined by {@link org.apache.jackrabbit.webdav.DavServletResponse} encapsulting
- * for the core WebDAV specification (RFC 2518) as well as the various extensions
- * used for observation and transaction support, ordering of collections, search
- * and versioning.
- */
-public interface WebdavResponse extends DavServletResponse,
- ObservationDavServletResponse {
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/WebdavResponseImpl.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/WebdavResponseImpl.java
deleted file mode 100644
index 284e2cfdda8..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/WebdavResponseImpl.java
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav;
-
-import org.jdom.Element;
-import org.jdom.Document;
-import org.jdom.output.XMLOutputter;
-import org.jdom.output.Format;
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.lock.*;
-import org.apache.jackrabbit.webdav.observation.*;
-
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.Cookie;
-import javax.servlet.ServletOutputStream;
-import java.io.IOException;
-import java.io.ByteArrayOutputStream;
-import java.io.PrintWriter;
-import java.util.Locale;
-
-/**
- * WebdavResponseImpl implements the WebdavResponse interface.
- */
-public class WebdavResponseImpl implements WebdavResponse {
-
- private static Logger log = Logger.getLogger(WebdavResponseImpl.class);
-
- private HttpServletResponse httpResponse;
-
- /**
- * Create a new WebdavResponse
- *
- * @param httpResponse
- */
- public WebdavResponseImpl(HttpServletResponse httpResponse) {
- this.httpResponse = httpResponse;
-
- /* set cache control headers in order to deal with non-webdav complient
- * http1.1 or http1.0 proxies. >> see RFC2518 9.4.5 */
- addHeader("Pragma", "No-cache"); // http1.0
- addHeader("Cache-Control", "no-cache"); // http1.1
- }
-
- /**
- *
- * @param exception
- * @throws IOException
- * @see DavServletResponse#sendErrorResponse(org.apache.jackrabbit.webdav.DavException)
- */
- public void sendErrorResponse(DavException exception) throws IOException {
- Element errorElem = exception.getError();
- if (errorElem == null || errorElem.getChildren().size() == 0) {
- httpResponse.sendError(exception.getErrorCode(), exception.getStatusPhrase());
- } else {
- sendXmlResponse(new Document(exception.getError()), exception.getErrorCode());
- }
- }
-
- /**
- * Send a multistatus response.
- *
- * @param multistatus
- * @throws IOException
- * @see DavServletResponse#sendMultiStatusResponse(org.apache.jackrabbit.webdav.MultiStatus)
- */
- public void sendMultiStatusResponse(MultiStatus multistatus) throws IOException {
- sendXmlResponse(multistatus.toXml(), SC_MULTI_STATUS);
- }
-
- /**
- * Send response body for a lock request intended to create a new lock.
- *
- * @param lock
- * @throws java.io.IOException
- * @see DavServletResponse#sendLockResponse(org.apache.jackrabbit.webdav.lock.ActiveLock)
- */
- public void sendLockResponse(ActiveLock lock) throws IOException {
- httpResponse.setHeader(DavConstants.HEADER_LOCK_TOKEN, "<" + lock.getToken() + ">");
-
- Element propElem = new Element(DavConstants.XML_PROP, DavConstants.NAMESPACE);
- propElem.addContent(new LockDiscovery(lock).toXml());
- sendXmlResponse(new Document(propElem), SC_OK);
- }
-
- /**
- * Send response body for a lock request that was intended to refresh one
- * or several locks.
- *
- * @param locks
- * @throws java.io.IOException
- * @see DavServletResponse#sendRefreshLockResponse(org.apache.jackrabbit.webdav.lock.ActiveLock[])
- */
- public void sendRefreshLockResponse(ActiveLock[] locks) throws IOException {
- Element propElem = new Element(DavConstants.XML_PROP, DavConstants.NAMESPACE);
- propElem.addContent(new LockDiscovery(locks).toXml());
- sendXmlResponse(new Document(propElem), SC_OK);
- }
-
- /**
- * Send Xml response body.
- *
- * @param xmlDoc
- * @param status
- * @throws IOException
- * @see DavServletResponse#sendXmlResponse(Document, int);
- */
- public void sendXmlResponse(Document xmlDoc, int status) throws IOException {
- httpResponse.setStatus(status);
- if (xmlDoc != null) {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- // Write dom tree into byte array output stream
- XMLOutputter xmli = new XMLOutputter(Format.getRawFormat());
- xmli.output(xmlDoc, out);
- byte[] bytes = out.toByteArray();
- httpResponse.setContentType("text/xml; charset=UTF-8");
- httpResponse.setContentLength(bytes.length);
- httpResponse.getOutputStream().write(bytes);
- out.close();
- out.flush();
- }
- }
-
- //----------------------------< ObservationDavServletResponse Interface >---
- /**
- *
- * @param subscription
- * @throws IOException
- * @see org.apache.jackrabbit.webdav.observation.ObservationDavServletResponse#sendSubscriptionResponse(org.apache.jackrabbit.webdav.observation.Subscription)
- */
- public void sendSubscriptionResponse(Subscription subscription) throws IOException {
- Element propElem = new Element(DavConstants.XML_PROP, DavConstants.NAMESPACE);
- propElem.addContent(new SubscriptionDiscovery(subscription).toXml());
- Document doc = new Document(propElem);
- sendXmlResponse(doc, SC_OK);
- }
-
- /**
- *
- * @param eventDiscovery
- * @throws IOException
- * @see org.apache.jackrabbit.webdav.observation.ObservationDavServletResponse#sendPollResponse(org.apache.jackrabbit.webdav.observation.EventDiscovery)
- */
- public void sendPollResponse(EventDiscovery eventDiscovery) throws IOException {
- Document pollDoc = new Document(eventDiscovery.toXml());
- sendXmlResponse(pollDoc, SC_OK);
- }
-
- //--------------------------------------< HttpServletResponse interface >---
- public void addCookie(Cookie cookie) {
- httpResponse.addCookie(cookie);
- }
-
- public boolean containsHeader(String s) {
- return httpResponse.containsHeader(s);
- }
-
- public String encodeURL(String s) {
- return httpResponse.encodeRedirectURL(s);
- }
-
- public String encodeRedirectURL(String s) {
- return httpResponse.encodeRedirectURL(s);
- }
-
- public String encodeUrl(String s) {
- return httpResponse.encodeUrl(s);
- }
-
- public String encodeRedirectUrl(String s) {
- return httpResponse.encodeRedirectURL(s);
- }
-
- public void sendError(int i, String s) throws IOException {
- httpResponse.sendError(i, s);
- }
-
- public void sendError(int i) throws IOException {
- httpResponse.sendError(i);
- }
-
- public void sendRedirect(String s) throws IOException {
- httpResponse.sendRedirect(s);
- }
-
- public void setDateHeader(String s, long l) {
- httpResponse.setDateHeader(s, l);
- }
-
- public void addDateHeader(String s, long l) {
- httpResponse.addDateHeader(s, l);
- }
-
- public void setHeader(String s, String s1) {
- httpResponse.setHeader(s, s1);
- }
-
- public void addHeader(String s, String s1) {
- httpResponse.addHeader(s, s1);
- }
-
- public void setIntHeader(String s, int i) {
- httpResponse.setIntHeader(s, i);
- }
-
- public void addIntHeader(String s, int i) {
- httpResponse.addIntHeader(s, i);
- }
-
- public void setStatus(int i) {
- httpResponse.setStatus(i);
- }
-
- public void setStatus(int i, String s) {
- httpResponse.setStatus(i, s);
- }
-
- public String getCharacterEncoding() {
- return httpResponse.getCharacterEncoding();
- }
-
- public ServletOutputStream getOutputStream() throws IOException {
- return httpResponse.getOutputStream();
- }
-
- public PrintWriter getWriter() throws IOException {
- return httpResponse.getWriter();
- }
-
- public void setContentLength(int i) {
-
- }
-
- public void setContentType(String s) {
- httpResponse.setContentType(s);
- }
-
- public void setBufferSize(int i) {
- httpResponse.setBufferSize(i);
- }
-
- public int getBufferSize() {
- return httpResponse.getBufferSize();
- }
-
- public void flushBuffer() throws IOException {
- httpResponse.flushBuffer();
- }
-
- public void resetBuffer() {
- httpResponse.resetBuffer();
- }
-
- public boolean isCommitted() {
- return httpResponse.isCommitted();
- }
-
- public void reset() {
- httpResponse.reset();
- }
-
- public void setLocale(Locale locale) {
- httpResponse.setLocale(locale);
- }
-
- public Locale getLocale() {
- return httpResponse.getLocale();
- }
-}
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/header/DepthHeader.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/header/DepthHeader.java
deleted file mode 100644
index ad26d892c8a..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/header/DepthHeader.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 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.jackrabbit.webdav.header;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.DavConstants;
-
-/**
- * DepthHeader...
- */
-public class DepthHeader implements DavConstants {
-
- private static Logger log = Logger.getLogger(DepthHeader.class);
-
- private final int depth;
-
- /**
- * Create a new DepthHeader from the given integer.
- *
- * @param depth
- */
- public DepthHeader(int depth) {
- if (depth == DavConstants.DEPTH_0 || depth == DavConstants.DEPTH_1 || depth == DavConstants.DEPTH_INFINITY) {
- this.depth = depth;
- } else {
- throw new IllegalArgumentException("Invalid depth: " + depth);
- }
- }
-
- /**
- * @return integer representation of the depth indicated by the given header.
- */
- public int getDepth() {
- return depth;
- }
-
- /**
- * Return {@link DavConstants#HEADER_DEPTH Depth}
- *
- * @return {@link DavConstants#HEADER_DEPTH Depth}
- * @see DavConstants#HEADER_DEPTH
- */
- public String getHeaderName() {
- return DavConstants.HEADER_DEPTH;
- }
-
- /**
- * Returns the header value.
- *
- * @return header value
- */
- public String getHeaderValue() {
- if (depth == DavConstants.DEPTH_0 || depth == DavConstants.DEPTH_1) {
- return depth + "";
- } else {
- return DavConstants.DEPTH_INFINITY_S;
- }
- }
-
- /**
- * Parse the given header value or use the defaultValue if the header
- * string is empty or null.
- *
- * @param headerValue
- * @param defaultValue
- * @return a new DepthHeader
- */
- public static DepthHeader parse(String headerValue, int defaultValue) {
- if (headerValue == null || "".equals(headerValue)) {
- return new DepthHeader(defaultValue);
- } else {
- return new DepthHeader(depthToInt(headerValue));
- }
- }
-
- /**
- * Convert the String depth value to an integer.
- *
- * @param depth
- * @return integer representation of the given depth String
- * @throws IllegalArgumentException if the String does not represent a valid
- * depth.
- */
- private static int depthToInt(String depth) {
- int d;
- if (depth.equalsIgnoreCase(DavConstants.DEPTH_INFINITY_S)) {
- d = DavConstants.DEPTH_INFINITY;
- } else if (depth.equals(DavConstants.DEPTH_0+"")) {
- d = DavConstants.DEPTH_0;
- } else if (depth.equals(DavConstants.DEPTH_1+"")) {
- d = DavConstants.DEPTH_1;
- } else {
- throw new IllegalArgumentException("Invalid depth value: " + depth);
- }
- return d;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/AbstractActiveLock.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/AbstractActiveLock.java
deleted file mode 100644
index 48513015917..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/AbstractActiveLock.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.lock;
-
-import org.apache.jackrabbit.webdav.DavConstants;
-import org.apache.jackrabbit.webdav.util.XmlUtil;
-import org.jdom.Element;
-
-/**
- * AbstractActiveLock...
- */
-public abstract class AbstractActiveLock implements ActiveLock, DavConstants {
-
- /**
- * Returns the default Xml representation of the 'activelock' element
- * as defined by RFC 2518.
- *
- * @return Xml representation
- */
- public Element toXml() {
- Element activeLock = new Element(XML_ACTIVELOCK, NAMESPACE);
-
- // locktype property
- Element property = new Element(XML_LOCKTYPE, NAMESPACE);
- property.addContent(getType().toXml());
- activeLock.addContent(property);
-
- // lockscope property
- property = new Element(XML_LOCKSCOPE, NAMESPACE);
- property.addContent(getScope().toXml());
- activeLock.addContent(property);
-
- // depth
- activeLock.addContent(XmlUtil.depthToXml(isDeep()));
- // timeout
- long timeout = getTimeout();
- if (!isExpired() && timeout != UNDEFINED_TIMEOUT) {
- activeLock.addContent(XmlUtil.timeoutToXml(getTimeout()));
- }
-
- // owner
- if (getOwner() != null) {
- property = new Element(XML_OWNER, NAMESPACE);
- property.setText(getOwner());
- activeLock.addContent(property);
- }
-
- // locktoken
- if (getToken() != null) {
- property = new Element(XML_LOCKTOKEN, NAMESPACE);
- Element href = new Element(XML_HREF, NAMESPACE);
- href.setText(getToken());
- property.addContent(href);
- activeLock.addContent(property);
- }
- return activeLock;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/AbstractLockEntry.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/AbstractLockEntry.java
deleted file mode 100644
index 20693cad536..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/AbstractLockEntry.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.lock;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.DavConstants;
-import org.jdom.Element;
-
-/**
- * AbstractLockEntry provides the generic {@link #toXml} method.
- */
-public abstract class AbstractLockEntry implements LockEntry, DavConstants {
-
- private static Logger log = Logger.getLogger(AbstractLockEntry.class);
-
- /**
- * Returns the Xml representation of this LockEntry.
- *
- * @return Xml representation
- */
- public Element toXml() {
- Element entry = new Element(XML_LOCKENTRY, NAMESPACE);
- Element prop = new Element(XML_LOCKSCOPE, NAMESPACE);
- prop.addContent(getScope().toXml());
- entry.addContent(prop);
- prop = new Element(XML_LOCKTYPE, NAMESPACE);
- prop.addContent(getType().toXml());
- entry.addContent(prop);
- return entry;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/ActiveLock.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/ActiveLock.java
deleted file mode 100644
index 08e1cd2ef4a..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/ActiveLock.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.lock;
-
-import org.jdom.Element;
-
-/**
- * ActiveLock encapsulates the lock information for a
- * {@link org.apache.jackrabbit.webdav.DavResource}.
- */
-public interface ActiveLock {
-
- /**
- * Return true, if the given token matches the lock token present in this
- * lock thus indicating that any lock relevant operation should not fail
- * due to a lock.
- *
- * @param lockToken to be checked
- * @return true if the given lock token matches.
- */
- public boolean isLockedByToken(String lockToken);
-
- /**
- * Returns true, if this lock is already expired.
- *
- * @return true if the lock is expired
- */
- public boolean isExpired();
-
- /**
- * Return the lock token.
- *
- * @return token string representing the lock token.
- */
- public String getToken();
-
- /**
- * Return the name (or id) of the lock owner.
- *
- * @return name (or id) of the lock owner.
- */
- public String getOwner();
-
- /**
- * Set the name (or id) of the lock owner
- *
- * @param owner
- */
- public void setOwner(String owner);
-
- /**
- * Return the number of milliseconds the lock will live until it is expired
- * or -1 if the timeout is not available (or the client is not allowed
- * to retrieve it).
- *
- * @return
- */
- public long getTimeout();
-
- /**
- * Defines the number of milliseconds until the timeout is reached.
- *
- * @param timeout
- */
- public void setTimeout(long timeout);
-
- /**
- * Return true if the lock is deep.
- *
- * @return true if the lock is deep.
- */
- public boolean isDeep();
-
- /**
- * Set the lock deepness.
- *
- * @param isDeep
- */
- public void setIsDeep(boolean isDeep);
-
- /**
- * Return the type of this lock.
- *
- * @return type
- */
- public Type getType();
-
- /**
- * Return the scope of this lock.
- *
- * @return scope
- */
- public Scope getScope();
-
- /**
- * Return the Xml representation of this lock.
- *
- * @return Xml representation of this lock
- */
- public Element toXml();
-}
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/LockDiscovery.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/LockDiscovery.java
deleted file mode 100644
index a9e2f57da67..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/LockDiscovery.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.lock;
-
-import org.jdom.Element;
-import org.apache.jackrabbit.webdav.property.DavPropertyName;
-import org.apache.jackrabbit.webdav.property.AbstractDavProperty;
-
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Iterator;
-
-/**
- * The LockDiscovery class encapsulates the webdav lock discovery
- * property that is sent in the request body (PROPFIND and LOCK) and received
- * in a LOCK response body.
- */
-public class LockDiscovery extends AbstractDavProperty {
-
- /**
- * Listing of existing locks applied to the resource this discovery was
- * requested for. Each entry reveals, who has a lock, what type of lock he has,
- * the timeout type and the time remaining on the timeout, and the lock-type.
- * NOTE, that any of the information listed may be not availble for the
- * server is free to withhold any or all of this information.
- */
- private List activeLocks = new ArrayList();
-
- /**
- * Creates a new empty LockDiscovery property
- */
- public LockDiscovery() {
- super(DavPropertyName.LOCKDISCOVERY, false);
- }
-
- /**
- * Create a new LockDiscovery property
- *
- * @param lock
- */
- public LockDiscovery(ActiveLock lock) {
- super(DavPropertyName.LOCKDISCOVERY, false);
- addActiveLock(lock);
- }
-
- /**
- * Create a new LockDiscovery property
- *
- * @param locks
- */
- public LockDiscovery(ActiveLock[] locks) {
- super(DavPropertyName.LOCKDISCOVERY, false);
- for (int i = 0; i < locks.length; i++) {
- addActiveLock(locks[i]);
- }
- }
-
- private void addActiveLock(ActiveLock lock) {
- if (lock != null) {
- activeLocks.add(lock);
- }
- }
-
- /**
- * Creates a JDOM <lockdiscovery> element in order to respond to a LOCK
- * request or to the lockdiscovery property of a PROPFIND request.
- * NOTE: if the {@link #activeLocks} list is empty an empty lockdiscovery
- * property is created ( <lockdiscovery/>)
- * @return A JDOM element of the <active> lock tag.
- */
- public Element toXml() {
- Element lockdiscovery = getName().toXml();
- Iterator it = activeLocks.iterator();
- while (it.hasNext()) {
- ActiveLock lock = (ActiveLock) it.next();
- lockdiscovery.addContent(lock.toXml());
- }
- return lockdiscovery;
- }
-
- /**
- * Returns the list of active locks.
- *
- * @return list of active locks
- * @see org.apache.jackrabbit.webdav.property.DavProperty#getValue()
- */
- public Object getValue() {
- return activeLocks;
- }
-}
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/LockEntry.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/LockEntry.java
deleted file mode 100644
index 49b90d6fb12..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/LockEntry.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.lock;
-
-import org.jdom.Element;
-
-/**
- * LockEntry...
- */
-public interface LockEntry {
-
- /**
- * Returns the type of this lock entry
- *
- * @return type of this lock entry.
- */
- public Type getType();
-
- /**
- * Returns the scope of this lock entry.
- *
- * @return scope of this lock entry.
- */
- public Scope getScope();
-
- /**
- * Returns the Xml representation of this entry.
- *
- * @return Xml representation
- */
- public Element toXml();
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/LockInfo.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/LockInfo.java
deleted file mode 100644
index 6847d413c15..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/LockInfo.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.lock;
-
-import org.apache.jackrabbit.webdav.DavConstants;
-import org.jdom.Element;
-
-import java.util.List;
-import java.util.Iterator;
-
-/**
- * LockInfo is a simple utility class encapsulating the information
- * passed with a LOCK request. It combines both the request body (which if present
- * is required to by a 'lockinfo' Xml element) and the lock relevant request
- * headers '{@link DavConstants#HEADER_TIMEOUT Timeout}' and
- * '{@link DavConstants#HEADER_DEPTH Depth}'.
- * Note that is class is not intended to perform any validation of the information
- * given, since this left to those objects responsible for the lock creation
- * on the requested resource.
- */
-public class LockInfo {
-
- private Type type;
- private Scope scope;
- private String owner;
- private boolean isDeep;
- private long timeout;
-
- private boolean isRefreshLock;
-
- /**
- * Create a new LockInfo object from the given information. If
- * liElement is null this lockinfo is assumed to
- * be issued from a 'Refresh Lock' request.
- *
- * @param liElement 'lockinfo' element present in the request body of a LOCK request
- * or null if the request was intended to refresh an existing lock.
- * @param timeout Requested timespan until the lock should expire. A LOCK
- * request MUST contain a '{@link DavConstants#HEADER_TIMEOUT Timeout}'
- * according to RFC 2518.
- * @param isDeep boolean value indicating whether the lock should be applied
- * with depth infinity or only to the requested resource.
- * @throws IllegalArgumentException if the liElement is not
- * null but does not start with an 'lockinfo' element.
- */
- public LockInfo(Element liElement, long timeout, boolean isDeep) {
- this.timeout = timeout;
- this.isDeep = isDeep;
-
- if (liElement != null) {
- if (!DavConstants.XML_LOCKINFO.equals(liElement.getName())) {
- throw new IllegalArgumentException("Element must have name 'lockinfo'.");
- }
-
- List childList = liElement.getChildren();
- for (int i = 0; i < childList.size(); i++) {
- Element child = (Element) childList.get(i);
- String nodeName = child.getName();
- if (DavConstants.XML_LOCKTYPE.equals(nodeName)) {
- Element typeElement = getFirstChildElement(child);
- type = Type.create(typeElement);
- } else if (DavConstants.XML_LOCKSCOPE.equals(nodeName)) {
- Element scopeElement = getFirstChildElement(child);
- scope = Scope.create(scopeElement);
- } else if (DavConstants.XML_OWNER.equals(nodeName)) {
- owner = child.getChildTextTrim(DavConstants.XML_HREF);
- if (owner==null) {
- // check if child is a text element
- owner = child.getTextTrim();
- }
- }
- }
- isRefreshLock = false;
- } else {
- isRefreshLock = true;
- }
- }
-
- /**
- * Retrieve the first element from the content list of the specified Xml element.
- *
- * @param elem
- * @return
- */
- private static Element getFirstChildElement(Element elem) {
- if (elem.getContentSize() > 0) {
- Iterator it = elem.getContent().iterator();
- while (it.hasNext()) {
- Object content = it.next();
- if (content instanceof Element) {
- return (Element) content;
- }
- }
- }
- return null;
- }
-
- /**
- * Returns the lock type or null if no 'lockinfo' element was
- * passed to the constructor or did not contain an 'type' element.
- *
- * @return type or null
- */
- public Type getType() {
- return type;
- }
-
- /**
- * Return the lock scope or null if no 'lockinfo' element was
- * passed to the constructor or did not contain an 'scope' element.
- *
- * @return scope or null
- */
- public Scope getScope() {
- return scope;
- }
-
- /**
- * Return the owner indicated by the corresponding child element from the
- * 'lockinfo' element or null if no 'lockinfo' element was
- * passed to the constructor or did not contain an 'owner' element.
- *
- * @return owner or null
- */
- public String getOwner() {
- return owner;
- }
-
- /**
- * Returns true if the lock must be applied with depth infinity.
- *
- * @return true if a deep lock must be created.
- */
- public boolean isDeep() {
- return isDeep;
- }
-
- /**
- * Returns the time until the lock is requested to expire.
- *
- * @return time until the lock should expire.
- */
- public long getTimeout() {
- return timeout;
- }
-
- /**
- * Returns true if this LockInfo was created for a LOCK
- * request intended to refresh an existing lock rather than creating a
- * new one.
- *
- * @return true if the corresponding LOCK request was intended to refresh
- * an existing lock.
- */
- public boolean isRefreshLock() {
- return isRefreshLock;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/LockManager.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/LockManager.java
deleted file mode 100644
index 3f415af8784..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/LockManager.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.lock;
-
-import org.apache.jackrabbit.webdav.DavException;
-import org.apache.jackrabbit.webdav.DavResource;
-
-/**
- * The LockManager interface.
- */
-public interface LockManager {
-
- /**
- * Create a new lock for the given {@link org.apache.jackrabbit.webdav.DavResource resource}.
- *
- * @param lockInfo
- * @param resource
- * @return
- * @throws DavException
- */
- public ActiveLock createLock(LockInfo lockInfo, DavResource resource)
- throws DavException;
-
- /**
- * Refresh the lock identified by the given lockToken and initially created
- * on the specified resouce. The update information can be retrieved from
- * the lockInfo object passes.
- *
- * @param lockInfo
- * @param lockToken
- * @param resource
- * @return
- * @throws DavException
- */
- public ActiveLock refreshLock(LockInfo lockInfo, String lockToken, DavResource resource)
- throws DavException;
-
- /**
- * Release the lock identified by the given lockToken and initially created
- * on the specified resouce.
- *
- * @param lockToken
- * @param resource
- * @throws DavException
- */
- public void releaseLock(String lockToken, DavResource resource)
- throws DavException;
-
- /**
- * Retrieve the lock with the given type and scope that is applied to the
- * given resource. The lock may be either initially created on this resource
- * or might be inherited from an ancestor resource that hold a deep lock.
- * If no such lock applies to the given resource null must be
- * returned.
- *
- * @param type
- * @param scope
- * @param resource
- * @return lock with the given type and scope applied to the resource or
- * null if no lock applies.
- */
- public ActiveLock getLock(Type type, Scope scope, DavResource resource);
-
- /**
- * Returns true, if the the manager contains a lock for the given
- * resource, that is hold by the specified token.
- *
- * @param lockToken
- * @param resource
- * @return true if the resource is locked by the specified token.
- */
- public boolean hasLock(String lockToken, DavResource resource);
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/Scope.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/Scope.java
deleted file mode 100644
index 0bd516ef624..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/Scope.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.lock;
-
-import org.jdom.Element;
-import org.jdom.Namespace;
-import org.apache.jackrabbit.webdav.DavConstants;
-
-import java.util.*;
-
-/**
- * The Scope class abstracts the lock scope as defined by RFC 2518.
- */
-public class Scope {
-
- private static final Map scopes = new HashMap();
-
- public static final Scope EXCLUSIVE = Scope.create(DavConstants.XML_EXCLUSIVE, DavConstants.NAMESPACE);
- public static final Scope SHARED = Scope.create(DavConstants.XML_SHARED, DavConstants.NAMESPACE);
-
- private final String name;
- private final Namespace namespace;
-
- /**
- * Private constructor
- *
- * @param name
- * @param namespace
- */
- private Scope(String name, Namespace namespace) {
- this.name = name;
- this.namespace = namespace;
- }
-
- /**
- * Return the Xml representation of the lock scope object as present in
- * the LOCK request and response body and in the {@link LockDiscovery}.
- *
- * @return Xml representation
- */
- public Element toXml() {
- return new Element(name, namespace);
- }
-
- /**
- * Create a Scope object from the given Xml element.
- *
- * @param lockScope
- * @return Scope object.
- */
- public static Scope create(Element lockScope) {
- if (lockScope == null) {
- throw new IllegalArgumentException("'null' is not valid lock scope entry.");
- }
- return create(lockScope.getName(), lockScope.getNamespace());
- }
-
- /**
- * Create a Scope object from the given name and namespace.
- *
- * @param name
- * @param namespace
- * @return Scope object.
- */
- public static Scope create(String name, Namespace namespace) {
- String key = "{" + namespace.getURI() + "}" + name;
- if (scopes.containsKey(key)) {
- return (Scope) scopes.get(key);
- } else {
- Scope scope = new Scope(name, namespace);
- scopes.put(key, scope);
- return scope;
- }
- }
-
- /**
- * Returns true if this Scope is equal to the given one.
- *
- * @param obj
- * @return
- */
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj instanceof Scope) {
- Scope other = (Scope) obj;
- return name.equals(other.name) && namespace.equals(other.namespace);
- }
- return false;
- }
-
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/Type.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/Type.java
deleted file mode 100644
index 24d0d8892f4..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/Type.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.lock;
-
-import org.jdom.Element;
-import org.jdom.Namespace;
-import org.apache.jackrabbit.webdav.DavConstants;
-
-import java.util.*;
-
-/**
- * The Type class encapsulates the lock type as defined by RFC 2518.
- */
-public class Type {
-
- private static Map types = new HashMap();
-
- public static final Type WRITE = Type.create(DavConstants.XML_WRITE, DavConstants.NAMESPACE);
-
- private final String name;
- private final Namespace namespace;
-
- /**
- * Private constructor.
- *
- * @param name
- * @param namespace
- */
- private Type(String name, Namespace namespace) {
- this.name = name;
- this.namespace = namespace;
- }
-
- /**
- * Returns the Xml representation of this lock Type.
- *
- * @return Xml representation
- */
- public Element toXml() {
- return new Element(name, namespace);
- }
-
- /**
- * Create a Type object from the given Xml element.
- *
- * @param lockType
- * @return Type object.
- */
- public static Type create(Element lockType) {
- if (lockType == null) {
- throw new IllegalArgumentException("'null' is not valid lock type entry.");
- }
- return create(lockType.getName(), lockType.getNamespace());
- }
-
- /**
- * Create a Type object from the given name and namespace.
- *
- * @param name
- * @param namespace
- * @return Type object.
- */
- public static Type create(String name, Namespace namespace) {
- String key = "{" + namespace.getURI() + "}" + name;
- if (types.containsKey(key)) {
- return (Type) types.get(key);
- } else {
- Type type = new Type(name, namespace);
- types.put(key, type);
- return type;
- }
- }
-
- /**
- * Returns true if this Type is equal to the given one.
- *
- * @param obj
- * @return
- */
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj instanceof Type) {
- Type other = (Type) obj;
- return name.equals(other.name) && namespace.equals(other.namespace);
- }
- return false;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/package.html b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/package.html
deleted file mode 100644
index b189cbfafd4..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/lock/package.html
+++ /dev/null
@@ -1,3 +0,0 @@
-
-Provides interfaces and classes for locking related issues.
-
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/EventDiscovery.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/EventDiscovery.java
deleted file mode 100644
index cc08afaf24e..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/EventDiscovery.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.observation;
-
-import org.apache.log4j.Logger;
-import org.jdom.Element;
-
-import java.util.List;
-import java.util.ArrayList;
-
-/**
- * EventDiscovery represents the request body of a successfull
- * POLL request. It reveals all events that occured since the last POLL. The
- * definition what events that particular subscription is interested in was
- * specified with the initial SUBSCRIPTION that started the event listening.
- */
-public class EventDiscovery implements ObservationConstants {
-
- private static Logger log = Logger.getLogger(EventDiscovery.class);
-
- private List bundles = new ArrayList();
-
- /**
- * Add the Xml representation of an single 'eventBundle' listing the
- * events that resulted from a change in the server, filtered by the
- * restrictions present in the corresponding subscription.
- *
- * @param eventBundle
- * @see Subscription
- */
- public void addEventBundle(Element eventBundle) {
- if (eventBundle != null) {
- bundles.add(eventBundle);
- }
- }
-
- /**
- * Returns the Xml representation of this EventDiscovery as
- * being present in the POLL response body.
- *
- * @return Xml representation
- */
- public Element toXml() {
- Element ed = new Element(XML_EVENTDISCOVERY, NAMESPACE);
- ed.addContent(bundles);
- return ed;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/ObservationConstants.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/ObservationConstants.java
deleted file mode 100644
index b7db08f79b1..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/ObservationConstants.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.observation;
-
-import org.jdom.Namespace;
-import org.apache.jackrabbit.webdav.property.DavPropertyName;
-
-/**
- * ObservationConstants interface provide constants for request
- * and response headers, Xml elements and property names used for handling
- * observation over WebDAV. There exists no public standard for this
- * functionality.
- */
-public interface ObservationConstants {
-
- /**
- * The namespace
- */
- public static final Namespace NAMESPACE = Namespace.getNamespace("jcr", "http://www.day.com/jcr/webdav/1.0");
-
- /**
- * The SubscriptionId request header
- */
- public static final String HEADER_SUBSCRIPTIONID = "SubscriptionId";
-
- /**
- * subscription Xml element
- * Mandatory element inside the {@link #SUBSCRIPTIONDISCOVERY subscriptiondiscovery}
- * property indicating the event listeners present for this session.
- * NOTE, that this will not reveal any subscription made by another session.
- */
- public static final String XML_SUBSCRIPTION = "subscription";
-
- /**
- * Xml elements
- */
- public static final String XML_SUBSCRIPTIONINFO = "subscriptioninfo";
-
- public static final String XML_EVENTTYPE = "eventtype";
- public static final String XML_NOLOCAL = "nolocal";
- public static final String XML_FILTER = "filter";
- public static final String XML_SUBSCRIPTIONID = "subscriptionid";
- public static final String XML_UUID = "uuid";
- public static final String XML_NODETYPE_NAME = "nodetype-name";
-
- public static final String XML_EVENTDISCOVERY = "eventdiscovery";
- public static final String XML_EVENTBUNDLE = "eventbundle";
- public static final String XML_EVENT = "event";
- public static final String XML_EVENTUSERID = "eventuserid";
-
- /**
- * Element representing the 'nodeadded' event type.
- * @see javax.jcr.observation.Event#NODE_ADDED
- */
- public static final String EVENT_NODEADDED = "nodeadded";
-
- /**
- * Element representing the 'noderemoved' event type.
- * @see javax.jcr.observation.Event#NODE_REMOVED
- */
- public static final String EVENT_NODEREMOVED = "noderemoved";
-
- /**
- * Element representing the 'propertyadded' event type.
- * @see javax.jcr.observation.Event#PROPERTY_ADDED
- */
- public static final String EVENT_PROPERTYADDED = "propertyadded";
-
- /**
- * Element representing the 'propertyremoved' event type.
- * @see javax.jcr.observation.Event#PROPERTY_REMOVED
- */
- public static final String EVENT_PROPERTYREMOVED = "propertyremoved";
-
- /**
- * Element representing the 'propertychanged' event type.
- * @see javax.jcr.observation.Event#PROPERTY_CHANGED
- */
- public static final String EVENT_PROPERTYCHANGED = "propertychanged";
-
- /**
- * The protected subscription discovery property is used to find out about
- * existing subscriptions present on the specified resource.
- */
- public static final DavPropertyName SUBSCRIPTIONDISCOVERY = DavPropertyName.create("subscriptiondiscovery", NAMESPACE);
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/ObservationDavServletRequest.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/ObservationDavServletRequest.java
deleted file mode 100644
index f6c5377623e..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/ObservationDavServletRequest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.observation;
-
-import org.apache.jackrabbit.webdav.DavServletRequest;
-
-/**
- * ObservationDavServletRequest provides extensions to the
- * {@link DavServletRequest} interface used for dealing with observation.
- */
-public interface ObservationDavServletRequest extends DavServletRequest {
-
- /**
- * Return the {@link ObservationConstants#HEADER_SUBSCRIPTIONID SubscriptionId header}
- * or null if no such header is present.
- *
- * @return the {@link ObservationConstants#HEADER_SUBSCRIPTIONID SubscriptionId header}
- */
- public String getSubscriptionId();
-
- /**
- * Return a {@link SubscriptionInfo} object representing the subscription
- * info present in the SUBSCRIBE request body or null if
- * retrieving the subscription info fails.
- *
- * @return subscription info object encapsulating the SUBSCRIBE request body
- * or null if the subscription info cannot be built.
- */
- public SubscriptionInfo getSubscriptionInfo();
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/ObservationDavServletResponse.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/ObservationDavServletResponse.java
deleted file mode 100644
index 8a68b97a509..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/ObservationDavServletResponse.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.observation;
-
-import org.apache.jackrabbit.webdav.DavServletResponse;
-
-import java.io.IOException;
-
-/**
- * ObservationDavServletResponse provides extensions to the
- * {@link DavServletResponse} interface used for dealing with observation.
- */
-public interface ObservationDavServletResponse extends DavServletResponse {
-
- /**
- * Send the response to a successful SUBSCRIBE request.
- *
- * @param subsription that needs to be represented in the response body.
- * @throws IOException
- */
- public void sendSubscriptionResponse(Subscription subsription) throws IOException;
-
- /**
- * Send the response to a sucessful POLL request.
- *
- * @param eventdiscovery {@link EventDiscovery} object to be returned in
- * the response body.
- * @throws IOException
- */
- public void sendPollResponse(EventDiscovery eventdiscovery) throws IOException;
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/Subscription.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/Subscription.java
deleted file mode 100644
index 0b7debd7640..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/Subscription.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.observation;
-
-import org.jdom.Element;
-
-/**
- * Subscription represents public representation of the event
- * listener created (or modified) by a successful SUBSCRIBE request.
- */
-public interface Subscription {
-
- /**
- * Returns the id of this subscription, that must be used for unsubscribing
- * as well as for event discovery later on.
- *
- * @return subscriptionId
- */
- public String getSubscriptionId();
-
- /**
- * Return the Xml representation of this Subscription that is
- * returned in the response to a successful SUBSCRIBE request as well
- * as in a PROPFIND request. In both cases the subscription is packed into
- * a {@link SubscriptionDiscovery} property object.
- *
- * @return Xml representation
- */
- public Element toXml();
-
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/SubscriptionDiscovery.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/SubscriptionDiscovery.java
deleted file mode 100644
index 58c9a51bc2b..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/SubscriptionDiscovery.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.observation;
-
-import org.apache.jackrabbit.webdav.property.AbstractDavProperty;
-import org.jdom.Element;
-
-/**
- * SubscriptionDiscovery encapsulates the 'subscriptiondiscovery'
- * property of a webdav resource.
- */
-public class SubscriptionDiscovery extends AbstractDavProperty {
-
- Subscription[] subscriptions = new Subscription[0];
-
- /**
- * Create a new SubscriptionDiscovery that lists the given
- * subscriptions.
- *
- * @param subscriptions
- */
- public SubscriptionDiscovery(Subscription[] subscriptions) {
- super(ObservationConstants.SUBSCRIPTIONDISCOVERY, true);
- if (subscriptions != null) {
- this.subscriptions = subscriptions;
- }
- }
-
- /**
- * Create a new SubscriptionDiscovery that contains a single
- * subscription entry.
- *
- * @param subscription
- */
- public SubscriptionDiscovery(Subscription subscription) {
- super(ObservationConstants.SUBSCRIPTIONDISCOVERY, true);
- if (subscription != null) {
- this.subscriptions = new Subscription[]{subscription};
- }
- }
-
- /**
- * Returns the Xml representation of the subscription discovery.
- *
- * @return Xml representation
- * @see org.apache.jackrabbit.webdav.property.DavProperty#toXml()
- */
- public Element toXml() {
- Element elem = getName().toXml();
- for (int i = 0; i < subscriptions.length; i++) {
- elem.addContent(subscriptions[i].toXml());
- }
- return elem;
- }
-
- /**
- * Returns an array of {@link Subscription}s.
- *
- * @return an array of {@link Subscription}s
- * @see org.apache.jackrabbit.webdav.property.DavProperty#getValue()
- */
- public Object getValue() {
- return subscriptions;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/SubscriptionInfo.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/SubscriptionInfo.java
deleted file mode 100644
index d9f1719c8b3..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/SubscriptionInfo.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.observation;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.util.XmlUtil;
-import org.jdom.Element;
-
-import java.util.List;
-
-/**
- * SubscriptionInfo class encapsulates the subscription info
- * that forms the request body of a SUBSCRIBE request.
- * @see ObservationConstants#XML_SUBSCRIPTIONINFO
- */
-public class SubscriptionInfo implements ObservationConstants {
-
- private static Logger log = Logger.getLogger(SubscriptionInfo.class);
-
- private Element info;
- private List eventTypes;
- private long timeout;
- private boolean isDeep;
-
- /**
- * Create a new SubscriptionInfo
- *
- * @param reqInfo Xml element present in the request body.
- * @param timeout as defined by the {@link org.apache.jackrabbit.webdav.DavConstants#HEADER_TIMEOUT timeout header}.
- * @param isDeep as defined by the {@link org.apache.jackrabbit.webdav.DavConstants#HEADER_DEPTH depth header}.
- * @throws IllegalArgumentException if the reqInfo element does not contain the mandatory elements.
- */
- public SubscriptionInfo(Element reqInfo, long timeout, boolean isDeep) {
- if (!XML_SUBSCRIPTIONINFO.equals(reqInfo.getName())) {
- throw new IllegalArgumentException("Element with name 'subscriptioninfo' expected");
- }
- if (reqInfo.getChild(XML_EVENTTYPE, NAMESPACE) == null ) {
- throw new IllegalArgumentException("'subscriptioninfo' must contain an 'eventtype' child element.");
- }
-
- eventTypes = reqInfo.getChild(XML_EVENTTYPE, NAMESPACE).getChildren();
- if (eventTypes.size() == 0) {
- throw new IllegalArgumentException("'subscriptioninfo' must at least indicate a single event type.");
- }
-
- // detach the request info, in order to remove the reference to the parent
- this.info = (Element)reqInfo.detach();
- this.isDeep = isDeep;
- setTimeOut(timeout);
- }
-
- /**
- * Return list of event types Xml elements present in the subscription info.
- * NOTE: the elements need to be detached in order to be added as content
- * to any other Xml element.
- *
- * @return List of Xml elements defining which events this subscription should
- * listen to.
- *
- */
- public List getEventTypes() {
- return eventTypes;
- }
-
- /**
- * Return array of filters with the specified name.
- *
- * @param name the filter elments must provide.
- * @return array containing the text of the filter elements with the given
- * name.
- */
- public String[] getFilters(String name) {
- String[] filters = null;
- Element filter = info.getChild(XML_FILTER);
- if (filter != null) {
- List li = filter.getChildren(name);
- if (!li.isEmpty()) {
- filters = new String[li.size()];
- for (int i = 0; i < filters.length; i++) {
- filters[i] = ((Element)li.get(i)).getText();
- }
- }
- }
- return filters;
- }
-
- /**
- * Returns true if the {@link #XML_NOLOCAL} element is present in this
- * subscription info.
- *
- * @return if {@link #XML_NOLOCAL} element is present.
- */
- public boolean isNoLocal() {
- return info.getChild(XML_NOLOCAL, NAMESPACE) != null;
- }
-
- /**
- * Returns true if the {@link org.apache.jackrabbit.webdav.DavConstants#HEADER_DEPTH
- * depths header} defined a depth other than '0'.
- *
- * @return true if this subscription info was created with isDeep
- * true.
- */
- public boolean isDeep() {
- return isDeep;
- }
-
- /**
- * Return the timeout as retrieved from the request.
- *
- * @return timeout.
- */
- public long getTimeOut() {
- return timeout;
- }
-
- /**
- * Set the timeout. NOTE: no validation is made.
- *
- * @param timeout as defined by the {@link org.apache.jackrabbit.webdav.DavConstants#HEADER_TIMEOUT}.
- */
- public void setTimeOut(long timeout) {
- this.timeout = timeout;
- }
-
- /**
- * Xml representation of this SubscriptionInfo.
- *
- * @return Xml representation
- */
- public Element[] toXml() {
- Element[] elems = { info, XmlUtil.depthToXml(isDeep), XmlUtil.timeoutToXml(timeout)};
- return elems;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/SubscriptionManager.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/SubscriptionManager.java
deleted file mode 100644
index 71d0a4ea890..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/SubscriptionManager.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.observation;
-
-import org.apache.jackrabbit.webdav.DavException;
-
-/**
- * SubscriptionManager interface.
- */
-public interface SubscriptionManager {
-
- /**
- * Retrieve the {@link org.apache.jackrabbit.webdav.observation.SubscriptionDiscovery} object for the given
- * resource. Note, that the discovery object will be empty if there are
- * no subscriptions present.
- *
- * @param resource
- */
- public SubscriptionDiscovery getSubscriptionDiscovery(ObservationResource resource);
-
- /**
- * Create a new Subscription or update an existing Subscription..
- *
- * @param info
- * @param subscriptionId
- * @param resource
- * @return Subscription that has been created or updated
- * @throws DavException if the subscription fails
- */
- public Subscription subscribe(SubscriptionInfo info, String subscriptionId,
- ObservationResource resource)
- throws DavException;
-
- /**
- * Unsubscribe the Subscription with the given id.
- *
- * @param subscriptionId
- * @param resource
- * @throws DavException
- */
- public void unsubscribe(String subscriptionId, ObservationResource resource)
- throws DavException;
-
- /**
- * Retrieve the list of events that occured since the last poll.
- *
- * @param subscriptionId indentifier for the subscription
- * @param resource
- * @return
- */
- public EventDiscovery poll(String subscriptionId, ObservationResource resource)
- throws DavException;
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/package.html b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/package.html
deleted file mode 100644
index 7ab068095ba..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/observation/package.html
+++ /dev/null
@@ -1,4 +0,0 @@
-
-Contains interfaces and classes related to observation, which is not covered
-by the WebDAV protocol.
-
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/ordering/OrderPatch.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/ordering/OrderPatch.java
deleted file mode 100644
index 7f006697876..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/ordering/OrderPatch.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.ordering;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.DavConstants;
-import org.jdom.Element;
-
-import java.util.List;
-import java.util.Iterator;
-import java.util.ArrayList;
-
-/**
- * OrderPatch represents the mandatory request body of an
- * ORDERPATCH request. RFC 3648 defines the following structure for it:
- *
- * <!ELEMENT orderpatch (ordering-type?, order-member*) >
- * <!ELEMENT order-member (segment, position) >
- * <!ELEMENT position (first | last | before | after) >
- * <!ELEMENT segment (#PCDATA) >
- * <!ELEMENT first EMPTY >
- * <!ELEMENT last EMPTY >
- * <!ELEMENT before segment >
- * <!ELEMENT after segment >
- *
- */
-public class OrderPatch implements OrderingConstants{
-
- private static Logger log = Logger.getLogger(OrderPatch.class);
-
- private Member[] instructions;
- private String orderingType;
-
- /**
- * Create a new OrderPath object.
- *
- * @param orderPatchElement
- * @throws IllegalArgumentException if the specified Xml element was not valid.
- */
- public OrderPatch(Element orderPatchElement) {
- if (!OrderingConstants.XML_ORDERPATCH.equals(orderPatchElement.getName()) ||
- orderPatchElement.getChild(OrderingConstants.XML_ORDERING_TYPE) == null) {
- throw new IllegalArgumentException("ORDERPATH request body must start with an 'orderpatch' element, which must contain an 'ordering-type' child element.");
- }
- // retrieve the orderingtype element
- orderingType = orderPatchElement.getChild(OrderingConstants.XML_ORDERING_TYPE).getChildText(DavConstants.XML_HREF);
-
- // set build the list of ordering instructions
- List oMembers = orderPatchElement.getChildren(OrderingConstants.XML_ORDER_MEMBER, DavConstants.NAMESPACE);
- Iterator it = oMembers.iterator();
- int cnt = 0;
- List tmpInst = new ArrayList();
- while (it.hasNext()) {
- Element member = (Element) it.next();
- try {
- String segment = member.getChildText(OrderingConstants.XML_SEGMENT);
- Position pos = new Position(member.getChild(OrderingConstants.XML_POSITION));
- Member om = new Member(segment, pos);
- tmpInst.add(om);
- cnt++;
- } catch (IllegalArgumentException e) {
- log.error("Invalid element in 'orderpatch' request body: " + e.getMessage());
- }
- }
- instructions = (Member[]) tmpInst.toArray(new Member[cnt]);
- }
-
- /**
- * Create a new OrderPath object.
- *
- * @param orderingType
- * @param instructions
- */
- public OrderPatch(String orderingType, Member[] instructions) {
- this.orderingType = orderingType;
- this.instructions = instructions;
- }
-
- /**
- * Return the ordering type.
- *
- * @return ordering type
- */
- public String getOrderingType() {
- return orderingType;
- }
-
- /**
- * Return an array of {@link Member} objects defining the re-ordering
- * instructions to be applied to the requested resource.
- *
- * @return ordering instructions.
- */
- public Member[] getOrderInstructions() {
- return instructions;
- }
-
- //--------------------------------------------------------------------------
- /**
- * Internal class Member represents the 'Order-Member' children
- * elements of an 'OrderPatch' request body present in the ORDERPATCH request.
- */
- public class Member {
-
- private String memberHandle;
- private Position position;
-
- /**
- * Create a new Member object.
- *
- * @param memberHandle
- * @param position
- */
- public Member(String memberHandle, Position position) {
- this.memberHandle = memberHandle;
- this.position = position;
- }
-
- /**
- * Return the handle of the internal member to be reordered.
- *
- * @return handle of the internal member.
- */
- public String getMemberHandle() {
- return memberHandle;
- }
-
- /**
- * Return the position where the internal member identified by the
- * member handle should be placed.
- *
- * @return position for the member after the request.
- * @see #getMemberHandle()
- */
- public Position getPosition() {
- return position;
- }
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/ordering/OrderingType.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/ordering/OrderingType.java
deleted file mode 100644
index 3f3af1ca1ea..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/ordering/OrderingType.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.ordering;
-
-import org.jdom.Element;
-import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
-import org.apache.jackrabbit.webdav.util.XmlUtil;
-
-/**
- * OrderingType represents the {@link #ORDERING_TYPE
- * DAV:ordering-type} property as defined by
- * RFC 3648. This property is
- * protected cannot be set using PROPPATCH. Its value may only be set by
- * including the Ordering-Type header with a MKCOL request or by submitting an
- * ORDERPATCH request.
- *
- * @see org.apache.jackrabbit.webdav.property.DavProperty#isProtected()
- */
-public class OrderingType extends DefaultDavProperty implements OrderingConstants {
-
- /**
- * Create an OrderingType with the given ordering.
- * NOTE: the ordering-type property is defined to be protected.
- *
- * @param href
- * @see org.apache.jackrabbit.webdav.property.DavProperty#isProtected()
- */
- public OrderingType(String href) {
- super(ORDERING_TYPE, href, true);
- }
-
- /**
- * Returns the Xml representation of this property. If the property has
- * a null value, the default ({@link #ORDERING_TYPE_UNORDERED
- * DAV:unordered}) is assumed.
- *
- * @return Xml representation
- */
- public Element toXml() {
- Element elem = getName().toXml();
- // spec requires that the default is 'DAV:unordered'
- String href = (getValue() != null) ? getValue().toString() : ORDERING_TYPE_UNORDERED;
- XmlUtil.hrefToXml(href);
- return elem;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/ordering/Position.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/ordering/Position.java
deleted file mode 100644
index 46833fcc85b..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/ordering/Position.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.ordering;
-
-import org.apache.log4j.Logger;
-import org.jdom.Element;
-
-import java.util.HashMap;
-
-/**
- * Position encapsulates the position in ordering information
- * contained in a Webdav request. This includes both the
- * {@link OrderingConstants#HEADER_POSITION Position header} and the position
- * Xml element present in the request body of an ORDERPATCH request.
- *
- * @see OrderingConstants#HEADER_POSITION
- * @see OrderingConstants#XML_POSITION
- * @see OrderPatch
- */
-public class Position implements OrderingConstants {
-
- private static Logger log = Logger.getLogger(Position.class);
-
- public static final int TYPE_FIRST = 1;
- public static final int TYPE_LAST = 2;
- public static final int TYPE_BEFORE = 4;
- public static final int TYPE_AFTER = 8;
-
- private static final HashMap xmlTypeMap = new HashMap(4);
- static {
- xmlTypeMap.put(XML_FIRST, new Integer(TYPE_FIRST));
- xmlTypeMap.put(XML_LAST, new Integer(TYPE_LAST));
- xmlTypeMap.put(XML_BEFORE, new Integer(TYPE_BEFORE));
- xmlTypeMap.put(XML_AFTER, new Integer(TYPE_AFTER));
- }
-
- private int type;
- private String segment;
-
- /**
- * Create a new Position object with the specified type.
- * Since any type except for {@link #XML_FIRST first} and {@link #XML_LAST last}
- * must be combined with a segment, only the mentioned types are valid
- * arguments.
- *
- * @param type {@link #XML_FIRST first} or {@link #XML_LAST last}
- * @throws IllegalArgumentException if the given type is other than {@link #XML_FIRST}
- * or {@link #XML_LAST}.
- */
- public Position(String type) {
- if (!(XML_FIRST.equals(type) || XML_LAST.equals(type))) {
- throw new IllegalArgumentException("If type is other than 'first' or 'last' a segment must be specified");
- }
- setType(type);
- }
-
- /**
- * Create a new Position object from the specified position
- * element. The element must fulfill the following structure:
- *
- * <!ELEMENT position (first | last | before | after) >
- * <!ELEMENT segment (#PCDATA) >
- * <!ELEMENT first EMPTY >
- * <!ELEMENT last EMPTY >
- * <!ELEMENT before segment >
- * <!ELEMENT after segment >
- *
- *
- * @param position Xml element defining the position.
- * @throws IllegalArgumentException if the given Xml element is not valid.
- */
- public Position(Element position) {
- if (position.getChildren().size() != 1) {
- throw new IllegalArgumentException("The 'position' element must contain exactly a single child indicating the type.");
- }
- Element typeElem = (Element)position.getChildren().get(0);
- String type = typeElem.getName();
- String segmentText = null;
- if (typeElem.getChildren().size() > 0) {
- segmentText = typeElem.getChildText(XML_SEGMENT);
- }
- init(type, segmentText);
- }
-
- /**
- * Create a new Position object with the specified type and
- * segment.
- *
- * @param type
- * @param segment
- * @throws IllegalArgumentException if the specified type and segment do not
- * form a valid pair.
- */
- public Position(String type, String segment) {
- init(type, segment);
- }
-
- /**
- * Initialize the internal fields.
- *
- * @param type
- * @param segment
- */
- private void init(String type, String segment) {
- if ((XML_AFTER.equals(type) || XML_BEFORE.equals(type)) && (segment == null || "".equals(segment))) {
- throw new IllegalArgumentException("If type is other than 'first' or 'last' a segment must be specified");
- }
- setType(type);
- this.segment = segment;
- }
-
- /**
- * Return the type of this Position object, which may be any
- * of the following valid types: {@link #XML_FIRST first},
- * {@link #XML_LAST last}, {@link #XML_AFTER after}, {@link #XML_BEFORE before}
- *
- * @return type
- */
- public int getType() {
- return type;
- }
-
- /**
- * Set the type.
- *
- * @param xmlType
- */
- private void setType(String xmlType) {
- type = ((Integer)xmlTypeMap.get(xmlType)).intValue();
- }
-
- /**
- * Returns the segment used to create this Position object or
- * null if no segment is present with the type.
- *
- * @return segment or null
- * @see #getType()
- */
- public String getSegment() {
- return segment;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/ordering/package.html b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/ordering/package.html
deleted file mode 100644
index d59cfbeb8d6..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/ordering/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-
-Contains interfaces and classes used to cover the functionality defined by the
-RFC 3648: Web Distributed Authoring
-and Versioning (WebDAV) Ordered Collections Protocol .
-
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/AbstractDavProperty.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/AbstractDavProperty.java
deleted file mode 100644
index 80da6498fd9..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/AbstractDavProperty.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.property;
-
-import org.apache.log4j.Logger;
-import org.jdom.Element;
-
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * AbstractDavProperty provides generic METHODS used by various
- * implementations of the {@link DavProperty} interface.
- */
-public abstract class AbstractDavProperty implements DavProperty {
-
- private static Logger log = Logger.getLogger(AbstractDavProperty.class);
-
- private final DavPropertyName name;
- private final boolean isProtected;
-
- /**
- * Create a new AbstractDavProperty with the given {@link DavPropertyName}
- * and a boolean flag indicating whether this property is protected.
- *
- * @param name
- * @param isProtected
- */
- public AbstractDavProperty(DavPropertyName name, boolean isProtected) {
- this.name = name;
- this.isProtected = isProtected;
- }
-
- /**
- * Computes the hash code using this propertys name and value.
- *
- * @return the hash code
- */
- public int hashCode() {
- int hashCode = getName().hashCode();
- if (getValue() != null) {
- hashCode += getValue().hashCode();
- }
- return hashCode % Integer.MAX_VALUE;
- }
-
- /**
- * Checks if this property has the same {@link DavPropertyName name}
- * and value as the given one.
- *
- * @param obj the object to compare to
- * @return true if the 2 objects are equal;
- * false otherwise
- */
- public boolean equals(Object obj) {
- if (obj instanceof DavProperty) {
- DavProperty prop = (DavProperty) obj;
- boolean equalName = getName().equals(prop.getName());
- boolean equalValue = (getValue() == null) ? prop.getValue() == null : getValue().equals(prop.getValue());
- return equalName && equalValue;
- }
- return false;
- }
-
-
- /**
- * Return a JDOM element representation of this property. The value of the
- * property will be added as text or as child element.
- *
- * new DavProperty("displayname", "WebDAV Directory").toXml()
- * gives a element like:
- * <D:displayname>WebDAV Directory</D:displayname>
- *
- * new DavProperty("resourcetype", new Element("collection")).toXml()
- * gives a element like:
- * <D:resourcetype><D:collection/></D:resourcetype>
- *
- * Element[] customVals = { new Element("bla", customNamespace), new Element("bli", customNamespace) };
- * new DavProperty("custom-property", customVals, customNamespace).toXml()
- * gives an element like
- * <Z:custom-property>
- * <Z:bla/>
- * <Z:bli/>
- * </Z:custom-property>
- *
- *
- * @return a JDOM element of this property
- * @see DavProperty#toXml()
- */
- public Element toXml() {
- Element elem = getName().toXml();
- Object value = getValue();
- if (value != null) {
- if (value instanceof Element) {
- elem.addContent((Element) value);
- } else if (value instanceof Element[]) {
- elem.addContent(Arrays.asList((Element[])value));
- } else if (value instanceof List) {
- elem.addContent((List)value);
- } else {
- elem.setText(value.toString());
- }
- }
- return elem;
- }
-
- /**
- * Returns the name of this property.
- *
- * @return name
- * @see DavProperty#getName()
- */
- public DavPropertyName getName() {
- return name;
- }
-
- /**
- * Returns true if this property is protected or computed.
- *
- * @return true if this is a protected (or computed) property.
- * @see org.apache.jackrabbit.webdav.property.DavProperty#isProtected()
- */
- public boolean isProtected() {
- return isProtected;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/DavProperty.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/DavProperty.java
deleted file mode 100644
index 700dc790feb..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/DavProperty.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.property;
-
-import org.jdom.Element;
-import org.apache.jackrabbit.webdav.DavConstants;
-
-/**
- * The Property class represents a Property of a WebDAV
- * resource. The {@link #hashCode()} and {@link #equals(Object)} METHODS are
- * overridden in a way, that the name and value of the property are
- * respected. this means, an property is equal to another, if the names
- * and values are equal.
- */
-public interface DavProperty extends DavConstants {
-
- /**
- * Return a JDOM element representation of this property. The value of the
- * property will be added as text or as child element.
- *
- * new DavProperty("displayname", "WebDAV Directory").toXml()
- * gives a element like:
- * <D:displayname>WebDAV Directory</D:displayname>
- *
- * new DavProperty("resourcetype", new Element("collection")).toXml()
- * gives a element like:
- * <D:resourcetype><D:collection/></D:resourcetype>
- *
- * Element[] customVals = { new Element("bla", customNamespace), new Element("bli", customNamespace) };
- * new DavProperty("custom-property", customVals, customNamespace).toXml()
- * gives an element like
- * <Z:custom-property>
- * <Z:bla/>
- * <Z:bli/>
- * </Z:custom-property>
- *
- *
- * @return a JDOM element of this property
- */
- public Element toXml();
-
- /**
- * Returns the name of this property
- *
- * @return the name of this property
- */
- public DavPropertyName getName();
-
- /**
- * Returns the value of this property
- *
- * @return the value of this property
- */
- public Object getValue();
-
- /**
- * Return true if this property is protected. A protected property
- * will not be returned in a {@link DavConstants#PROPFIND_ALL_PROP DAV:allprop}
- * PROPFIND request and cannot be set/removed with a PROPPATCH request.
- *
- * @return true, if this property is protected.
- */
- public boolean isProtected();
-}
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/DavPropertyIterator.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/DavPropertyIterator.java
deleted file mode 100644
index 042836220d7..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/DavPropertyIterator.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.property;
-
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-
-/**
- * The DavPropertyIterator extends the Iterator by
- * a property specific next() method.
- */
-public interface DavPropertyIterator extends Iterator {
- /**
- * Returns the next Property in the interation.
- *
- * @return the next Property in the iteration.
- * @throws java.util.NoSuchElementException if iteration has no more elements.
- */
- public DavProperty nextProperty() throws NoSuchElementException;
-}
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/DavPropertyName.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/DavPropertyName.java
deleted file mode 100644
index 97b36529c02..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/DavPropertyName.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.property;
-
-import org.jdom.Namespace;
-import org.jdom.Element;
-import org.apache.jackrabbit.webdav.DavConstants;
-
-import java.util.HashMap;
-
-/**
- * The DavPropertyName class reflects a Webdav property name. It
- * holds together the actualy name of the property and its namespace.
- */
-public class DavPropertyName implements DavConstants {
-
- /** internal 'cache' of created property names */
- private static final HashMap cache = new HashMap();
-
- /* some standard webdav property (that have #PCDATA) */
- public static final DavPropertyName CREATIONDATE = DavPropertyName.create(PROPERTY_CREATIONDATE);
- public static final DavPropertyName DISPLAYNAME = DavPropertyName.create(PROPERTY_DISPLAYNAME);
- public static final DavPropertyName GETCONTENTLANGUAGE = DavPropertyName.create(PROPERTY_GETCONTENTLANGUAGE);
- public static final DavPropertyName GETCONTENTLENGTH = DavPropertyName.create(PROPERTY_GETCONTENTLENGTH);
- public static final DavPropertyName GETCONTENTTYPE = DavPropertyName.create(PROPERTY_GETCONTENTTYPE);
- public static final DavPropertyName GETETAG = DavPropertyName.create(PROPERTY_GETETAG);
- public static final DavPropertyName GETLASTMODIFIED = DavPropertyName.create(PROPERTY_GETLASTMODIFIED);
-
- /* some standard webdav property (that have other elements) */
- public static final DavPropertyName LOCKDISCOVERY = DavPropertyName.create(PROPERTY_LOCKDISCOVERY);
- public static final DavPropertyName RESOURCETYPE = DavPropertyName.create(PROPERTY_RESOURCETYPE);
- public static final DavPropertyName SOURCE = DavPropertyName.create(PROPERTY_SOURCE);
- public static final DavPropertyName SUPPORTEDLOCK = DavPropertyName.create(PROPERTY_SUPPORTEDLOCK);
-
- /* property use by microsoft that are not specified in the RFC 2518 */
- public static final DavPropertyName ISCOLLECTION = DavPropertyName.create("iscollection");
-
- /** the name of the property */
- private final String name;
-
- /** the namespace of the property */
- private final Namespace namespace;
-
- /**
- * Creates a new DavPropertyName with the given name and
- * Namespace.
- *
- * @param name The local name of the new property name
- * @param namespace The namespace of the new property name
- *
- * @return The WebDAV property name
- */
- public synchronized static DavPropertyName create(String name, Namespace namespace) {
-
- // get (or create) map for the given namespace
- HashMap map = (HashMap) cache.get(namespace);
- if (map == null) {
- map = new HashMap();
- cache.put(namespace, map);
- }
- // get (or create) property name object
- DavPropertyName ret = (DavPropertyName) map.get(name);
- if (ret == null) {
- if (namespace.equals(NAMESPACE)) {
- // ensure prefix for default 'DAV:' namespace
- namespace = NAMESPACE;
- }
- ret = new DavPropertyName(name, namespace);
- map.put(name, ret);
- }
- return ret;
- }
-
- /**
- * Creates a new DavPropertyName with the given local name
- * and the default WebDAV {@link DavConstants#NAMESPACE namespace}.
- *
- * @param name The local name of the new property name
- *
- * @return The WebDAV property name
- */
- public synchronized static DavPropertyName create(String name) {
- return create(name, NAMESPACE);
- }
-
- /**
- * Create a new DavPropertyName with the name and namespace
- * of the given Xml element.
- *
- * @param nameElement
- * @return DavPropertyName instance
- */
- public synchronized static DavPropertyName createFromXml(Element nameElement) {
- if (nameElement == null) {
- throw new IllegalArgumentException("Cannot build DavPropertyName from a 'null' element.");
- }
- Namespace ns = nameElement.getNamespace();
- if (ns == null) {
- return create(nameElement.getName());
- } else {
- return create(nameElement.getName(), ns);
- }
- }
-
- /**
- * Creates a new DavPropertyName with the given name and
- * Namespace.
- *
- * @param name The local name of the new property name
- * @param namespace The namespace of the new property name
- */
- private DavPropertyName(String name, Namespace namespace) {
- if (name == null || namespace == null) {
- throw new IllegalArgumentException("Name and namespace must not be 'null' for a DavPropertyName.");
- }
- this.name = name;
- this.namespace = namespace;
- }
-
- /**
- * Return the name of this DavPropertyName.
- *
- * @return name
- */
- public String getName() {
- return name;
- }
-
- /**
- * Return the namespace of this DavPropertyName.
- *
- * @return namespace
- */
- public Namespace getNamespace() {
- return namespace;
- }
-
-
- /**
- * Computes the hash code using this propertys name and namespace.
- *
- * @return the hash code
- */
- public int hashCode() {
- return (name.hashCode() + namespace.hashCode()) % Integer.MAX_VALUE;
- }
-
- /**
- * Checks if this property has the same name and namespace as the
- * given one.
- *
- * @param obj the object to compare to
- *
- * @return true if the 2 objects are equal;
- * false otherwise
- */
- public boolean equals(Object obj) {
- if (obj instanceof DavPropertyName) {
- DavPropertyName propName = (DavPropertyName) obj;
- return name.equals(propName.name) && namespace.equals(propName.namespace);
- }
- return false;
- }
-
- /**
- * Returns a string representation of this property suitable for debugging
- *
- * @return a human readable string representation
- */
- public String toString() {
- return "{" + namespace.getURI() + "}" + name;
- }
-
- /**
- * Creates a JDOM element with the name and namespace of this
- * DavPropertyName.
- *
- * @return A JDOM Element.
- */
- public Element toXml() {
- return new Element(name, namespace);
- }
-}
-
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/DavPropertyNameSet.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/DavPropertyNameSet.java
deleted file mode 100644
index 50e52fd4220..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/DavPropertyNameSet.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.property;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.DavConstants;
-import org.jdom.Element;
-
-import java.util.HashSet;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * DavPropertyNameSet represents a Set of {@link DavPropertyName}
- * objects.
- */
-public class DavPropertyNameSet extends HashSet {
-
- private static Logger log = Logger.getLogger(DavPropertyNameSet.class);
-
- /**
- * Create a new empty set.
- * @see HashSet()
- */
- public DavPropertyNameSet() {
- super();
- }
-
- /**
- * Create a new set from the given collection.
- * @param c
- * @see HashSet(Collection)
- */
- public DavPropertyNameSet(Collection c) {
- super(c);
- }
-
- /**
- * Create a new DavPropertyNameSet from the given DAV:prop
- * element.
- *
- * @param propElement
- * @throws IllegalArgumentException if the specified element is null
- * or is not a DAV:prop element.
- */
- public DavPropertyNameSet(Element propElement) {
- super();
- if (propElement == null || !propElement.getName().equals(DavConstants.XML_PROP)) {
- throw new IllegalArgumentException("'DAV:prop' element expected.");
- }
-
- // fill the set
- List props = propElement.getChildren();
- for (int j = 0; j < props.size(); j++) {
- Element prop = (Element) props.get(j);
- String propName = prop.getName();
- if (propName != null && !"".equals(propName)) {
- add(DavPropertyName.create(propName, prop.getNamespace()));
- }
- }
- }
-
- /**
- * Adds the specified {@link DavPropertyName} object to this
- * set if it is not already present.
- *
- * @param propertyName element to be added to this set.
- * @return true if the set did not already contain the specified
- * element.
- */
- public boolean add(DavPropertyName propertyName) {
- return super.add(propertyName);
- }
-
- /**
- * Add the given object to this set. In case the object is not a {@link DavPropertyName}
- * this method returns false.
- *
- * @param o
- * @return true if adding the object was successful.
- * @see #add(DavPropertyName)
- */
- public boolean add(Object o) {
- if (o instanceof DavPropertyName) {
- return add((DavPropertyName) o);
- } else {
- return false;
- }
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/DavPropertySet.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/DavPropertySet.java
deleted file mode 100644
index b48fa113ce2..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/DavPropertySet.java
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.property;
-
-import org.jdom.Namespace;
-import org.apache.jackrabbit.webdav.DavConstants;
-
-import java.util.*;
-
-/**
- * The DavPropertySet class represents a set of WebDAV
- * property.
- */
-public class DavPropertySet {
-
- /**
- * the set of property
- */
- private final HashMap map = new HashMap();
-
- /**
- * Adds a new property to this set.
- *
- * @param property The property to add
- *
- * @return The previously assigned property or null.
- */
- public DavProperty add(DavProperty property) {
- return (DavProperty) map.put(property.getName(), property);
- }
-
- /**
- *
- * @param pset Properties to add
- */
- public void addAll(DavPropertySet pset) {
- map.putAll(pset.map);
- }
-
- /**
- * Retrieves the property with the specified name and the
- * default WebDAV {@link org.apache.jackrabbit.webdav.DavConstants#NAMESPACE namespace}.
- *
- * @param name The name of the property to retrieve
- *
- * @return The desired property or null
- */
- public DavProperty get(String name) {
- return get(DavPropertyName.create(name));
- }
-
- /**
- * Retrieves the property with the specified name and
- * namespace.
- *
- * @param name The name of the property to retrieve
- * @param namespace The namespace of the property to retrieve
- *
- * @return The desired property or null
- */
- public DavProperty get(String name, Namespace namespace) {
- return get(DavPropertyName.create(name, namespace));
- }
-
- /**
- * Retrieves the property with the specified name
- *
- * @param name The webdav property name of the property to retrieve
- *
- * @return The desired property or null
- */
- public DavProperty get(DavPropertyName name) {
- return (DavProperty) map.get(name);
- }
-
-
- /**
- * Removes the indicated property from this set.
- *
- * @param name The webdav property name to remove
- *
- * @return The removed property or null
- */
- public DavProperty remove(DavPropertyName name) {
- return (DavProperty) map.remove(name);
- }
-
- /**
- * Removes the property with the specified name and the
- * default WebDAV {@link org.apache.jackrabbit.webdav.DavConstants#NAMESPACE namespace}.
- *
- * @param name The name of the property to remove
- *
- * @return The removed property or null
- */
- public DavProperty remove(String name) {
- return remove(DavPropertyName.create(name));
- }
-
- /**
- * Removes the property with the specified name and
- * namespace from this set.
- *
- * @param name The name of the property to remove
- * @param namespace The namespace of the property to remove
- *
- * @return The removed property or null
- */
- public DavProperty remove(String name, Namespace namespace) {
- return remove(DavPropertyName.create(name, namespace));
- }
-
- /**
- * Returns an iterator over all property in this set.
- *
- * @return An iterator over {@link DavProperty}.
- */
- public DavPropertyIterator iterator() {
- return new PropIter();
- }
-
- /**
- * Returns an iterator over all those property in this set, that have the
- * indicated namespace.
- *
- * @param namespace The namespace of the property in the iteration.
- *
- * @return An iterator over {@link DavProperty}.
- */
- public DavPropertyIterator iterator(Namespace namespace) {
- return new PropIter(namespace);
- }
-
- /**
- * Checks if this set contains the property with the specified name.
- *
- * @param name The name of the property
- *
- * @return true if this set contains the property;
- * false otherwise.
- */
- public boolean contains(DavPropertyName name) {
- return map.containsKey(name);
- }
-
- /**
- * Checks if this set contains the property with the specified name and the
- * default WebDAV {@link org.apache.jackrabbit.webdav.DavConstants#NAMESPACE namespace}.
- *
- * @param name The name of the property
- *
- * @return true if this set contains the property;
- * false otherwise.
- */
- public boolean contains(String name) {
- return contains(DavPropertyName.create(name, DavConstants.NAMESPACE));
- }
-
- /**
- * Return true if this property set is empty.
- *
- * @return true if the internal map contains no elements.
- */
- public boolean isEmpty() {
- return map.isEmpty();
- }
-
- /**
- * Return the names of all properties present in this set.
- *
- * @return array of {@link DavPropertyName property names} present in this set.
- */
- public DavPropertyName[] getPropertyNames() {
- Set keySet = map.keySet();
- return (DavPropertyName[]) keySet.toArray(new DavPropertyName[keySet.size()]);
- }
-
- //---------------------------------------------------------- Inner class ---
- /**
- * Implementation of a DavPropertyIterator that returns webdav property.
- * Additionally, it can only return property with the given namespace.
- */
- private class PropIter implements DavPropertyIterator {
-
- /** the namespace to match agains */
- private final Namespace namespace;
-
- /** the internal iterator */
- private final Iterator iterator;
-
- /** the next property to return */
- private DavProperty next;
-
- /**
- * Creates a new property iterator.
- */
- private PropIter() {
- this(null);
- }
-
- /**
- * Creates a new iterator with the given namespace
- * @param namespace The namespace to match against
- */
- private PropIter(Namespace namespace) {
- this.namespace = namespace;
- iterator = map.values().iterator();
- seek();
- }
-
- /**
- * @see DavPropertyIterator#nextProperty();
- */
- public DavProperty nextProperty() throws NoSuchElementException {
- if (next==null) {
- throw new NoSuchElementException();
- }
- DavProperty ret = next;
- seek();
- return ret;
- }
-
- /**
- * @see DavPropertyIterator#hasNext();
- */
- public boolean hasNext() {
- return next!=null;
- }
-
- /**
- * @see DavPropertyIterator#next();
- */
- public Object next() {
- return nextProperty();
- }
-
- /**
- * @see DavPropertyIterator#remove();
- */
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Seeks for the next valid property
- */
- private void seek() {
- while (iterator.hasNext()) {
- next = (DavProperty) iterator.next();
- if (namespace == null || namespace.equals(next.getName().getNamespace())) {
- return;
- }
- }
- next = null;
- }
- }
-}
-
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/DefaultDavProperty.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/DefaultDavProperty.java
deleted file mode 100644
index ff533d5a741..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/DefaultDavProperty.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.property;
-
-import org.apache.log4j.Logger;
-import org.jdom.Namespace;
-import org.jdom.Element;
-import org.jdom.Content;
-import org.jdom.Text;
-
-/**
- * DefaultDavProperty...
- */
-public class DefaultDavProperty extends AbstractDavProperty {
-
- private static Logger log = Logger.getLogger(DefaultDavProperty.class);
-
- /**
- * the value of the property
- */
- private final Object value;
-
- /**
- * Creates a new WebDAV property with the given namespace, name and value.
- * If the property is intended to be protected the isProtected flag must
- * be set to true.
- *
- * @param name the name of the property
- * @param value the value of the property
- * @param namespace the namespace of the property
- * @param isProtected A value of true, defines this property to be protected.
- * It will not be returned in a {@link org.apache.jackrabbit.webdav.DavConstants#PROPFIND_ALL_PROP DAV:allprop}
- * PROPFIND request and cannot be set/removed with a PROPPATCH request.
- */
- public DefaultDavProperty(String name, Object value, Namespace namespace, boolean isProtected) {
- super(DavPropertyName.create(name, namespace), isProtected);
- this.value = value;
- }
-
- /**
- * Creates a new non-protected WebDAV property with the given namespace, name
- * and value.
- *
- * @param name the name of the property
- * @param value the value of the property
- * @param namespace the namespace of the property
- */
- public DefaultDavProperty(String name, Object value, Namespace namespace) {
- this(name, value, namespace, false);
- }
-
- /**
- * Creates a new WebDAV property with the given DavPropertyName
- * and value. If the property is meant to be protected the 'isProtected'
- * flag must be set to true.
- *
- * @param name the name of the property
- * @param value the value of the property
- * @param isProtected A value of true, defines this property to be protected.
- * It will not be returned in a {@link org.apache.jackrabbit.webdav.DavConstants#PROPFIND_ALL_PROP DAV:allprop}
- * PROPFIND request and cannot be set/removed with a PROPPATCH request.
- */
- public DefaultDavProperty(DavPropertyName name, Object value, boolean isProtected) {
- super(name, isProtected);
- this.value = value;
- }
-
- /**
- * Creates a new non- protected WebDAV property with the given
- * DavPropertyName and value.
- *
- * @param name the name of the property
- * @param value the value of the property
- */
- public DefaultDavProperty(DavPropertyName name, Object value) {
- this(name, value, false);
- }
-
- /**
- * Returns the value of this property
- *
- * @return the value of this property
- */
- public Object getValue() {
- return value;
- }
-
- /**
- * Create a new DefaultDavProperty instance from the given Xml
- * element. Name and namespace of the element are building the {@link DavPropertyName},
- * while the element's content forms the property value. The following logic
- * is applied:
- *
- * - empty Element -> null value
- * - single Text content -> String value
- * - single non-Text content -> Element.getContent(0) is used as value
- * - other: List obtained from Element.getContent() is used as value
- *
- *
- * @param propertyElement
- * @return
- */
- public static DefaultDavProperty createFromXml(Element propertyElement) {
- if (propertyElement == null) {
- throw new IllegalArgumentException("Cannot create a new DavProperty from a 'null' element.");
- }
- DavPropertyName name = DavPropertyName.createFromXml(propertyElement);
- Object value;
- int size = propertyElement.getContentSize();
- switch (size) {
- case 0:
- value = null;
- break;
- case 1:
- Content c = propertyElement.getContent(0);
- if (c instanceof Text) {
- value = ((Text)c).getText();
- } else {
- value = c;
- }
- break;
- default:
- value = propertyElement.getContent();
- }
- return new DefaultDavProperty(name, value, false);
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/HrefProperty.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/HrefProperty.java
deleted file mode 100644
index ee9c5c5cbf4..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/HrefProperty.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.property;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.util.XmlUtil;
-import org.jdom.Element;
-
-import java.util.List;
-import java.util.Iterator;
-import java.util.ArrayList;
-import java.util.Arrays;
-
-/**
- * HrefProperty is an extension to the common {@link DavProperty}.
- * The String representation of the property value is always displayed as text
- * inside an extra 'href' element. If the value is a String array each array
- * element is added as text to a separate 'href' element.
- *
- * @see org.apache.jackrabbit.webdav.DavConstants#XML_HREF
- * @see org.apache.jackrabbit.webdav.property.DavProperty#getValue()
- */
-public class HrefProperty extends AbstractDavProperty {
-
- private static Logger log = Logger.getLogger(HrefProperty.class);
-
- private final String[] value;
-
- /**
- * Creates a new WebDAV property with the given DavPropertyName
- *
- * @param name the name of the property
- * @param value the value of the property
- * @param isProtected A value of true, defines this property to be protected.
- * It will not be returned in a {@link org.apache.jackrabbit.webdav.DavConstants#PROPFIND_ALL_PROP DAV:allprop}
- * PROPFIND request and cannot be set/removed with a PROPPATCH request.
- */
- public HrefProperty(DavPropertyName name, String value, boolean isProtected) {
- super(name, isProtected);
- this.value = new String[]{value};
- }
-
- /**
- * Creates a new WebDAV property with the given DavPropertyName
- *
- * @param name the name of the property
- * @param value the value of the property
- * @param isProtected A value of true, defines this property to be protected.
- * It will not be returned in a {@link org.apache.jackrabbit.webdav.DavConstants#PROPFIND_ALL_PROP DAV:allprop}
- * PROPFIND request and cannot be set/removed with a PROPPATCH request.
- */
- public HrefProperty(DavPropertyName name, String[] value, boolean isProtected) {
- super(name, isProtected);
- this.value = value;
- }
-
- /**
- * Create a new HrefProperty from the specified property.
- * Please note, that the property must have a List value
- * object, consisting of {@link #XML_HREF href} Element entries.
- *
- * @param prop
- * @throws IllegalArgumentException if the property {@link DavProperty#getValue() value}
- * is not a List.
- */
- public HrefProperty(DavProperty prop) {
- super(prop.getName(), prop.isProtected());
- if (! (prop.getValue() instanceof List)) {
- throw new IllegalArgumentException("Expected a property with a List value object.");
- }
- Iterator it = ((List)prop.getValue()).iterator();
- ArrayList hrefList = new ArrayList();
- while (it.hasNext()) {
- Object o = it.next();
- if (o instanceof Element) {
- String href = ((Element)o).getChildText(XML_HREF, NAMESPACE);
- if (href != null) {
- hrefList.add(href);
- } else {
- log.warn("Valid DAV:href element expected instead of " + o.toString());
- }
- } else {
- log.warn("DAV: href element expected in the content of " + getName().toString());
- }
- }
- value = (String[]) hrefList.toArray(new String[hrefList.size()]);
- }
-
- /**
- * Returns an Xml element with the following form:
- *
- * where Z: represents the prefix of the namespace defined with the initial
- * webdav property name.
- *
- * @return Xml representation
- * @see XmlUtil#hrefToXml(String)
- */
- public Element toXml() {
- Element elem = getName().toXml();
- Object value = getValue();
- if (value != null) {
- if (value instanceof String[]) {
- String[] hrefs = (String[]) value;
- for (int i = 0; i < hrefs.length; i++) {
- elem.addContent(XmlUtil.hrefToXml(hrefs[i]));
- }
- } else {
- elem.addContent(XmlUtil.hrefToXml(value.toString()));
- }
- }
- return elem;
- }
-
- /**
- * Returns an array of String.
- *
- * @return an array of String.
- * @see DavProperty#getValue()
- */
- public Object getValue() {
- return value;
- }
-
- /**
- * Return an array of String containg the text of those DAV:href elements
- * that would be returned as child elements of this property on {@link #toXml()}
- *
- * @return
- */
- public List getHrefs() {
- return (value != null) ? Arrays.asList(value) : new ArrayList();
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/ResourceType.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/ResourceType.java
deleted file mode 100644
index 224e9943dde..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/ResourceType.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.property;
-
-import org.jdom.Element;
-
-/**
- * The ResourceType class represents the webdav resource
- * type property. Valid resource types are '{@link #COLLECTION collection}',
- * {@link #DEFAULT_RESOURCE}.
- */
-public class ResourceType extends AbstractDavProperty {
-
- /**
- * The default resource type
- */
- public static final int DEFAULT_RESOURCE = 0;
-
- /**
- * The collection resource type
- */
- public static final int COLLECTION = DEFAULT_RESOURCE + 1;
-
- private int resourceType = DEFAULT_RESOURCE;
-
- /**
- * Create a resource type property
- */
- public ResourceType(int resourceType) {
- super(DavPropertyName.RESOURCETYPE, false);
- if (!isValidResourceType(resourceType)) {
- throw new IllegalArgumentException("Invalid resource type '"+ resourceType +"'.");
- }
- this.resourceType = resourceType;
- }
-
- /**
- * Return the JDOM element representation of this resource type
- *
- * @return a JDOM element
- */
- public Element toXml() {
- Element elem = getName().toXml();
- if (getValue() != null) {
- elem.addContent((Element)getValue());
- }
- return elem;
- }
-
- /**
- * Returns the Xml representation of this resource type.
- *
- * @return Xml representation of this resource type.
- * @see DavProperty#getValue()
- */
- public Object getValue() {
- return (resourceType == COLLECTION) ? new Element(XML_COLLECTION, NAMESPACE) : null;
- }
-
- /**
- * Returns the resource type specified with the constructor.
- *
- * @return resourceType
- */
- public int getResourceType() {
- return resourceType;
- }
-
- /**
- * Validates the specified resourceType.
- *
- * @param resourceType
- * @return true if the specified resourceType is valid.
- */
- public boolean isValidResourceType(int resourceType) {
- if (resourceType < DEFAULT_RESOURCE || resourceType > COLLECTION) {
- return false;
- }
- return true;
- }
-}
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/package.html b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/package.html
deleted file mode 100644
index 5794344d36d..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/property/package.html
+++ /dev/null
@@ -1,3 +0,0 @@
-
-Interfaces and classes related to WebDAV properties.
-
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/search/QueryGrammerSet.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/search/QueryGrammerSet.java
deleted file mode 100644
index 252d808b878..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/search/QueryGrammerSet.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.search;
-
-import org.apache.jackrabbit.webdav.property.DavProperty;
-import org.apache.jackrabbit.webdav.property.AbstractDavProperty;
-import org.jdom.Element;
-import org.jdom.Namespace;
-
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Iterator;
-
-/**
- * QueryGrammerSet is a {@link DavProperty} that
- * encapsulates the 'supported-query-grammer-set' as defined by the
- * Webdav SEARCH internet draft.
- */
-public class QueryGrammerSet extends AbstractDavProperty implements SearchConstants {
-
- private List queryLanguages = new ArrayList();
-
- /**
- * Create a new QueryGrammerSet from the given query languages
- * string array. The default {@link SearchConstants#NAMESPACE} is assumed.
- * @param qLanguages
- */
- public QueryGrammerSet(String[] qLanguages) {
- super(QUERY_GRAMMER_SET, true);
- if (qLanguages != null) {
- for (int i = 0; i < qLanguages.length; i++) {
- queryLanguages.add(new Element(qLanguages[i], SearchConstants.NAMESPACE));
- }
- }
- }
-
- /**
- * Add another query language to this set.
- *
- * @param qLanguage
- * @param namespace
- */
- public void addQueryLanguage(String qLanguage, Namespace namespace) {
- if (namespace == null) {
- namespace = SearchConstants.NAMESPACE;
- }
- queryLanguages.add(new Element(qLanguage, namespace));
- }
-
- /**
- * Return a String array containing the URIs of the query
- * languages supported.
- *
- * @return names of the supported query languages
- */
- public String[] getQueryLanguages() {
- int size = queryLanguages.size();
- if (size > 0) {
- String[] qLangStr = new String[size];
- Element[] elements = (Element[]) queryLanguages.toArray(new Element[size]);
- for (int i = 0; i < elements.length; i++) {
- qLangStr[i] = elements[i].getNamespaceURI() + elements[i].getName();
- }
- return qLangStr;
- } else {
- return new String[0];
- }
- }
-
- /**
- * Return the Xml representation of this property according to the definition
- * of the 'supported-query-grammer-set'.
- *
- * @return Xml representation
- * @see SearchConstants#QUERY_GRAMMER_SET
- * @see org.apache.jackrabbit.webdav.property.DavProperty#toXml()
- */
- public Element toXml() {
- Element elem = getName().toXml();
- Iterator qlIter = queryLanguages.iterator();
- while (qlIter.hasNext()) {
- Element grammer = new Element(XML_GRAMMER, SearchConstants.NAMESPACE).addContent((Element)qlIter.next());
- Element sqg = new Element(XML_QUERY_GRAMMAR, SearchConstants.NAMESPACE).addContent(grammer);
- elem.addContent(sqg);
- }
- return elem;
- }
-
- /**
- * Returns the list of supported query languages.
- *
- * @return list of supported query languages.
- * @see org.apache.jackrabbit.webdav.property.DavProperty#getValue()
- */
- public Object getValue() {
- return queryLanguages;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/search/SearchConstants.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/search/SearchConstants.java
deleted file mode 100644
index fe2ef5451fe..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/search/SearchConstants.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.search;
-
-import org.apache.jackrabbit.webdav.property.DavPropertyName;
-import org.apache.jackrabbit.webdav.DavConstants;
-import org.jdom.Namespace;
-
-/**
- * SearchConstants interface provide constants for request
- * and response headers, Xml elements and property names used for WebDAV
- * search.
- */
-public interface SearchConstants {
-
- /**
- * Namespace definition.
- * NOTE: For convenience reasons, the namespace is defined to be the default
- * {@link DavConstants#NAMESPACE DAV:} namespace. This is not correct for the
- * underlaying specification is still in a draft state. See also the editorial
- * note inside the
- * Internet Draft WebDAV Search
- * document.
- */
- public static final Namespace NAMESPACE = DavConstants.NAMESPACE;
-
- /**
- * The DASL response header specifing the query languages supported by
- * the requested resource.
- */
- public static final String HEADER_DASL = "DASL";
-
- /**
- * Xml element name for a single query grammar element inside
- * the {@link #QUERY_GRAMMER_SET supported-query-grammer-set property}.
- */
- public static final String XML_QUERY_GRAMMAR = "supported-query-grammar";
-
- /**
- * Name constant for the 'DAV:grammar' element, which is used inside the
- * {@link #XML_QUERY_GRAMMAR} element.
- */
- public static final String XML_GRAMMER = "grammar";
-
- /**
- * Xml element name for the required request body of a SEARCH request.
- *
- * @see SearchRequest
- * @see SearchResource#search(SearchRequest)
- */
- public static final String XML_SEARCHREQUEST = "searchrequest";
-
- /**
- * Optional Xml element name used in the SEARCH request body instead of {@link XML_SEARCHREQUEST}
- * in order to access a given query schema.
- */
- public static final String XML_QUERY_SCHEMA_DISCOVERY = "query-schema-discovery";
-
-
- /**
- * Predefined basic query grammer.
- */
- public static final String BASICSEARCH = NAMESPACE.getPrefix()+"basicsearch";
-
- /**
- * Property indicating the set of query languages the given resource is
- * able deal with. The property has the following definition:
- *
- */
- public static final DavPropertyName QUERY_GRAMMER_SET = DavPropertyName.create("supported-query-grammar-set", NAMESPACE);
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/search/SearchRequest.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/search/SearchRequest.java
deleted file mode 100644
index 1aa792fea07..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/search/SearchRequest.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.search;
-
-import org.apache.log4j.Logger;
-import org.jdom.*;
-
-/**
- * SearchRequest parses the 'searchrequest' element of a SEARCH
- * request body and performs basic validation. Both query language and the
- * query itself can be access from the resulting object.
- * NOTE: The query is expected to be represented by the text contained in the
- * Xml element specifying the query language, thus the 'basicsearch' defined
- * by the Webdav Search Internet Draft is not supported by this implementation.
- *
- *
- * Example of a valid 'searchrequest' body
- *
- *
- */
-public class SearchRequest implements SearchConstants {
-
- private static Logger log = Logger.getLogger(SearchRequest.class);
-
- private final Element language;
-
- /**
- * Create a new SearchRequest from the specified element.
- *
- * @param searchRequest
- * @throws IllegalArgumentException if the element's name is other than
- * 'searchrequest' or if it does not contain a single child element specifying
- * the query language to be used.
- */
- public SearchRequest(Element searchRequest) {
- if (searchRequest == null || !XML_SEARCHREQUEST.equals(searchRequest.getName())) {
- throw new IllegalArgumentException("The root element must be 'searchrequest'.");
- } else if (searchRequest.getChildren().size() != 1) {
- throw new IllegalArgumentException("A single child element is expected with the 'searchrequest'.");
- }
- Element child = (Element)searchRequest.getChildren().get(0);
- language = (Element) child.detach();
- }
-
- /**
- * Create a new SearchRequest from the specifying document
- * retrieved from the request body.
- *
- * @param searchDocument
- * @see #SearchRequest(Element)
- */
- public SearchRequest(Document searchDocument) {
- this(searchDocument.getRootElement());
- }
-
- /**
- * Returns the name of the query language to be used.
- *
- * @return name of the query language
- */
- public String getLanguageName() {
- return language.getName();
- }
-
- /**
- * Returns the namespace of the language specified with the search request element.
- *
- * @return namespace of the requestes language.
- */
- public Namespace getLanguageNameSpace() {
- return language.getNamespace();
- }
-
- /**
- * Return the query string.
- *
- * @return query string
- */
- public String getQuery() {
- return language.getText();
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/search/SearchResource.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/search/SearchResource.java
deleted file mode 100644
index 1ac328f0210..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/search/SearchResource.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.search;
-
-import org.apache.jackrabbit.webdav.MultiStatus;
-import org.apache.jackrabbit.webdav.DavException;
-
-/**
- * SearchResource defines METHODS required in order to handle
- * a SEARCH request.
- */
-public interface SearchResource {
-
- /**
- * No extra compliance class defined by the Webdav Search spec.
- * Instead an extra DASL header is included.
- */
- public String COMPLIANCE_CLASS = "";
-
- /**
- * The 'SEARCH' method
- */
- public String METHODS = "SEARCH";
-
-
- /**
- * Returns the protected DAV:supported-method-set property which is defined
- * mandatory by RTF 3253. This method call is a shortcut for
- * DavResource.getProperty(SearchConstants.QUERY_GRAMMER_SET).
- *
- * @return the DAV:supported-query-grammer-set
- * @see SearchConstants#QUERY_GRAMMER_SET
- */
- public QueryGrammerSet getQueryGrammerSet();
-
- /**
- * Runs a search with the language and query defined in the {@link SearchRequest}
- * object specified and returns a {@link MultiStatus} object listing the
- * results.
- *
- * @param sRequest SearchRequest element encapsulating the SEARCH
- * request body.
- * @return MultiStatus object listing the results.
- * @throws DavException
- */
- public MultiStatus search(SearchRequest sRequest) throws DavException;
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/search/package.html b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/search/package.html
deleted file mode 100644
index a42961cb3af..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/search/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-
-Contains interfaces and classes used to cover the functionality defined by the
-Internet
-Draft WebDAV Search.
-
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/statuscode.properties b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/statuscode.properties
deleted file mode 100644
index 94a5e6e40bc..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/statuscode.properties
+++ /dev/null
@@ -1,47 +0,0 @@
-100=Continue
-101=Switching Protocols
-102=Processing
-200=OK
-201=Created
-202=Accepted
-203=Non-Authoritative Information
-204=No Content
-205=Reset Content
-206=Partial Content
-207=Multi-Status
-300=Multiple Choices
-301=Moved Permanently
-302=Found
-303=See Other
-304=Not Modified
-305=Use Proxy
-307=Temporary Redirect
-400=Bad Request
-401=Unauthorized
-402=Payment Required
-403=Forbidden
-404=Not Found
-405=Method Not Allowed
-406=Not Acceptable
-407=Proxy Authentication Required
-408=Request Time-out
-409=Conflict
-410=Gone
-411=Length Required
-412=Precondition Failed
-413=Request Entity Too Large
-414=Request-URI Too Large
-415=Unsupported Media Type
-416=Requested range not satisfiable
-417=Expectation Failed
-420=Method Failure
-422=Unprocessable Entity
-423=Locked
-424=Failed Dependency
-500=Internal Server Error
-501=Not Implemented
-502=Bad Gateway
-503=Service Unavailable
-504=Gateway Time-out
-505=HTTP Version not supported
-507=Insufficient Storage
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/transaction/TransactionConstants.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/transaction/TransactionConstants.java
deleted file mode 100644
index 5e0ea71d745..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/transaction/TransactionConstants.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.transaction;
-
-import org.apache.jackrabbit.webdav.DavConstants;
-import org.apache.jackrabbit.webdav.lock.Type;
-import org.apache.jackrabbit.webdav.lock.Scope;
-import org.apache.jackrabbit.webdav.property.DavPropertyName;
-import org.jdom.Namespace;
-
-/**
- * TransactionConstants interface provide constants for request
- * and response headers, Xml elements and property names used for handling
- * transactions over WebDAV. There exists no public standard for this functionality.
- *
- * todo: 'local' and 'global' are not accurate terms in the given context > replace
- */
-public interface TransactionConstants {
-
- /**
- * Namespace for transaction related xml elements
- */
- public static final Namespace NAMESPACE = Namespace.getNamespace("jcr", "http://www.day.com/jcr/webdav/1.0");
-
- /**
- * TransactionId Header
- */
- public static final String HEADER_TRANSACTIONID = "TransactionId";
-
- /**
- * transaction XML element
- * Used as element inside the {@link DavConstants#XML_LOCKTYPE locktype}
- * element.
- * @see DavConstants#XML_LOCKTYPE
- */
- public static final String XML_TRANSACTION = "transaction";
-
- /**
- * global XML element
- * Used as element inside of the {@link DavConstants#XML_LOCKSCOPE lockscope} element.
- * It indicates the transaction to be global (e.g. a JCR transaction).
- *
- * @see DavConstants#XML_LOCKSCOPE
- */
- public static final String XML_GLOBAL = "global";
-
- /**
- * local XML element
- * Used as element inside of the {@link DavConstants#XML_LOCKSCOPE lockscope} element.
- * It indicates the transaction to be local (e.g. transient changes to
- * a repository).
- *
- * @see DavConstants#XML_LOCKSCOPE
- */
- public static final String XML_LOCAL = "local";
-
- /**
- * transactioninfo XML element
- * Mandatory element of the UNLOCK request body, if the unlock request
- * is intended to complete a transaction.
- */
- public static final String XML_TRANSACTIONINFO = "transactioninfo";
-
- /**
- * transactionstatus XML element
- * Mandatory element inside the {@link #XML_TRANSACTIONINFO transactioninfo}
- * element indicating how the transaction should be completed.
- * @see #XML_TRANSACTIONINFO
- */
- public static final String XML_TRANSACTIONSTATUS = "transactionstatus";
-
- /**
- * commit XML element
- * Used as element inside of the {@link #XML_TRANSACTIONSTATUS transactionstatus}
- * element. It indicates a completion by committing the transaction.
- * @see #XML_TRANSACTIONSTATUS
- */
- public static final String XML_COMMIT = "commit";
-
- /**
- * rollback XML element
- * Used as element inside of the {@link #XML_TRANSACTIONSTATUS transactionstatus}
- * element. It indicates a completion by roll backing the transaction.
- * @see #XML_TRANSACTIONSTATUS
- */
- public static final String XML_ROLLBACK = "rollback";
-
- /**
- * String defining the 'isnew' property, that identifies a {@link TransactionResource}
- * to be new within the given local transaction, meaning that it exists only in
- * transient storage. This property is not defined by any of the Webdav RTFs.
- * @see javax.jcr.Item#isNew()
- * @see #XML_LOCAL
- */
- public static final DavPropertyName ISNEW = DavPropertyName.create("isnew", NAMESPACE);
-
- /**
- * String defining the 'ismodified' property, that is present on any {@link TransactionResource}
- * that has been modified whithout the corresponding local transaction
- * being completed yet. This property is not defined by any of the Webdav RTFs.
- * @see javax.jcr.Item#isModified()
- * @see #XML_LOCAL
- */
- public static final DavPropertyName ISMODIFIED = DavPropertyName.create("ismodified", NAMESPACE);
-
- /**
- * "transaction" lock type constant.
- * @see #XML_TRANSACTION
- * @see Type#create(String, org.jdom.Namespace)
- */
- public static final Type TRANSACTION = Type.create(XML_TRANSACTION, TransactionConstants.NAMESPACE);
-
- /**
- * "local" lock scope constant.
- *
- * @see #XML_LOCAL
- * @see Scope#create(String, org.jdom.Namespace)
- */
- public static final Scope LOCAL = Scope.create(XML_LOCAL, TransactionConstants.NAMESPACE);
-
- /**
- * "global" lock scope constant.
- *
- * @see #XML_GLOBAL
- * @see Scope#create(String, org.jdom.Namespace)
- */
- public static final Scope GLOBAL = Scope.create(XML_GLOBAL, TransactionConstants.NAMESPACE);
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/transaction/TransactionDavServletRequest.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/transaction/TransactionDavServletRequest.java
deleted file mode 100644
index 22cc8c68584..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/transaction/TransactionDavServletRequest.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.transaction;
-
-import org.apache.jackrabbit.webdav.DavServletRequest;
-
-/**
- * TransactionDavServletRequest provides extensions to the
- * {@link DavServletRequest} interface used for dealing with transaction lock
- * requests.
- */
-public interface TransactionDavServletRequest extends DavServletRequest {
-
- /**
- * Retrieve the 'transactioninfo' request body that must be included with
- * the UNLOCK request of a transaction lock. If the request body is does not
- * provide the information required (either because it is missing or the
- * Xml is not valid) null is returned.
- *
- * @return TransactionInfo object encapsulating the 'transactioninfo'
- * Xml element present in the request body or null if no
- * body is present or if it could not be parsed.
- */
- public TransactionInfo getTransactionInfo();
-
-
- /**
- * Retrieve the transaction id from the
- * {@link TransactionConstants#HEADER_TRANSACTIONID TransactionId header}.
- *
- * @return transaction id as present in the {@link TransactionConstants#HEADER_TRANSACTIONID TransactionId header}
- * or null.
- */
- public String getTransactionId();
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/transaction/TransactionInfo.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/transaction/TransactionInfo.java
deleted file mode 100644
index d35a4b4d41a..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/transaction/TransactionInfo.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.transaction;
-
-import org.apache.log4j.Logger;
-import org.jdom.Element;
-
-/**
- * TransactionInfo class encapsultes the information present
- * in the {@link #XML_TRANSACTIONINFO} element that forms the request body of
- * the UNLOCk request for a transaction lock.
- *
- * @see TransactionConstants#XML_TRANSACTIONINFO
- * @see TransactionConstants#XML_TRANSACTION
- */
-public class TransactionInfo implements TransactionConstants {
-
- private static Logger log = Logger.getLogger(TransactionInfo.class);
-
- private Element status;
-
- /**
- * Creates a TransactionInfo object from the given 'transactionInfo'
- * element. The 'transactionInfo' must have the following form:
- *
- * @param transactionInfo as present in the UNLOCK request body.
- * @throws IllegalArgumentException if the given transactionInfo element
- * is not valid.
- */
- public TransactionInfo(Element transactionInfo) {
- if (transactionInfo == null || !XML_TRANSACTIONINFO.equals(transactionInfo.getName())) {
- throw new IllegalArgumentException("transactionInfo element expected.");
- }
- Element tStatus = transactionInfo.getChild(XML_TRANSACTIONSTATUS, NAMESPACE);
- if (tStatus == null) {
- throw new IllegalArgumentException("transactionInfo must contain a single 'jcr:transactionstatus' element.");
- }
-
- // retrieve status: commit or rollback
- status = tStatus.getChild(XML_COMMIT, NAMESPACE);
- if (status == null) {
- status = tStatus.getChild(XML_ROLLBACK, NAMESPACE);
- }
-
- if (status == null) {
- throw new IllegalArgumentException("'jcr:transactionstatus' element must contain either a '" + XML_COMMIT + "' or a '" + XML_ROLLBACK + "' elements.");
- }
- }
-
- /**
- * Returns either 'commit' or 'rollback' with are the only allowed status
- * types.
- *
- * @return 'commit' or 'rollback'
- * @see #XML_COMMIT
- * @see #XML_ROLLBACK
- */
- public String getStatus() {
- return status.getName();
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/transaction/TxLockEntry.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/transaction/TxLockEntry.java
deleted file mode 100644
index 0fb612b28e3..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/transaction/TxLockEntry.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.transaction;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.lock.Type;
-import org.apache.jackrabbit.webdav.lock.Scope;
-import org.apache.jackrabbit.webdav.lock.AbstractLockEntry;
-
-/**
- * TxLockEntry represents the lock entry objects allowed for
- * a transaction lock.
- */
-public final class TxLockEntry extends AbstractLockEntry implements TransactionConstants {
-
- private static Logger log = Logger.getLogger(TxLockEntry.class);
-
- private final Scope scope;
-
- /**
- * Create a lock entry that identifies transaction lock.
- *
- * @param isLocal boolean value indicating whether this is a local or a global
- * lock entry.
- */
- public TxLockEntry(boolean isLocal) {
- if (isLocal) {
- scope = LOCAL;
- } else {
- scope = GLOBAL;
- }
- }
-
- /**
- * Returns the {@link #TRANSACTION 'transaction'} lock type.
- *
- * @return always returns the 'transaction' type.
- * @see org.apache.jackrabbit.webdav.lock.LockEntry#getType()
- * @see #TRANSACTION
- */
- public Type getType() {
- return TRANSACTION;
- }
-
- /**
- * Returns either {@link #LOCAL local} or {@link #GLOBAL global} scope
- * depending on the initial construtor value.
- *
- * @return returns 'global' or 'local' scope.
- * @see org.apache.jackrabbit.webdav.lock.LockEntry#getScope()
- * @see #GLOBAL
- * @see #LOCAL
- */
- public Scope getScope() {
- return scope;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/transaction/TxLockManager.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/transaction/TxLockManager.java
deleted file mode 100644
index c9eff6a161b..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/transaction/TxLockManager.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2005 Your Corporation. All Rights Reserved.
- */
-package org.apache.jackrabbit.webdav.transaction;
-
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.lock.*;
-
-/**
- * TxLockManager manages locks with locktype
- * '{@link TransactionConstants#TRANSACTION jcr:transaction}'.
- *
- * todo: removing all expired locks
- * todo: 'local' and 'global' are not accurate terms in the given context > replace
- * todo: the usage of the 'global' transaction is not according to the JTA specification,
- * which explicitely requires any transaction present on a servlet to be completed before
- * the service method returns. Starting/completing transactions on the session object,
- * which is possible with the jackrabbit implementation is a hack.
- * todo: review of this transaction part is therefore required. Is there a use-case
- * for those 'global' transactions at all...
- */
-public interface TxLockManager extends LockManager {
-
-
- /**
- * Release the lock identified by the given lock token.
- *
- * @param lockInfo
- * @param lockToken
- * @param resource
- * @throws org.apache.jackrabbit.webdav.DavException
- */
- public void releaseLock(TransactionInfo lockInfo, String lockToken,
- TransactionResource resource) throws DavException;
-
-
- /**
- * Return the lock applied to the given resource or null
- *
- * @param type
- * @param scope
- * @param resource
- * @return lock applied to the given resource or null
- * @see org.apache.jackrabbit.webdav.lock.LockManager#getLock(org.apache.jackrabbit.webdav.lock.Type, org.apache.jackrabbit.webdav.lock.Scope, org.apache.jackrabbit.webdav.DavResource)
- */
- public ActiveLock getLock(Type type, Scope scope, TransactionResource resource);
-
-
-}
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/transaction/package.html b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/transaction/package.html
deleted file mode 100644
index a552dc6ab13..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/transaction/package.html
+++ /dev/null
@@ -1,3 +0,0 @@
-
-Contains interfaces and classes related to transaction locks.
-
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/util/Text.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/util/Text.java
deleted file mode 100644
index 4c7e07c2de2..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/util/Text.java
+++ /dev/null
@@ -1,2042 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.util;
-
-import java.io.ByteArrayOutputStream;
-import java.io.UnsupportedEncodingException;
-import java.math.BigDecimal;
-import java.security.NoSuchAlgorithmException;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.*;
-
-/**
- * This class holds a collection of string utility operations.
- */
-public final class Text extends org.apache.jackrabbit.core.util.Text {
-
- /**
- * The default format pattern used in strftime() if no pattern
- * parameter has been supplied. This is the default format used to format
- * dates in Communiqué 2
- */
- public static final String DEFAULT_DATE_FORMAT_PATTERN = "dd.MM.yyyy HH:mm:ss";
-
- /**
- * Common used DateFormat implementation. When the supplied formatting
- * pattern has been translated it is applied to this formatter and then
- * executed. Both steps occur in a synchronized section, such that no
- * two threads disturb each other.
- *
- *
A single instance of the formatter is used to prevent the object
- * creation overhead. But then how much is this ?
- *
Using one static formatter for each thread may prove to give even
- * more overhead given all those synchronized blocks waiting for each
- * other during real formatting. But then how knows ?
- *
- *
- * This formatter must always be used synchronized as follows :
- *
- *
- */
- private static final SimpleDateFormat dateFormatter = new SimpleDateFormat();
-
- /**
- * The UTC timezone
- */
- public static final TimeZone TIMEZONE_UTC = TimeZone.getTimeZone("UTC");
-
- /** format for RFC 1123 date string -- "Sun, 06 Nov 1994 08:49:37 GMT" */
- private final static SimpleDateFormat rfc1123Format =
- new SimpleDateFormat("EEE, dd MMM yyyyy HH:mm:ss z", Locale.US);
-
- static {
- rfc1123Format.setTimeZone(TIMEZONE_UTC);
- }
-
- /**
- * The local timezone
- */
- public static final TimeZone TIMEZONE_LOCAL = TimeZone.getDefault();
-
- /**
- * Empty result
- */
- private final static String[] empty = new String[0];
-
- /**
- * avoid instantiation
- */
- private Text() {
- }
-
- /**
- * returns an array of strings decomposed of the original string, split at
- * every occurance of 'ch'. if 2 'ch' follow each other with no intermediate
- * characters, empty "" entries are avoided.
- *
- * @param str the string to decompose
- * @param ch the character to use a split pattern
- * @return an array of strings
- */
- public static String[] explode(String str, int ch) {
- return explode(str,ch,false);
- }
-
- /**
- * returns an array of strings decomposed of the original string, split at
- * every occurance of 'ch'.
- * @param str the string to decompose
- * @param ch the character to use a split pattern
- * @param respectEmpty if true, empty elements are generated
- * @return an array of strings
- */
- public static String[] explode(String str, int ch, boolean respectEmpty) {
- if (str == null) {
- return empty;
- }
-
- Vector strings = new Vector();
- int pos = 0;
- int lastpos = 0;
-
- // add snipples
- while ((pos = str.indexOf(ch, lastpos)) >= 0) {
- if (pos-lastpos>0 || respectEmpty)
- strings.add(str.substring(lastpos, pos));
- lastpos = pos+1;
- }
- // add rest
- if (lastpos < str.length()) {
- strings.add(str.substring(lastpos));
- } else if (respectEmpty && lastpos==str.length()) {
- strings.add("");
- }
-
- // return stringarray
- return (String[]) strings.toArray(new String[strings.size()]);
- }
-
- public static String implode(String[] arr, String delim) {
- StringBuffer buf = new StringBuffer();
- for (int i=0; i0) {
- buf.append(delim);
- }
- buf.append(arr[i]);
- }
- return buf.toString();
- }
-
- /**
- * compares to handles lexigographically with one exception: the '/'
- * character is always considered smaller than all other chars. this results
- * in a ordering, in which the parent pages come first (it's about 6 times
- * slower than the string impl. of compareTo).
- *
example (normal string compare):
- *
/foo
- *
/foo-bar
- *
/foo/bar
- *
- *
example (this handle compare):
- *
/foo
- *
/foo/bar
- *
/foo-bar
- *
- *
- * @param h1 the first handle
- * @param h2 the second handle
- * @return the return is positive, if the first handle is bigger than the
- * second; negative, if the first handle is smaller than the second;
- * and zero, if the two handles are equal.
- */
- public static int comparePaths(String h1, String h2) {
- char[] ca1=h1.toCharArray(); // this is faster, than a .charAt everytime
- char[] ca2=h2.toCharArray();
- int n= ca1.length < ca2.length ? ca1.length : ca2.length;
- int i=0;
- while (iparent as parent directory rather than a base
- * handle. if further respects full qualified uri's.
- * examples:
- *
- * parent | path | result
- * ----------+----------+------------
- * "" | "" | /
- * /foo | "" | /foo
- * "" | /foo | /foo
- * "." | foo | foo
- * /foo/bar | bla | /foo/bar/bla
- * /foo/bar | /bla | /bla
- * /foo/bar | ../bla | /foo/bla
- * /foo/bar | ./bla | /foo/bar/bla
- * foo | bar | foo/bar
- * c:/bla | gurk | c:/bla/gurk
- * /foo | c:/bar | c:/bar
- *
- *
- * @param parent the base handle
- * @param path the path
- */
- public static String fullFilePath(String parent, String path) {
- if (parent==null) parent="";
- if (path==null) path="";
-
- // compose source string
- StringBuffer source;
- if (path.equals("") || (path.charAt(0)!='/' && path.indexOf(':')<0)) {
- // relative
- source = new StringBuffer(parent);
- if (!path.equals("")) {
- source.append("/./");
- source.append(path);
- }
- } else {
- // absolute
- source = new StringBuffer(path==null?"":path);
- }
- return makeCanonicalPath(source);
- }
-
- /**
- * returns a full path.
- * if base is empty, '/' is assumed
- * if base and path are relative, a relative path will be generated.
- * examples:
- *
- *
- * @param base the base handle
- * @param path the path
- */
- public static String fullPath(String base, String path) {
- if (base==null) base="";
- if (path==null) path="";
-
- // compose source string
- StringBuffer source;
- if (path.equals("") || path.charAt(0)!='/') {
- // relative
- source = new StringBuffer(base);
- if (!path.equals("")) {
- source.append("/../");
- source.append(path);
- }
- } else {
- // absolute
- source = new StringBuffer(path==null?"":path);
- }
- return makeCanonicalPath(source);
- }
-
- /**
- * Make a path canonical. This is a shortcut for
- *
- * Text.makeCanonicalPath(new StringBuffer(path));
- *
- * @param path path to make canonical
- */
- public static String makeCanonicalPath(String path) {
- return makeCanonicalPath(new StringBuffer(path));
- }
-
- /**
- * make a cannonical path. removes all /./ and /../ and multiple slashes.
- * @param source the input source
- * @return a string containing the cannonical path
- */
- public static String makeCanonicalPath(StringBuffer source) {
- // remove/resolve .. and .
- int dst=0, pos=0, slash=0, dots=0, last=0, len=source.length();
- int[] slashes=new int[1024];
- slashes[0]=source.charAt(0)=='/' ? 0 : -1;
- while (pos=0) source.setCharAt(dst, (char) (last=ch));
- dst++;
- }
- // check dots again
- if (dots == 1) {
- dst = slashes[slash];
- } else if (dots == 2) {
- if (slash > 0) {
- slash--;
- }
- dst = slashes[slash];
- }
-
- // truncate result
- if (dst>0) source.setLength(dst);
- return dst==0 ? "/" : source.toString();
- }
-
- /**
- * Determines, if two handles are sister-pages, that meens, if they
- * represent the same hierarchic level and share the same parent page.
- * @param h1 first handle
- * @param h2 second handle
- * @return true if on same level, false otherwise
- */
- public static boolean isSibling(String h1, String h2) {
- int pos1 = h1.lastIndexOf('/');
- int pos2 = h2.lastIndexOf('/');
- return (pos1==pos2 && pos1>=0 && h1.regionMatches(0,h2,0,pos1));
- }
-
- /**
- * Determines if the descendant handle is hierarchical a
- * descendant of handle.
- *
- * /content/playground/en isDescendantOf /content/playground
- * /content/playground/en isDescendantOf /content
- * /content/playground/en isNOTDescendantOf /content/designground
- * /content/playground/en isNOTDescendantOf /content/playground/en
- *
- *
- * @param handle the current handle
- * @param descendant the potential descendant
- * @return true if the descendant is a descendant;
- * false otherwise.
- * @since gumbear
- */
- public static boolean isDescendant(String handle, String descendant) {
- return !handle.equals(descendant) &&
- descendant.startsWith(handle) &&
- descendant.charAt(handle.length())=='/';
- }
-
- /**
- * Determines if the descendant handle is hierarchical a
- * descendant of handle or equal to it.
- *
- * /content/playground/en isDescendantOrEqualOf /content/playground
- * /content/playground/en isDescendantOrEqualOf /content
- * /content/playground/en isDescendantOrEqualOf /content/playground/en
- * /content/playground/en isNOTDescendantOrEqualOf /content/designground
- *
- *
- * @param path the path to check
- * @param descendant the potential descendant
- * @return true if the descendant is a descendant
- * or equal; false otherwise.
- * @since gumbear
- */
- public static boolean isDescendantOrEqual(String path, String descendant) {
- if (path.equals(descendant)) {
- return true;
- } else {
- String pattern = path.endsWith("/") ? path : path + "/";
- return descendant.startsWith(pattern);
- }
- }
-
- /**
- * Returns the label of a handle
- * @param handle the handle
- * @return the label
- */
- public static String getLabel(String handle) {
- int pos=handle.lastIndexOf('/');
- return pos>=0 ? handle.substring(pos+1) : "";
- }
-
- /**
- * Returns the label of a string
- * @param handle the string
- * @param delim the delimiter
- * @return the label
- */
- public static String getLabel(String handle, char delim) {
- int pos=handle.lastIndexOf(delim);
- return pos>=0 ? handle.substring(pos+1) : "";
- }
-
- /**
- * Digest the plain string using the given algorithm.
- *
- * @param algorithm The alogrithm for the digest. This algorithm must be
- * supported by the MessageDigest class.
- * @param data The plain text String to be digested.
- *
- * @return The digested plain text String represented as Hex digits.
- *
- * @throws NoSuchAlgorithmException if the desired algorithm is not supported by
- * the MessageDigest class.
- *
- * @deprecated since echidna, use {@link #digest(String, String, String)}
- */
- public static String digest(String algorithm, String data)
- throws NoSuchAlgorithmException {
-
- return digest(algorithm, data.getBytes());
- }
-
- /**
- * Returns the nth relative parent of the handle, where n=level.
- *
Example:
- *
- * Text.getRelativeParent("/en/home/index/about", 1) == "/en/home/index"
- *
- *
- * @param handle the handle of the page
- * @param level the level of the parent
- */
- public static String getRelativeParent(String handle, int level) {
- int idx = handle.length();
- while (level > 0) {
- idx = handle.lastIndexOf('/',idx-1);
- if (idx < 0) {
- return "";
- }
- level--;
- }
- return (idx == 0) ? "/" : handle.substring(0,idx);
- }
-
- /**
- * Returns the nth absolute parent of the handle, where n=level.
- *
Example:
- *
- * Text.getAbsoluteParent("/en/home/index/about", 1) == "/en/home"
- *
- *
- * @param handle the handle of the page
- * @param level the level of the parent
- */
- public static String getAbsoluteParent(String handle, int level) {
- int idx = 0;
- int len = handle.length();
- while (level >= 0 && idx=0 ? "" : handle.substring(0,idx);
- }
-
- /**
- * The list of characters that are not encoded by the escape()
- * and unescape() METHODS. They contains the characters as
- * defined 'unreserved' in section 2.3 of the RFC 2396 'URI genric syntax':
- *
- *
- */
- public static BitSet URISave;
-
- /**
- * Same as {@link #URISave} but also contains the '/'
- */
- public static BitSet URISaveEx;
-
- static {
- URISave = new BitSet(256);
- int i;
- for (i = 'a'; i <= 'z'; i++) {
- URISave.set(i);
- }
- for (i = 'A'; i <= 'Z'; i++) {
- URISave.set(i);
- }
- for (i = '0'; i <= '9'; i++) {
- URISave.set(i);
- }
- URISave.set('-');
- URISave.set('_');
- URISave.set('.');
- URISave.set('!');
- URISave.set('~');
- URISave.set('*');
- URISave.set('\'');
- URISave.set('(');
- URISave.set(')');
-
- URISaveEx = (BitSet) URISave.clone();
- URISaveEx.set('/');
- }
-
- /**
- * Does an URL encoding of the string using the
- * escape character. The characters that don't need encoding
- * are those defined 'unreserved' in section 2.3 of the 'URI genric syntax'
- * RFC 2396, but without the escape character.
- *
- * @param string the string to encode.
- * @param escape the escape character.
- * @return the escaped string
- *
- * @throws NullPointerException if string is null.
- */
- public static String escape(String string, char escape) {
- return escape(string, escape, false);
- }
-
- /**
- * Does an URL encoding of the string using the
- * escape character. The characters that don't need encoding
- * are those defined 'unreserved' in section 2.3 of the 'URI genric syntax'
- * RFC 2396, but without the escape character. If isPath is
- * true, additionally the slash '/' is ignored, too.
- *
- * @param string the string to encode.
- * @param escape the escape character.
- * @param isPath if true, the string is treated as path
- *
- * @return the escaped string
- *
- * @throws NullPointerException if string is null.
- */
- public static String escape(String string, char escape, boolean isPath) {
- try {
- BitSet validChars = isPath ? URISaveEx : URISave;
- byte[] bytes = string.getBytes("utf-8");
- StringBuffer out = new StringBuffer(bytes.length);
- for (int i = 0; i < bytes.length; i++) {
- int c = bytes[i]&0xff;
- if (validChars.get(c) && c!=escape) {
- out.append((char)c);
- } else {
- out.append(escape);
- out.append(hexTable[(c>>4) & 0x0f]);
- out.append(hexTable[(c ) & 0x0f]);
- }
- }
- return out.toString();
- } catch (UnsupportedEncodingException e) {
- throw new InternalError(e.toString());
- }
- }
-
- /**
- * Does a URL encoding of the string. The characters that
- * don't need encoding are those defined 'unreserved' in section 2.3 of
- * the 'URI genric syntax' RFC 2396.
- *
- * @param string the string to encode
- * @return the escaped string
- *
- * @throws NullPointerException if string is null.
- */
- public static String escape(String string) {
- return escape(string, '%');
- }
-
- /**
- * Does a URL encoding of the path. The characters that
- * don't need encoding are those defined 'unreserved' in section 2.3 of
- * the 'URI genric syntax' RFC 2396. In contrast to the
- * {@link #escape(String)} method, not the entire path string is escaped,
- * but every individual part (i.e. the slashes are not escaped).
- *
- * @param path the path to encode
- * @return the escaped path
- *
- * @throws NullPointerException if path is null.
- */
- public static String escapePath(String path) {
- return escape(path, '%', true);
- }
-
- /**
- * Does a URL decoding of the string using the
- * escape character. Please note that in opposite to the
- * {@link java.net.URLDecoder} it does not transform the + into spaces.
- * @param string the string to decode
- * @param escape the escape character
- * @return the decoded string
- *
- * @throws NullPointerException if string is null.
- * @throws ArrayIndexOutOfBoundsException if not enough character follow an
- * escape character
- * @throws IllegalArgumentException if the 2 characters following the escape
- * character do not represent a hex-number.
- */
- public static String unescape(String string, char escape) {
- ByteArrayOutputStream out = new ByteArrayOutputStream(string.length());
- for (int i=0; istring
. Please note that in
- * opposite to the {@link java.net.URLDecoder} it does not transform the +
- * into spaces.
- *
- * @param string the string to decode
- * @return the decoded string
- *
- * @throws NullPointerException if string is null.
- * @throws ArrayIndexOutOfBoundsException if not enough character follow an
- * escape character
- * @throws IllegalArgumentException if the 2 characters following the escape
- * character do not represent a hex-number.
- */
- public static String unescape(String string) {
- return unescape(string, '%');
- }
-
- /**
- * Returns a stringified date accoring to the date format specified in
- * RTF1123. this is of the form: "Sun, 06 Nov 1994 08:49:37 GMT"
- */
- public static String dateToRfc1123String(Date date) {
- synchronized (rfc1123Format) {
- return rfc1123Format.format(date);
- }
- }
-
- /**
- * Implements a date formatting routine supporting (a subset) of the POSIX
- * strftime() function.
- *
- * @param date The date value to be formatted
- * @param formatPattern The pattern used to format the date. This pattern
- * supports a subset of the pattern characters of the POSIX
- * strftime() function. If this pattern is empty or
- * null the default pattern
- * dd.MM.yyyy HH:mm:ss is used.
- * @param zone Defines for which time zone the date should be outputted. If
- * this parameter is null, then the local time zone is taken.
- *
- * @return the formatted date as a String.
- */
- public static final String strftime(Date date, String formatPattern, TimeZone zone) {
- // Check whether to apply default format
- if (formatPattern == null || formatPattern.length() == 0) {
- formatPattern = DEFAULT_DATE_FORMAT_PATTERN;
- } else {
- formatPattern = convertFormat(formatPattern);
- }
-
- // check zone
- if (zone == null) zone = TIMEZONE_LOCAL;
-
- // Reuse the global SimpleDateFormat synchronizing on it to prevent
- // multiple tasks from interfering with each other
- synchronized(dateFormatter) {
- dateFormatter.applyPattern(formatPattern);
- dateFormatter.setTimeZone(zone);
- return dateFormatter.format(date);
- }
- }
-
- /**
- * Implements a date formatting routine supporting (a subset) of the POSIX
- * strftime() function.
- *
- * @param date The date value to be formatted
- * @param formatPattern The pattern used to format the date. This pattern
- * supports a subset of the pattern characters of the POSIX
- * strftime() function. If this pattern is empty or
- * null the default pattern
- * dd.MM.yyyy HH:mm:ss is used.
- * @param asUTC Defines whether to interpret the date as belong to the UTC
- * time zone or the local time zone.
- */
- public static final String strftime(Date date, String formatPattern, boolean asUTC) {
- return strftime(date, formatPattern, asUTC ? TIMEZONE_UTC : TIMEZONE_LOCAL);
- }
-
- /**
- * Implements a date formatting routine supporting (a subset) of the POSIX
- * strftime() function. The default pattern
- * dd.MM.yyyy HH:mm:ss is used to format the date.
- *
- * @param date The date value to be formatted
- * @param asUTC Defines whether to interpret the date as belong to the UTC
- * time zone or the local time zone.
- */
- public static final String strftime(Date date, boolean asUTC) {
- return strftime(date, null, asUTC);
- }
-
- /**
- * Implements a date formatting routine supporting (a subset) of the POSIX
- * strftime() function. The default pattern
- * dd.MM.yyyy HH:mm:ss is used to format the date, which is
- * interpreted to be in the local time zone.
- *
- * @param date The date value to be formatted
- */
- public static final String strftime(Date date) {
- return strftime(date, null, false);
- }
-
- /**
- * Parses the date string based on the format pattern which is in the
- * format used by the Java platfrom SimpleDateFormat class.
- *
- * @param dateString The date string to be parsed
- * @param formatPattern the pattern to use for parsing. If null
- * or empty, the same default pattern is used as with
- * {@link #strftime(Date, String, boolean)}, namely
- * dd.MM.yyyy HH:mm:ss.
- *
- * @throws ParseException if the date string cannot be parsed accordinung
- * to the format pattern.
- */
- public static final Date parseDate(String dateString, String formatPattern)
- throws ParseException {
-
- return parseDate(dateString, formatPattern, false);
- }
-
- /**
- * Parses the date string based on the format pattern which is in the
- * format used by the Java platfrom SimpleDateFormat class.
- *
- * @param dateString The date string to be parsed
- * @param formatPattern the pattern to use for parsing. If null
- * or empty, the same default pattern is used as with
- * {@link #strftime(Date, String, boolean)}, namely
- * dd.MM.yyyy HH:mm:ss.
- * @param isUTC if true the date string is considered in UTC,
- * otherwise the default timezone of the host is used.
- *
- * @throws ParseException if the date string cannot be parsed accordinung
- * to the format pattern.
- */
- public static final Date parseDate(String dateString, String formatPattern,
- boolean isUTC)
- throws ParseException {
-
- synchronized (dateFormatter) {
- dateFormatter.applyPattern(formatPattern);
- if (isUTC) {
- dateFormatter.setTimeZone(TIMEZONE_UTC);
- } else {
- dateFormatter.setTimeZone(TimeZone.getDefault());
- }
- return dateFormatter.parse(dateString);
- }
- }
-
- /**
- * Parses the date string based on the format pattern which is in the
- * default format dd.MM.yyyy HH:mm:ss.
- *
- * @param dateString The date string to be parsed
- *
- * @throws ParseException if the date string cannot be parsed accordinung
- * to the format pattern.
- */
- public static final Date parseDate(String dateString) throws ParseException {
- return parseDate(dateString, DEFAULT_DATE_FORMAT_PATTERN, false);
- }
-
- /**
- * Parses the date string based on the format pattern which is in the
- * default format dd.MM.yyyy HH:mm:ss.
- *
- * @param dateString The date string to be parsed
- * @param isUTC if true the date string is considered in UTC,
- * otherwise the default timezone of the host is used.
- *
- *
- * @throws ParseException if the date string cannot be parsed accordinung
- * to the format pattern.
- */
- public static final Date parseDate(String dateString, boolean isUTC)
- throws ParseException {
- return parseDate(dateString, DEFAULT_DATE_FORMAT_PATTERN, isUTC);
- }
-
- //--------- sprintf() formatting constants ---------------------------------
-
- /** left justified - '-' flag */
- private static final int FLAG_LJ = 1;
-
- /** always show sign - '+' flag */
- private static final int FLAG_SI = 2;
-
- /** space placeholder for omitted plus sign - ' ' flag, ignore if SI */
- private static final int FLAG_SP = 3;
-
- /** zero padded if right aligned - '0' flag, ignore if LJ */
- private static final int FLAG_ZE = 4;
-
- /**
- * alternate format - '#' flag :
- * SI - incr. precision to have zero as first char
- * x - prefix '0x'
- * X - prefix '0X'
- * eEf - always show decimal point, omit trailing zeroes
- * gG - always show decimal point, show trailing zeroes
- */
- private static final int FLAG_AL = 5;
-
- /** interpret ints as short - 'h' size */
- private static final int FLAG_SHORT = 8;
-
- /** interpret ints as long - 'l' size */
- private static final int FLAG_LONG = 9;
-
- /** waiting for format */
- private static final int PARSE_STATE_NONE = 0;
-
- /** parsing flags */
- private static final int PARSE_STATE_FLAGS = 1;
-
- /** parsing wdth */
- private static final int PARSE_STATE_WIDTH = 2;
-
- /** parsing precision */
- private static final int PARSE_STATE_PRECISION = 3;
-
- /** parsing size */
- private static final int PARSE_STATE_SIZE = 4;
-
- /** parsing type */
- private static final int PARSE_STATE_TYPE = 5;
-
- /** parsing finished */
- private static final int PARSE_STATE_END = 6;
-
- /** incomplete pattern at end of format string, throw error */
- private static final int PARSE_STATE_ABORT = 7;
-
- /** end of format string during plain text */
- private static final int PARSE_STATE_TERM = 8;
-
- /**
- * This method implements the famous and ubiquituous sprintf
- * formatter in Java. The arguments to the method are the formatting string
- * and the list of arguments defined by the formatting instructions
- * contained in the formatting string.
- *
- * Each element in the argument array is either a Number object
- * or any other Object type. Whenever the formatting string
- * stipulates the corresponding argument to be numeric, it is assumed this
- * array element to be a Number. If this is not the case an
- * IllegalArgumentException is thrown. If a String
- * argument is stipulated by the formatting string, a simple call to the
- * toString() method of the object yields the
- * String required.
- *
- * SPECIFICATION
- *
- * sprintf accepts a series of arguments, applies to each a
- * format specifier from format, and stores the formatted data
- * to the result Strint. The method throws an
- * IllegalArgumentException if either the format
- * is incorrect, there are not enough arguments for the format
- * or if any of the argument's type is wrong. sprintf returns
- * when it reaches the end of the format string. If there are more
- * arguments than the format requires, excess arguments are ignored.
- *
- * format is a String containing two types of
- * objects: ordinary characters (other than %), which
- * are copied unchanged to the output, and conversion specifications,
- * each of which is introduced by %. (To include
- * % in the output, use %% in the format
- * string.) A conversion specification has the following form:
- *
- * The fields of the conversion specification have the following meanings:
- *
- *
- *
flags
- *
an optional sequence of characters which control output
- * justification, numeric signs, decimal points, trailing zeroes, and
- * octal and hex prefixes. The flag characters are minus (-),
- * plus (+), space (""), zero (0),
- * and sharp (# ). They can appear in any combination.
- *
- *
- *
- *
-
- *
The result of the conversion is left justified, and the right
- * is padded with blanks. If you do not use this flag, the result
- * is right justified, and padded on the left.
- *
- *
- *
+
- *
The result of a signed conversion (as determined by type)
- * will always begin with a plus or minus sign. (If you do not use
- * this flag, positive values do not begin with a plus sign.)
- *
- *
- *
"" (space)
- *
If the first character of a signed conversion specification is
- * not a sign, or if a signed conversion results in no characters,
- * the result will begin with a space. If the space
- * () flag and the plus (+) flag both
- * appear, the space flag is ignored.
- *
- *
- *
0
- *
If the type is d, i,
- * o, u, x, X,
- * e, E, f, g,
- * or G: leading zeroes, are used to pad the field
- * width (following any indication of sign or base); no spaces
- * are used for padding. If the zero (0) and minus
- * (-) flags both appear, the zero (0)
- * flag will be ignored. For d, i,
- * o, u, x, X
- * conversions, if a precision prec is specified, the zero
- * (0) flag is ignored.
- *
- * Note that 0 is interpreted as a flag, not as the
- * beginning of a field width.
- *
- *
- *
#
- *
The result is to be converted to an alternative form, according
- * to the type character:
- *
- *
o
- *
Increases precision to force the first digit of the result
- * to be a zero.
- *
- *
x
- *
A non-zero result will have a 0x prefix.
- *
- *
X
- *
A non-zero result will have a 0X prefix.
- *
- *
e, E, or f
- *
The result will always contain a decimal point even if no
- * digits follow the point. (Normally, a decimal point appears
- * only if a digit follows it.) Trailing zeroes are removed.
- *
- *
g or G
- *
Same as e or E, but trailing
- * zeroes arenot removed.
- *
- *
all others
- *
Undefined.
- *
- *
- *
- *
- *
width
- *
width is an optional minimum field width. You can either
- * specify it directly as a decimal integer, or indirectly by using instead
- * an asterisk (*), in which case an integral numeric argument
- * is used as the field width. Negative field widths are not supported; if
- * you attempt to specify a negative field width, it is interpreted as a
- * minus (i) flag followed by a positive field width.
- *
- *
prec
- *
an optional field; if present, it is introduced with
- * `.' (a period). This field gives the maximum number of
- * characters to print in a conversion; the minimum number of digits of an
- * integer to print, for conversions with typed,
- * i, o, u, x, and
- * X; the maximum number of significant digits, for the
- * g and G conversions; or the number of digits
- * to print after the decimal point, for e, E,
- * and f conversions. You can specify the precision either
- * directly as a decimal integer or indirectly by using an asterisk
- * (*), in which case an integral numeric argument is used as
- * the precision. Supplying a negative precision is equivalent to
- * omitting the precision. If only a period is specified the precision
- * is zero. If a precision appears with any other conversion type
- * than those listed here, the behavior is undefined.
- *
- *
size
- *
h, l, and L are optional size
- * characters which override the default way that sprintf
- * interprets the data type of the corresponding argument.
- * h forces the following d, i,
- * o, u, x, or X
- * conversion type to apply to a short or unsigned
- * short. Similarily, an l forces the following
- * d, i, o, u,
- * x, or X conversion type to apply to
- * a long or unsigned long. If an h
- * or an l appears with another conversion specifier, the
- * behavior is undefined. L forces a following
- * e, E, f, g, or
- * G conversion type to apply to a long
- * double argument. If L appears with any other
- * conversion type, the behavior is undefined.
- *
- *
type
- *
type specifies what kind of conversion sprintf
- * performs. Here is a table of these:
- *
- *
- *
%
- *
prints the percent character (%)
- *
- *
c
- *
prints arg as single character. That is the argument is
- * converted to a String of which only the first
- * character is printed.
- *
- *
s
- *
Prints characters until precision is reached or the
- * String ends; takes any Object whose
- * toString() method is called to get the
- * String to print.
- *
- *
d
- *
prints a signed decimal integer; takes a Number (same
- * as i)
- *
- *
d
- *
prints a signed decimal integer; takes a Number (same
- * as d)
- *
- *
d
- *
prints a signed octal integer; takes a Number
- *
- *
u
- *
prints a unsigned decimal integer; takes a Number.
- * This conversion is not supported correctly by the Java
- * implementation and is really the same as i.
- *
- *
x
- *
prints an unsigned hexadecimal integer (using abcdef as
- * digits beyond 9; takes a Number
- *
- *
X
- *
prints an unsigned hexadecimal integer (using ABCDEF as
- * digits beyond 9; takes a Number
- *
- *
f
- *
prints a signed value of the form [-]9999.9999; takes a
- * Number
- *
- *
e
- *
prints a signed value of the form [-]9.9999e[+|-]999; takes
- * a Number
- *
- *
E
- *
prints the same way as e, but using E to
- * introduce the exponent; takes a Number
- *
- *
g
- *
prints a signed value in either f or e
- * form, based on given value and precision &emdash; trailing zeros
- * and the decimal point are printed only if necessary; takes a
- * Number
- *
- *
G
- *
prints the same way as g, but using E
- * for the exponent if an exponent is needed; takes a
- * Number
- *
- *
n
- *
Not supported in the Java implementation, throws an
- * IllegalArgumentException if used.
- *
- *
p
- *
Not supported in the Java implementation, throws an
- * IllegalArgumentException if used.
- *
- *
- *
- *
- *
- * IMPLEMENTATION NOTES
- *
- * Due to the nature of the Java programming language, neither pointer
- * conversions, nor unsigned and long double
- * conversions are supported.
- *
- * Also the Java implementation only distinguishes between
- * Number and other Object arguments. If a
- * numeric argument is expected as per the format
- * String, the current argument must be a Number
- * object that is converted to a basic type as expected. If a
- * String or char argument is expected, any
- * Object is valid, whose toString() method is used to convert
- * to a String.
- *
- * @param format The format string as known from the POSIX sprintf()
- * C function.
- * @param args The list of arguments to accomodate the format string. This
- * argument list is supposed to contain at least as much entries as
- * there are formatting options in the format string. If for a
- * numeric option, the entry is not a number an
- * IllegalArgumentException is thrown.
- *
- * @return The formatted String. An empty String
- * is only returned if the formatString
- * is empty. A null value is never returned.
- *
- * @throws NullPointerException if the formatting string or any of the
- * argument values is null.
- * @throws IllegalArgumentException if the formatting string has wrong
- * format tags, if the formatting string has an incomplete
- * formatting pattern at the end of the string, if the argument
- * vector has not enough values to satisfy the formatting string
- * or if an argument's type does not match the requirements of the
- * format string.
- *
- */
- public static String sprintf(String format, Object[] args) {
-
- // Return immediately if we have no arguments ....
- if (format == null) {
- throw new NullPointerException("format");
- }
-
- if (format.length() == 0) {
- return "";
- }
-
- // Get the format string
- char[] s = format.toCharArray();
-
- // prepare the result, initial size has no sound basis
- StringBuffer res = new StringBuffer( s.length * 3 / 2 );
-
- for (int i=0,j=0, length=format.length(); i < length; ) {
-
- int parse_state = PARSE_STATE_NONE;
- BitSet flags = new BitSet(16);
- int width = 0;
- int precision = -1;
- char fmt = ' ';
-
- // find a start of a formatting ...
- while (parse_state == PARSE_STATE_NONE) {
- if (i >= length) parse_state = PARSE_STATE_TERM;
- else if (s[i] == '%') {
- if (i < length - 1) {
- if (s[i + 1] == '%') {
- res.append('%');
- i++;
- } else {
- parse_state = PARSE_STATE_FLAGS;
- }
- } else {
- throw new java.lang.IllegalArgumentException(
- "Incomplete format at end of format string");
- }
- } else {
- res.append(s[i]);
- }
- i++;
- }
-
- // Get flags, if any
- while (parse_state == PARSE_STATE_FLAGS) {
- if (i >= length) parse_state = PARSE_STATE_ABORT;
- else if (s[i] == ' ') flags.set(FLAG_SP);
- else if (s[i] == '-') flags.set(FLAG_LJ);
- else if (s[i] == '+') flags.set(FLAG_SI);
- else if (s[i] == '0') flags.set(FLAG_ZE);
- else if (s[i] == '#') flags.set(FLAG_AL);
- else {
- parse_state = PARSE_STATE_WIDTH;
- i--;
- }
- i++;
- }
-
- // Get width specification
- while (parse_state == PARSE_STATE_WIDTH) {
- if (i >= length) {
-
- parse_state = PARSE_STATE_ABORT;
-
- } else if ('0' <= s[i] && s[i] <= '9') {
-
- width = width * 10 + s[i] - '0';
- i++;
-
- } else {
- // finished with digits or none at all
-
- // if width is a '*' take width from arg
- if (s[i] == '*') {
- // Check whether we have an argument
- if (j >= args.length) {
- throw new IllegalArgumentException("Missing " +
- "argument for the width");
- }
- try {
- width = ((Number)(args[j++])).intValue();
- } catch (ClassCastException cce) {
- // something wrong with the arg
- throw new IllegalArgumentException("Width " +
- "argument is not numeric");
- }
- i++;
- }
-
- // if next is a dot, then we have a precision, else a size
- if (s[i] == '.') {
- parse_state = PARSE_STATE_PRECISION;
- precision = 0;
- i++;
- } else {
- parse_state = PARSE_STATE_SIZE;
- }
-
- }
- }
-
- // Get precision
- while (parse_state == PARSE_STATE_PRECISION) {
-
- if (i >= length) {
-
- parse_state = PARSE_STATE_ABORT;
-
- } else if ('0' <= s[i] && s[i] <= '9') {
-
- precision = precision * 10 + s[i] - '0';
- i++;
-
- } else {
- // finished with digits or none at all
-
- // if width is a '*' take precision from arg
- if (s[i] == '*') {
- // Check whether we have an argument
- if (j >= args.length) {
- throw new IllegalArgumentException("Missing " +
- "argument for the precision");
- }
- try {
- width = ((Number)(args[j++])).intValue();
- } catch (ClassCastException cce) {
- // something wrong with the arg
- throw new IllegalArgumentException("Precision " +
- "argument is not numeric");
- }
- i++;
- }
-
- parse_state = PARSE_STATE_SIZE;
-
- }
-
- }
-
- // Get size character
- if (parse_state == PARSE_STATE_SIZE) {
- if (i >= length) parse_state = 6;
- else {
- if (s[i] == 'h') {
- flags.set(FLAG_SHORT);
- i++;
- } else if (s[i] == 'l' || s[i] == 'L') {
- flags.set(FLAG_LONG);
- i++;
- }
- parse_state = PARSE_STATE_TYPE;
- }
- }
-
- // Get format character
- if (parse_state == PARSE_STATE_TYPE) {
- if (i >= length) parse_state = PARSE_STATE_ABORT;
- else {
- fmt = s[i];
- i++;
- parse_state = PARSE_STATE_END;
- }
- }
-
- // Now that we have anything, format it ....
- if (parse_state == PARSE_STATE_END) {
-
- // Check whether we have an argument
- if (j >= args.length) {
- throw new IllegalArgumentException("Not enough parameters for the format string");
- }
-
- try {
-
- // Convert the argument according to the flag
- switch (fmt) {
- case 'd': // decimal - fall through
- case 'i': // integral - fall through
- case 'x': // hexadecimal, lower case - fall through
- case 'X': // hexadecimal, upper case - fall through
- case 'o': // octal - fall through
- case 'u': // unsigned (not really supported)
- format(res, (Number)args[j], fmt, width, precision,
- flags);
- break;
-
- case 'f': // float - fall through
- case 'e': // exponential, lower case - fall through
- case 'E': // exponential, upper case - fall through
- case 'g': // float or exp., lower case - fall through
- case 'G': // float or exp., upper case - fall through
- format(res, ((Number)args[j]).doubleValue(), fmt,
- width, precision, flags);
- break;
-
- case 'c': // character
- precision = 1;
- // fall through
-
- case 's': // string
-
- String val = args[j].toString();
- if (val.length() > precision && precision > 0) {
- val = val.substring(0, precision);
- }
-
- flags.clear(FLAG_ZE);
- format(res, val, "", width, flags);
- break;
-
- default : // unknown format
-
- throw new IllegalArgumentException("Unknown " +
- "conversion type " + fmt);
-
- }
-
- } catch (ClassCastException cce) {
- // something wrong with the arg
- throw new IllegalArgumentException("sprintf: Argument #" +
- j + " of type " + args[j].getClass().getName() +
- " does not match format " + fmt);
- }
-
- // goto the next argument
- j++;
- }
-
- // if the format string is not complete
- if (parse_state == PARSE_STATE_ABORT) {
- throw new java.lang.IllegalArgumentException(
- "Incomplete format at end of format string");
- }
-
- } // while i
-
- return res.toString();
- }
-
- /**
- * Formats a string according to format and argument. This method only
- * supports string formats. See {@link #sprintf(String, Object[])} for details.
- *
- * @param format The format string
- * @param a0 The single parameter
- *
- * @return the result from sprintf(format, new Object[]{ a0 }).
- *
- * @throws IllegalArgumentException from {@link #sprintf(String, Object[])}.
- */
- public static String sprintf(String format, Object a0) {
- return sprintf(format, new Object[]{a0});
- }
-
- /**
- * Formats a string according to format and argument. This method only
- * supports string formats. See {@link #sprintf(String, Object[])} for details.
- *
- * @param format The format string
- * @param a0 The first parameter
- * @param a1 The second parameter
- *
- * @return the result from sprintf(format, new Object[]{ ... }).
- *
- * @throws IllegalArgumentException from {@link #sprintf(String, Object[])}.
- */
- public static String sprintf(String format, Object a0, Object a1) {
- return sprintf(format, new Object[]{a0, a1});
- }
-
- /**
- * Formats a string according to format and argument. This method only
- * supports string formats. See {@link #sprintf(String, Object[])} for details.
- *
- * @param format The format string
- * @param a0 The first parameter
- * @param a1 The second parameter
- * @param a2 The thrid parameter
- *
- * @return the result from sprintf(format, new Object[]{ ... }).
- *
- * @throws IllegalArgumentException from {@link #sprintf(String, Object[])}.
- */
- public static String sprintf(String format, Object a0, Object a1,
- Object a2) {
-
- return sprintf(format, new Object[]{a0, a1, a2});
- }
-
- /**
- * Formats a string according to format and argument. This method only
- * supports string formats. See {@link #sprintf(String, Object[])} for details.
- *
- * @param format The format string
- * @param a0 The first parameter
- * @param a1 The second parameter
- * @param a2 The thrid parameter
- * @param a3 The fourth parameter
- *
- * @return the result from sprintf(format, new Object[]{ ... }).
- *
- * @throws IllegalArgumentException from {@link #sprintf(String, Object[])}.
- */
- public static String sprintf(String format, Object a0, Object a1,
- Object a2, Object a3) {
-
- return sprintf(format, new Object[]{a0, a1, a2, a3});
- }
-
- /**
- * Formats a string according to format and argument. This method only
- * supports string formats. See {@link #sprintf(String, Object[])} for details.
- *
- * @param format The format string
- * @param a0 The first parameter
- * @param a1 The second parameter
- * @param a2 The thrid parameter
- * @param a3 The fourth parameter
- * @param a4 The fifth parameter
- *
- * @return the result from sprintf(format, new Object[]{ ... }).
- *
- * @throws IllegalArgumentException from {@link #sprintf(String, Object[])}.
- */
- public static String sprintf(String format, Object a0, Object a1,
- Object a2, Object a3, Object a4) {
- return sprintf(format, new Object[]{a0, a1, a2, a3, a4});
- }
-
- //---------- internal ------------------------------------------------------
-
- /**
- * Convert a Date formatting string in POSIX strftime() format to the
- * pattern format used by the Java SimpleDateFormat class.
- *
- * These are the symbols used in SimpleDateFormat to which we convert
- * our strftime() symbols.
- *
- *
- *
Symbol
Meaning
Presentation
Example
- *
G
era designator
(Text)
AD
- *
y
year
(Number)
1996
- *
M
month in year
(Text & Number)
July & 07
- *
d
day in month
(Number)
10
- *
h
hour in am/pm (1~12)
(Number)
12
- *
H
hour in day (0~23)
(Number)
0
- *
m
minute in hour
(Number)
30
- *
s
second in minute
(Number)
55
- *
S
millisecond
(Number)
978
- *
E
day in week
(Text)
Tuesday
- *
D
day in year
(Number)
189
- *
F
day of week in month
(Number)
2 (2nd Wed in July)
- *
w
week in year
(Number)
27
- *
W
week in month
(Number)
2
- *
a
am/pm marker
(Text)
PM
- *
k
hour in day (1~24)
(Number)
24
- *
K
hour in am/pm (0~11)
(Number)
0
- *
z
time zone
(Text)
Pacific Standard Time
- *
'
escape for text
(Delimiter)
- *
''
single quote
(Literal)
'
- *
- *
- * @param posixFormat The formatting pattern in POSIX strftime() format.
- * @return The Date formatting pattern in SimpleDateFormat pattern format.
- *
- * todo: Check for the more or less complete support of all pattern tags.
- */
- private static String convertFormat(String posixFormat) {
- char[] format = posixFormat.toCharArray();
- StringBuffer jFormat = new StringBuffer(format.length);
- boolean inString = false;
-
- for (int i=0; isprintf() method, that is, this method handles d, i, o, u,
- * x, and X formatting characters.
- *
- * @param buf The formatted number is appended to this string buffer
- * @param num The number object to format
- * @param fmt The format character defining the radix of the number
- * @param width The minimum field width for the number
- * @param precision The minimum number of digits to print for the number,
- * this does not include any signs or prefix characters
- * @param flags The flags governing the formatting. This is a combination
- * of the FLAG_* constants above.
- *
- * @return The formatted string
- *
- * @see sprintf()
- */
- private static StringBuffer format(StringBuffer buf, Number num,
- char fmt, int width, int precision, BitSet flags) {
-
- String numStr;
- String prefStr = "";
- boolean toUpper = (fmt == 'X');
-
- // Check precision and make default
- if (precision >= 0) {
- flags.clear(FLAG_ZE);
- } else {
- precision = 1;
- }
-
- // Get the value and adjust size interpretation
- long val;
- long sizeMask;
- if (flags.get(FLAG_SHORT)) {
- val = num.shortValue();
- sizeMask = 0xffffL;
- } else if (flags.get(FLAG_LONG)) {
- val = num.longValue();
- sizeMask = 0xffffffffffffffffL;
- } else {
- val = num.intValue();
- sizeMask = 0xffffffffL;
- }
-
- // check formatting type
- if (fmt == 'x' || fmt == 'X') {
-
- numStr = Long.toHexString(val & sizeMask);
-
- if (toUpper) {
- numStr = numStr.toUpperCase();
- }
-
- if (flags.get(FLAG_AL)) {
- prefStr = toUpper ? "0X" : "0x";
- }
-
- } else if (fmt == 'o') {
-
- numStr = Long.toOctalString(val & sizeMask);
-
- if (flags.get(FLAG_AL) && val != 0 && precision <= numStr.length()) {
- precision = numStr.length() + 1;
- }
-
- } else {
-
- numStr = Long.toString(val);
-
- // move sign to prefix if negative, or set '+'
- if (val < 0) {
- prefStr = "-";
- numStr = numStr.substring(1);
- } else if (flags.get(FLAG_SI)) {
- prefStr = "+";
- }
-
-
- }
-
- // prefix 0 for precision
- if (precision > numStr.length()) {
- StringBuffer tmp = new StringBuffer(precision);
- for (precision -= numStr.length(); precision > 0; precision--) {
- tmp.append('0');
- }
- numStr = tmp.append(numStr).toString();
- }
-
- return format(buf, numStr, prefStr, width, flags);
- }
-
- /**
- * Implements the floating point number formatting part of the
- * sprintf() method, that is, this method handles f, e, E, g,
- * and G formatting characters.
- *
- * @param buf The formatted number is appended to this string buffer
- * @param num The numeric value to format
- * @param fmt The format character defining the floating point format
- * @param width The minimum field width for the number
- * @param precision Depending on fmt either the number of
- * digits after the decimal point or the number of significant
- * digits.
- * @param flags The flags governing the formatting. This is a combination
- * of the FLAG_* constants above.
- *
- * @return The formatted string
- *
- * @see sprintf()
- */
- private static StringBuffer format(StringBuffer buf, double num,
- char fmt, int width, int precision, BitSet flags) {
-
- BigDecimal val = new BigDecimal(num).abs();
-
- // the exponent character, will be defined if exponent is needed
- char expChar = 0;
-
- // the exponent value
- int exp;
- if (fmt != 'f') {
- exp = val.unscaledValue().toString().length() - val.scale() - 1;
- } else {
- exp = 0;
- }
-
- // force display of the decimal dot, if otherwise omitted
- boolean needDot = (precision == 0 && flags.get(FLAG_AL));
-
- // for fmt==g|G : treat trailing 0 and decimal dot specially
- boolean checkTrails = false;
-
- // get a sensible precision value
- if (precision < 0) {
- precision = 6;
- }
-
- switch (fmt) {
- case 'G': // fall through
- case 'g':
- // decrement precision, to simulate significance
- if (precision > 0) {
- precision--;
- }
-
- // we have to check trailing zeroes later
- checkTrails = true;
-
- // exponent does not stipulate exp notation, break here
- if (exp <= precision) {
- precision -= exp;
- break;
- }
-
- // fall through for exponent handling
-
- case 'E': // fall through
- case 'e':
- // place the dot after the first decimal place
- val = val.movePointLeft(exp);
-
- // define the exponent character
- expChar = (fmt == 'e' || fmt == 'g') ? 'e' : 'E';
-
- break;
- }
-
- // only rescale if the precision is positive, may be negative
- // for g|G
- if (precision >= 0) {
- val = val.setScale(precision, BigDecimal.ROUND_HALF_UP);
- }
-
- // convert the number to a string
- String numStr = val.toString();
-
- // for g|G : check trailing zeroes
- if (checkTrails) {
-
- if (flags.get(FLAG_AL)) {
-
- // need a dot, if not existing for alternative format
- needDot |= (numStr.indexOf('.') < 0);
-
- } else {
- // remove trailing dots and zeros
- int dot = numStr.indexOf('.');
- if (dot >= 0) {
- int i;
- for (i=numStr.length()-1; i>=dot && numStr.charAt(i)=='0';
- i--);
- // if stopped at dot, remove it
- if (i > dot) {
- i++;
- }
- numStr = numStr.substring(0, i);
- }
- }
- }
-
- // Get a buffer with the number up to now
- StringBuffer numBuf = new StringBuffer(numStr);
-
- // if we need a decimal dot, add it
- if (needDot) {
- numBuf.append('.');
- }
-
- // we have an exponent to add
- if (expChar != 0) {
- numBuf.append(expChar);
- numBuf.append(exp < 0 ? '-' : '+');
- if (exp < 10) {
- numBuf.append('0');
- }
- numBuf.append(exp);
- }
-
- // define the number's sign as the prefix for later formatting
- String prefStr;
- if (num < 0) {
- prefStr = "-";
- } else if (flags.get(FLAG_SI)) {
- prefStr = "+";
- } else {
- prefStr = "";
- }
-
- // now format it and up we go
- return format(buf, numBuf.toString(), prefStr, width, flags);
- }
-
- /**
- * Formats the String appending to the
- * StringBuffer at least the String and
- * justifying according to the flags.
- *
- * The flags will be interpreted as follows :
- * * if {@link #FLAG_LJ} is set, append blanks for left justification
- * * else if {@link #FLAG_ZE} is set, insert zeroes between prefStr and str
- * * else prepend blanks for right justification
- *
- * @param buf The StringBuffer to append the formatted result
- * to.
- * @param str The String to be appended with surrounding
- * blanks, zeroes and prefStr depending on the
- * flags. This is usually the real string to print
- * like "ape" or "4.5E99".
- * @param prefStr An optional prefix String to be appended
- * in front of the String. This is usually the prefix
- * string for numeric str values, for example
- * "-", "0x", or "+". The reason for this separation is that the
- * {@link #FLAG_ZE} flag will insert zeroes between the prefix and
- * the string itself to fill the field to the width.
- * @param width The minimal field width. If the field width is larger than
- * the sum of the lengths of str and
- * prefStr, blanks or zeroes will be prepended or
- * appended according to the flags value.
- * @param flags The flags indicating where blanks or zeroes will be filled.
- * See above for the interpretation of flags.
- *
- * @throws NullPointerException if any of buf,
- * str, prefStr or flags
- * is null.
- */
- private static StringBuffer format(StringBuffer buf, String str,
- String prefStr, int width, BitSet flags) {
-
- int numFill = width - prefStr.length() - str.length();
- int preZero = 0;
- int preBlank = 0;
- int postBlank = 0;
-
- if (flags.get(FLAG_LJ)) {
- postBlank = numFill;
- } else if (flags.get(FLAG_ZE)) {
- preZero = numFill;
- } else {
- preBlank = numFill;
- }
-
- for ( ; preBlank > 0; preBlank--) buf.append(' ');
- buf.append(prefStr);
- for ( ; preZero > 0; preZero--) buf.append('0');
- buf.append(str);
- for ( ; postBlank > 0; postBlank--) buf.append(' ');
-
- return buf;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/util/XmlUtil.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/util/XmlUtil.java
deleted file mode 100644
index 56dc01bbe0d..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/util/XmlUtil.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.util;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.DavConstants;
-import org.jdom.Element;
-
-/**
- * XmlUtil provides utility METHODS for building Xml representation.
- */
-public class XmlUtil implements DavConstants {
-
- private static Logger log = Logger.getLogger(XmlUtil.class);
-
- /**
- * Converts the given timeout (long value defining the number of milli-
- * second until timeout is reached) to its Xml representation as defined
- * by RTF 2518.
- *
- * @param timeout number of milli-seconds until timeout is reached.
- * @return 'timeout' JDOM element
- */
- public static Element timeoutToXml(long timeout) {
- // TODO: check if 'infinite' would be better to return for infinite timeout.
- String expString = "Second-"+ timeout/1000;
- Element exp = new Element(XML_TIMEOUT, NAMESPACE);
- exp.setText(expString);
- return exp;
- }
-
- /**
- * Returns the Xml representation of a boolean isDeep, where false
- * presents a depth value of '0', true a depth value of 'infinity'.
- *
- * @param isDeep
- * @return Xml representation
- */
- public static Element depthToXml(boolean isDeep) {
- return depthToXml(isDeep? "infinity" : "0");
- }
-
- /**
- * Returns the Xml representation of a depth String. Webdav defines the
- * following valid values for depths: 0, 1, infinity
- *
- * @param depth
- * @return 'deep' JDOM element
- */
- public static Element depthToXml(String depth) {
- Element dElem = new Element(XML_DEPTH, NAMESPACE);
- dElem.setText(depth);
- return dElem;
- }
-
- /**
- * Builds a 'href' Xml element from the given String
- *
- * @param href String representing the text of the 'href' Xml element
- * @return Xml representation of a 'href' according to RFC 2518.
- */
- public static Element hrefToXml(String href) {
- return new Element(XML_HREF, NAMESPACE).setText(href);
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/util/package.html b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/util/package.html
deleted file mode 100644
index 8b8b2f978eb..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/util/package.html
+++ /dev/null
@@ -1,3 +0,0 @@
-
-Utility classes used for Text handling and creation of common Xml elements.
-
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/DeltaVConstants.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/DeltaVConstants.java
deleted file mode 100644
index 89cb94a235c..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/DeltaVConstants.java
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.version;
-
-import org.apache.jackrabbit.webdav.property.DavPropertyName;
-import org.apache.jackrabbit.webdav.DavConstants;
-import org.jdom.Namespace;
-
-/**
- * DeltaVConstants defines the following headers and properties
- * required for any resource that is complient to
- * RFC 3253:
- */
-public interface DeltaVConstants {
-
- /**
- * The DAV: namespace.
- */
- public static final Namespace NAMESPACE = DavConstants.NAMESPACE;
-
- /**
- * For certain METHODS, if the request-URL identifies a version-controlled
- * resource, a label can be specified in a LabelInfo request header to cause the
- * method to be applied to the version selected by that label.
- * LabelInfo header MUST have no effect on a request whose request-URL does not
- * identify a version-controlled resource. In particular, it MUST have no
- * effect on a request whose request-URL identifies a version or a version
- * history.
- */
- public static final String HEADER_LABEL = "Label";
-
- /**
- * Location header as defined by
- * RFC 2616. In the versioning
- * context it is used to indicate the location of the new version created by a
- * successful checkin in the response.
- * From RFC 2616:
- * The Location response-header field is used to redirect the recipient to a
- * location other than the Request-URI for completion of the request or
- * identification of a new resource.
- * For 201 (Created) responses, the Location is that of the new resource
- * which was created by the request.
- */
- public static final String HEADER_LOCATION = "Location";
-
- /**
- * The "DAV:comment" property is used to track a brief comment about a resource that is
- * suitable for presentation to a user. The DAV:comment of a version can be
- * used to indicate why that version was created.
- */
- public static final DavPropertyName COMMENT = DavPropertyName.create("comment", NAMESPACE);
-
- /**
- * The "DAV:creator-displayname" property contains a description of the creator of
- * the resource that is suitable for presentation to a user. The
- * DAV:creator-displayname of a version can be used to indicate who created
- * that version.
- */
- public static final DavPropertyName CREATOR_DISPLAYNAME = DavPropertyName.create("creator-displayname", NAMESPACE);
-
- /**
- * Required protected live property for any resources being complient with
- * RFC 3253. Clients should classify a resource by examing the values of the
- * DAV:supported-method-set and DAV:supported-live-property-set
- * properties of that resource.
- * Property structure:
- *
- * <!ELEMENT supported-method-set (supported-method*)>
- * <!ELEMENT supported-method ANY>
- * <!ATTLIST supported-method name NMTOKEN #REQUIRED>
- * name value: a method name
- *
- *
- * @see #SUPPORTED_LIVE_PROPERTY_SET
- */
- public static final DavPropertyName SUPPORTED_METHOD_SET = DavPropertyName.create("supported-method-set", NAMESPACE);
-
- /**
- * Required protected live property for any resources being complient with
- * RFC 3253. Clients should classify a resource by examing the values of the
- * DAV:supported-method-set and DAV:supported-live-property-set
- * properties of that resource.
- * Property structure:
- *
- * <!ELEMENT supported-live-property-set (supported-live-property*)>
- * <!ELEMENT supported-live-property name>
- * <!ELEMENT prop ANY>
- * ANY value: a property element type
- *
- *
- * @see #SUPPORTED_METHOD_SET
- */
- public static final DavPropertyName SUPPORTED_LIVE_PROPERTY_SET = DavPropertyName.create("supported-live-property-set", NAMESPACE);
-
- /**
- * Protected "supported-report-set" property identifies the reports that are
- * supported by the resource.
- *
- * @see #SUPPORTED_REPORT_SET
- */
- public static final DavPropertyName SUPPORTED_REPORT_SET = DavPropertyName.create("supported-report-set", NAMESPACE);
-
- /**
- * Protected "workspace" property indicating the workspace of a resource.
- *
- * @see #WORKSPACE
- */
- public static final DavPropertyName WORKSPACE = DavPropertyName.create("workspace", NAMESPACE);
-
-
- //--------------------------------------------------------------------------
- /**
- * Xml elements
- */
- public static final String XML_ACTIVITY = "activity";
- public static final String XML_BASELINE = "baseline";
-
- public static final String XML_SUPPORTED_METHOD = "supported-method";
- public static final String XML_VERSION_HISTORY = "version-history";
- public static final String XML_VERSION = "version";
- public static final String XML_WORKSPACE = "workspace";
-
- // options
- /**
- * If the OPTIONS request contains a body, i must start with an DAV:options
- * element.
- *
- * @see OptionsInfo
- * @see #XML_VH_COLLECTION_SET
- * @see #XML_WSP_COLLECTION_SET
- * @see #XML_ACTIVITY_COLLECTION_SET
- */
- public static final String XML_OPTIONS = "options";
-
- /**
- * If an XML response body for a successful request is included, it must be
- * a DAV:options-response XML element.
- *
- * @see OptionsResponse
- */
- public static final String XML_OPTIONS_RESPONSE = "options-response";
-
- /**
- * A DAV:version-history-collection-set element may be included in the OPTIONS
- * request body to identify collections that may contain version history
- * resources.
- * The response body for a successful request must in consequence contain a
- * DAV:version-history-collection-set element identifying collections that
- * may contain version histories. An identified collection may be the root
- * collection of a tree of collections, all of which may contain version
- * histories.
- *
- *
- */
- public static final String XML_VH_COLLECTION_SET = "version-history-collection-set";
-
- /**
- * A DAV:workspace-collection-set element may be included in the OPTIONS request
- * body to identify collections that may contain workspace resources.
- * The response body for a successful request must contain a
- * DAV:workspace-collection-set element identifying collections that may
- * contain workspaces. An identified collection may be the root collection
- * of a tree of collections, all of which may contain workspaces.
- *
- *
- */
- public static final String XML_WSP_COLLECTION_SET = "workspace-collection-set";
-
- /**
- * A DAV:workspace-collection-set element may be included in the OPTIONS request
- * body to identify collections that may contain activity resources.
- * The response body for a successful request must contain a
- * DAV:workspace-collection-set element identifying collections that may
- * contain activity resources. An identified collection may be the root collection
- * of a tree of collections, all of which may contain activity resources.
- *
- *
- */
- public static final String XML_ACTIVITY_COLLECTION_SET = "activity-collection-set";
-
- /**
- * Name of Xml element contained in the {@link #SUPPORTED_REPORT_SET} property.
- *
- * @see #SUPPORTED_REPORT_SET
- * @see org.apache.jackrabbit.webdav.version.report.SupportedReportSetProperty
- */
- public static final String XML_SUPPORTED_REPORT = "supported-report";
-
- /**
- * Name of Xml child elements of {@link #XML_SUPPORTED_REPORT}.
- *
- * @see org.apache.jackrabbit.webdav.version.report.SupportedReportSetProperty
- */
- public static final String XML_REPORT = "report";
-
- /**
- * Top element for the 'DAV:version-tree' report
- */
- public static final String XML_VERSION_TREE = "version-tree";
-
- /**
- * Top element for the 'DAV:expand-property' report
- */
- public static final String XML_EXPAND_PROPERTY = "expand-property";
-
- /**
- * 'DAV:property' element to be used inside the 'DAV:expand-property' element.
- *
- * @see #XML_EXPAND_PROPERTY
- */
- public static final String XML_PROPERTY = "property";
-
- /**
- * 'DAV:name' attribute for the property element
- *
- * @see #XML_PROPERTY
- */
- public static final String ATTR_NAME = "name";
-
- /**
- * 'DAV:namespace' attribute for the property element
- *
- * @see #XML_PROPERTY
- */
- public static final String ATTR_NAMESPACE = "namespace";
-
- /**
- * Top element for the 'DAV:locate-by-history' report
- */
- public static final String XML_LOCATE_BY_HISTORY = "locate-by-history";
-
- /**
- * 'DAV:version-history-set' to be used inside the 'DAV:locate-by-history'
- * element
- *
- * @see #XML_LOCATE_BY_HISTORY
- */
- public static final String XML_VERSION_HISTORY_SET = "version-history-set";
-
-
- /**
- * Xml element representing the mandatory root element of a LABEL request
- * body.
- *
- * @see #XML_LABEL_NAME
- * @see #XML_LABEL_ADD
- * @see #XML_LABEL_REMOVE
- * @see #XML_LABEL_SET
- * @see LabelInfo
- */
- public static final String XML_LABEL = "label";
- public static final String XML_LABEL_NAME = "label-name";
- public static final String XML_LABEL_ADD = "add";
- public static final String XML_LABEL_REMOVE = "remove";
- public static final String XML_LABEL_SET = "set";
-
- /**
- * Xml element defining the top element in the UPDATE request body. RFC 3253
- * defines the following structure for the 'update' element.
- *
- * <!ELEMENT update ANY>
- * ANY value: A sequence of elements with at most one DAV:version element
- * and at most one DAV:prop element.
- * <!ELEMENT version (href)>
- * prop: see RFC 2518, Section 12.11
- *
- */
- public static final String XML_UPDATE = "update";
-
- // auto-version
- public static final String XML_CHECKOUT_CHECKIN = "checkin-checkout";
- public static final String XML_CHECKOUT_UNLOCK_CHECKIN = "checkout-unlocked-checkin";
- public static final String XML_CHECKOUT = "checkout";
- public static final String XML_LOCKED_CHECKIN = "locked-checkout";
-
- // merge
- public static final String XML_MERGE = "merge";
- public static final String XML_N0_AUTO_MERGE = "no-auto-merge";
- public static final String XML_N0_CHECKOUT = "no-checkout";
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/DeltaVServletRequest.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/DeltaVServletRequest.java
deleted file mode 100644
index 8a9f9f6ae4d..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/DeltaVServletRequest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.version;
-
-import org.apache.jackrabbit.webdav.DavServletRequest;
-import org.apache.jackrabbit.webdav.version.report.ReportInfo;
-
-/**
- * DeltaVServletRequest provides extension useful for functionality
- * related to RFC 3253.
- */
-public interface DeltaVServletRequest extends DavServletRequest {
-
- /**
- * Returns the Label header or null
- *
- * @return label header or null
- * @see DeltaVConstants#HEADER_LABEL
- */
- public String getLabel();
-
- /**
- * Return the request body as LabelInfo object or null
- * if parsing the request body or the creation of the label info failed.
- *
- * @return LabelInfo object or null
- */
- public LabelInfo getLabelInfo();
-
- /**
- * Return the request body as MergeInfo object or null
- * if the creation failed due to invalid format.
- *
- * @return MergeInfo object or null
- */
- public MergeInfo getMergeInfo();
-
- /**
- * Parses the UPDATE request body a build the corresponding UpdateInfo
- * object. If the request body is missing or does not of the required format
- * null is returned.
- *
- * @return the parsed update request body or null
- */
- public UpdateInfo getUpdateInfo();
-
- /**
- * Returns the request body and the Depth header as ReportInfo
- * object. The default depth, if no {@link org.apache.jackrabbit.webdav.DavConstants#HEADER_DEPTH
- * Depth header}, is {@link org.apache.jackrabbit.webdav.DavConstants#DEPTH_0}.
- * If the requuest body could not be parsed into an {@link org.jdom.Element}
- * null is returned.
- *
- * @return ReportInfo or null
- */
- public ReportInfo getReportInfo();
-
- /**
- * Returns the {@link OptionsInfo} present with the request or null.
- *
- * @return {@link OptionsInfo} or null
- */
- public OptionsInfo getOptionsInfo();
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/LabelInfo.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/LabelInfo.java
deleted file mode 100644
index 8a1f6ca6974..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/LabelInfo.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.version;
-
-import org.apache.log4j.Logger;
-import org.jdom.Element;
-
-import java.util.Iterator;
-
-/**
- * LabelInfo encapsulates the request body of a LABEL request
- * used to add, set or remove a label from the requested version resource or
- * from that version specified with the Label header in case the requested resource
- * is a version-controlled resource.
- * The request body (thus the 'labelElement' passed to the constructore must be
- * a DAV:label element:
- *
- * <!ELEMENT label ANY>
- * ANY value: A sequence of elements with at most one DAV:add,
- * DAV:set, or DAV:remove element.
- * <!ELEMENT add (label-name)>
- * <!ELEMENT set (label-name)>
- * <!ELEMENT remove (label-name)>
- * <!ELEMENT label-name (#PCDATA)>
- * PCDATA value: string
- *
- */
-public class LabelInfo implements DeltaVConstants {
-
- private static Logger log = Logger.getLogger(LabelInfo.class);
-
- public static final int TYPE_SET = 0;
- public static final int TYPE_REMOVE = 1;
- public static final int TYPE_ADD = 2;
-
- private final Element labelElement;
- private final int depth;
-
- private int type;
- private String labelName;
-
- /**
- * Create a new LabelInfo from the given element and depth
- * integer. If the specified Xml element does have a {@link DeltaVConstants#XML_LABEL}
- * root element or no label name is specified with the action to perform
- * the creation will fail.
- *
- * @param labelElement
- * @param depth
- * @throws IllegalArgumentException if the specified element does not
- * start with a {@link DeltaVConstants#XML_LABEL} element or if the DAV:label
- * element contains illegal instructions e.g. contains multiple DAV:add, DAV:set
- * or DAV:remove elements.
- */
- public LabelInfo(Element labelElement, int depth) {
- if (labelElement == null || !labelElement.getName().equals(DeltaVConstants.XML_LABEL)) {
- throw new IllegalArgumentException("label element expected");
- }
-
- this.labelElement = (Element) labelElement.detach();
-
- Iterator childrenIter = labelElement.getChildren().iterator();
- while (childrenIter.hasNext()) {
- Element child = (Element) childrenIter.next();
- if (!NAMESPACE.equals(child.getNamespace())) {
- continue;
- }
- String name = child.getName();
- if (XML_LABEL_ADD.equals(name)) {
- type = TYPE_ADD;
- setLabelName(child);
- } else if (XML_LABEL_REMOVE.equals(name)) {
- type = TYPE_REMOVE;
- setLabelName(child);
- } else if (XML_LABEL_SET.equals(name)) {
- type = TYPE_SET;
- setLabelName(child);
- }
- }
- this.depth = depth;
- }
-
- /**
- * Create a new LabelInfo from the given element. As depth
- * the default value 0 is assumed.
- *
- * @param labelElement
- * @throws IllegalArgumentException
- * @see #LabelInfo(org.jdom.Element, int)
- */
- public LabelInfo(Element labelElement) {
- this(labelElement, 0);
- }
-
- /**
- * Return the 'label-name' or null
- *
- * @return 'label-name' or null
- */
- public String getLabelName() {
- return labelName;
- }
-
- /**
- * Retrieve the text of the 'label-name' child element of the specified
- * parent element.
- *
- * @param parent the is intended to contain a valid 'label-name' child.
- * @throws IllegalArgumentException if the labelName has been set before.
- */
- private void setLabelName(Element parent) {
- // test if any label name is present
- if (labelName != null) {
- throw new IllegalArgumentException("The DAV:label element may contain at most one DAV:add, DAV:set, or DAV:remove element");
- }
- labelName = parent.getChildText(XML_LABEL_NAME, NAMESPACE);
- }
-
- /**
- * Return the type of the LABEL request. This might either be {@link #TYPE_SET},
- * {@link #TYPE_ADD} or {@link #TYPE_REMOVE}.
- *
- * @return type
- */
- public int getType() {
- return type;
- }
-
- /**
- * Return the depth
- *
- * @return depth
- */
- public int getDepth() {
- return depth;
- }
-
- /**
- * Return the DAV:label element
- *
- * @return the DAV:label element
- */
- public Element getLabelElement() {
- return labelElement;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/MergeInfo.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/MergeInfo.java
deleted file mode 100644
index e9cb7b78f1e..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/MergeInfo.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.version;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.DavConstants;
-import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
-import org.jdom.Element;
-
-/**
- * MergeInfo encapsulates the information present in the DAV:merge
- * element, that forms the mandatory request body of a MERGE request.
- * The DAV:merge element is specified to have the following form.
- *
- * <!ELEMENT merge ANY>
- * ANY value: A sequence of elements with one DAV:source element, at most one
- * DAV:no-auto-merge element, at most one DAV:no-checkout element, at most one
- * DAV:prop element, and any legal set of elements that can occur in a DAV:checkout
- * element.
- * <!ELEMENT source (href+)>
- * <!ELEMENT no-auto-merge EMPTY>
- * <!ELEMENT no-checkout EMPTY>
- * prop: see RFC 2518, Section 12.11
- *
- */
-public class MergeInfo implements DeltaVConstants {
-
- private static Logger log = Logger.getLogger(MergeInfo.class);
-
- private Element mergeElement;
-
- /**
- * Create a new MergeInfo
- *
- * @param mergeElement
- * @throws IllegalArgumentException if the mergeElement is null
- * or not a DAV:merge element.
- */
- public MergeInfo(Element mergeElement) {
- if (mergeElement == null || !mergeElement.getName().equals(XML_MERGE)) {
- throw new IllegalArgumentException("'DAV:merge' element expected");
- }
- this.mergeElement = (Element) mergeElement.detach();
- }
-
- /**
- * Returns the URL specified with the DAV:source element or null
- * if no such child element is present in the DAV:merge element.
- *
- * @return href present in the DAV:source child element or null.
- */
- public String getSourceHref() {
- Element source = mergeElement.getChild(DavConstants.XML_SOURCE, DavConstants.NAMESPACE);
- if (source != null) {
- return source.getChildText(DavConstants.XML_HREF, DavConstants.NAMESPACE);
- }
- return null;
- }
-
- /**
- * Returns true if the DAV:merge element contains a DAV:no-auto-merge child element.
- *
- * @return true if the DAV:merge element contains a DAV:no-auto-merge child.
- */
- public boolean isNoAutoMerge() {
- return mergeElement.getChild(XML_N0_AUTO_MERGE, NAMESPACE) != null;
- }
-
- /**
- * Returns true if the DAV:merge element contains a DAV:no-checkout child element.
- *
- * @return true if the DAV:merge element contains a DAV:no-checkout child
- */
- public boolean isNoCheckout() {
- return mergeElement.getChild(XML_N0_CHECKOUT, NAMESPACE) != null;
- }
-
- /**
- * Returns a {@link DavPropertyNameSet}. If the DAV:merge element contains
- * a DAV:prop child element the properties specified therein are included
- * in the set. Otherwise an empty set is returned.
- *
- * @return set listing the properties specified in the DAV:prop element indicating
- * those properties that must be reported in the response body.
- */
- public DavPropertyNameSet getPropertyNameSet() {
- Element propElement = mergeElement.getChild(DavConstants.XML_PROP, DavConstants.NAMESPACE);
- if (propElement != null) {
- return new DavPropertyNameSet(propElement);
- } else {
- return new DavPropertyNameSet();
- }
- }
-
- /**
- * Returns the DAV:merge element used to create this MergeInfo
- * object.
- *
- * @return DAV:merge element
- */
- public Element getMergeElement() {
- return mergeElement;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/OptionsInfo.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/OptionsInfo.java
deleted file mode 100644
index ca2c90d68a9..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/OptionsInfo.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.version;
-
-import org.apache.log4j.Logger;
-import org.jdom.Element;
-import org.jdom.Namespace;
-
-import java.util.List;
-
-/**
- * OptionsInfo represents the Xml request body, that may be present
- * with a OPTIONS request.
- *
- * The DAV:options element is specified to have the following form.
- *
- *
- * <!ELEMENT options ANY>
- * ANY value: A sequence of elements each at most onces.
- *
- *
- * @see DeltaVConstants#XML_VH_COLLECTION_SET
- * @see DeltaVConstants#XML_WSP_COLLECTION_SET
- * @see DeltaVConstants#XML_ACTIVITY_COLLECTION_SET
- */
-public class OptionsInfo {
-
- private static Logger log = Logger.getLogger(OptionsInfo.class);
-
- private final Element optionsElement;
-
- /**
- * Create a new UpdateInfo object.
- *
- * @param optionsElement
- * @throws IllegalArgumentException if the updateElement is null
- * or not a DAV:update element or if the element does not match the required
- * structure.
- */
- public OptionsInfo(Element optionsElement) {
- if (optionsElement == null || !optionsElement.getName().equals(DeltaVConstants.XML_OPTIONS)) {
- throw new IllegalArgumentException("DAV:options element expected");
- }
- this.optionsElement = (Element) optionsElement.detach();
- }
-
- /**
- * Returns the set of elements present in the {@link DeltaVConstants#XML_OPTIONS DAV:options}
- * element. These elements define the information the client wishes to retrieve
- * the OPTIONS request.
- *
- * @return set of child elements
- */
- public List getElements() {
- return optionsElement.getChildren();
- }
-
- /**
- * Returns true if a child element with the given name and namespace is present.
- *
- * @param name
- * @param namespace
- * @return true if such a child element exists in the options element.
- */
- public boolean containsElement(String name, Namespace namespace) {
- return optionsElement.getChild(name, namespace) != null;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/OptionsResponse.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/OptionsResponse.java
deleted file mode 100644
index 1c49fc3549e..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/OptionsResponse.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.version;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.util.XmlUtil;
-import org.jdom.Document;
-import org.jdom.Element;
-import org.jdom.Namespace;
-
-/**
- * OptionsResponse encapsulates the DAV:options-response element
- * present in the response body of a successful OPTIONS request (with body).
- *
- * The DAV:options-response element is defined to have the following format.
- *
- *
- * <!ELEMENT options-response ANY>
- * ANY value: A sequence of elements
- *
- */
-public class OptionsResponse implements DeltaVConstants {
-
- private static Logger log = Logger.getLogger(OptionsResponse.class);
-
- private final Element optionsResponse = new Element(XML_OPTIONS_RESPONSE, NAMESPACE);
-
- /**
- * Add a new entry to this OptionsResponse
- *
- * @param elem
- */
- public void addEntry(Element elem) {
- optionsResponse.addContent(elem.detach());
- }
-
- /**
- * Add a new entry to this OptionsResponse and make each
- * href present in the String array being a separate {@link org.apache.jackrabbit.webdav.DavConstants#XML_HREF DAV:href}
- * element within the entry.
- *
- * @param name
- * @param namespace
- * @param hrefs
- */
- public void addEntry(String name, Namespace namespace, String[] hrefs) {
- Element elem = new Element(name, namespace);
- for (int i = 0; i < hrefs.length; i++) {
- elem.addContent(XmlUtil.hrefToXml(hrefs[i]));
- }
- optionsResponse.addContent(elem);
- }
-
- /**
- * Return the Xml representation.
- *
- * @return Xml representation.
- */
- public Document toXml() {
- return new Document(optionsResponse);
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/ResourceType.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/ResourceType.java
deleted file mode 100644
index 36d1aae4eb6..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/ResourceType.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.version;
-
-import org.apache.log4j.Logger;
-import org.jdom.Element;
-
-/**
- * The ResourceType extends the {@link org.apache.jackrabbit.webdav.property.ResourceType}
- * by DeltaV specific types.
- */
-public class ResourceType extends org.apache.jackrabbit.webdav.property.ResourceType
- implements DeltaVConstants {
-
- private static Logger log = Logger.getLogger(ResourceType.class);
-
- /**
- * The version-history resource type
- */
- public static final int VERSION_HISTORY = COLLECTION + 1;
-
- /**
- * The activity resource type
- */
- public static final int ACTIVITY = VERSION_HISTORY + 1;
-
- /**
- * The baseline resource type
- */
- public static final int BASELINE = ACTIVITY + 1;
-
- /**
- * Array containing all possible resourcetype elements
- */
- private static final String[] ELEMENT_NAMES = {
- null,
- XML_COLLECTION,
- XML_VERSION_HISTORY,
- XML_ACTIVITY,
- XML_BASELINE
- };
-
-
- /**
- * Create a resource type property
- *
- * @param resourceType
- */
- public ResourceType(int resourceType) {
- super(resourceType);
- }
-
- /**
- * Return the resource type as Xml element.
- *
- * @return Xml element representing the internal type or null
- * if the resource has no element name assigned (default resource type).
- */
- public Object getValue() {
- String name = ELEMENT_NAMES[getResourceType()];
- return (name != null) ? new Element(name, DeltaVConstants.NAMESPACE) : null;
- }
-
- /**
- * Returns true if the given integer defines a valid resource type.
- *
- * @param resourceType to be validated.
- * @return true if this is a known resource type.
- */
- public boolean isValidResourceType(int resourceType) {
- if (resourceType < DEFAULT_RESOURCE || resourceType > BASELINE) {
- return false;
- }
- return true;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/SupportedMethodSetProperty.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/SupportedMethodSetProperty.java
deleted file mode 100644
index 3a0dd817ff9..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/SupportedMethodSetProperty.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.version;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.property.DefaultDavProperty;
-import org.jdom.Element;
-
-/**
- * The SupportedMethodSetProperty
- */
-public class SupportedMethodSetProperty extends DefaultDavProperty implements DeltaVConstants {
-
- private static Logger log = Logger.getLogger(SupportedMethodSetProperty.class);
-
- /**
- * Create a new SupportedMethodSetProperty property.
- *
- * @param methods that are supported by the resource having this property.
- */
- public SupportedMethodSetProperty(String[] methods) {
- super(DeltaVConstants.SUPPORTED_METHOD_SET, new Element[methods.length], true);
-
- // fill the array with the proper elements
- Element[] value = (Element[]) getValue();
- for (int i = 0; i < methods.length; i++) {
- Element methodElem = new Element(DeltaVConstants.XML_SUPPORTED_METHOD, DeltaVConstants.NAMESPACE);
- methodElem.setAttribute("name",methods[i], DeltaVConstants.NAMESPACE);
- value[i] = methodElem;
- }
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/UpdateInfo.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/UpdateInfo.java
deleted file mode 100644
index a75e4f256f2..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/UpdateInfo.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.version;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
-import org.apache.jackrabbit.webdav.DavConstants;
-import org.jdom.Element;
-
-import java.util.List;
-import java.util.Iterator;
-
-/**
- * UpdateInfo encapsulates the request body of an UPDATE request.
- * RFC 3253 defines the request body as follows:
- *
- * <!ELEMENT update ANY>
- * ANY value: A sequence of elements with at most one DAV:version element and at
- * most one DAV:prop element.
- * <!ELEMENT version (href)>
- * prop: see RFC 2518, Section 12.11
- *
- *
- * In order to reflect the complete range of version restoring and updating
- * of nodes defined by JSR170 the definition has been extended:
- *
- */
-public class UpdateInfo implements DeltaVConstants {
-
- private static Logger log = Logger.getLogger(UpdateInfo.class);
-
- private final Element updateElement;
- private String[] versionHref;
- private String[] labelName;
- private String workspaceHref;
-
- /**
- * Create a new UpdateInfo object.
- *
- * @param updateElement
- * @throws IllegalArgumentException if the updateElement is null
- * or not a DAV:update element or if the element does not match the required
- * structure.
- */
- public UpdateInfo(Element updateElement) {
- if (updateElement == null || !updateElement.getName().equals(DeltaVConstants.XML_UPDATE)) {
- throw new IllegalArgumentException("DAV:update element expected");
- }
-
- List targetList;
- if (!(targetList = updateElement.getChildren(XML_VERSION, NAMESPACE)).isEmpty()) {
- Iterator it = targetList.iterator();
- versionHref = new String[targetList.size()];
- int i = 0;
- while (it.hasNext()) {
- Element versionElem = (Element) it.next();
- versionHref[i] = versionElem.getChildText(DavConstants.XML_HREF, NAMESPACE);
- i++;
- }
- } else if (!(targetList = updateElement.getChildren(XML_LABEL_NAME, NAMESPACE)).isEmpty()) {
- Iterator it = targetList.iterator();
- labelName = new String[targetList.size()];
- int i = 0;
- while (it.hasNext()) {
- Element labelNameElem = (Element) it.next();
- labelName[i] = labelNameElem.getText();
- i++;
- }
- } else if (updateElement.getChild(XML_WORKSPACE, NAMESPACE) != null) {
- workspaceHref = updateElement.getChild(XML_WORKSPACE, NAMESPACE).getChildText(DavConstants.XML_HREF, NAMESPACE);
- } else {
- throw new IllegalArgumentException("DAV:update element must contain either DAV:version, DAV:label-name or DAV:workspace child element.");
- }
-
- this.updateElement = (Element) updateElement.detach();
- }
-
- /**
- *
- * @return
- */
- public String[] getVersionHref() {
- return versionHref;
- }
-
- /**
- *
- * @return
- */
- public String[] getLabelName() {
- return labelName;
- }
-
- /**
- *
- * @return
- */
- public String getWorkspaceHref() {
- return workspaceHref;
- }
-
- /**
- * Returns a {@link DavPropertyNameSet}. If the DAV:update element contains
- * a DAV:prop child element the properties specified therein are included
- * in the set. Otherwise an empty set is returned.
- *
- * @return set listing the properties specified in the DAV:prop element indicating
- * those properties that must be reported in the response body.
- */
- public DavPropertyNameSet getPropertyNameSet() {
- Element propElement = updateElement.getChild(DavConstants.XML_PROP, DavConstants.NAMESPACE);
- if (propElement != null) {
- return new DavPropertyNameSet(propElement);
- } else {
- return new DavPropertyNameSet();
- }
- }
-
- /**
- *
- * @return
- */
- public Element getUpdateElement() {
- return updateElement;
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/VersionControlledResource.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/VersionControlledResource.java
deleted file mode 100644
index 0cc5e926f2d..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/VersionControlledResource.java
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.version;
-
-import org.apache.jackrabbit.webdav.DavException;
-import org.apache.jackrabbit.webdav.MultiStatus;
-import org.apache.jackrabbit.webdav.property.DavPropertyName;
-import org.apache.jackrabbit.webdav.property.DavPropertySet;
-import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
-
-/**
- * The VersionControlledResource represents in contrast to the
- * VersionableResource a resource, that has already been put
- * under version-control. This resource can be checked-in, checked-out and
- * has its on {@link javax.jcr.version.VersionHistory version history}.
- *
- * RFC 3253 defines the following required properties for a
- * version-controlled resource (vc-resource):
- *
- *
DAV:auto-version
- *
DAV:version-history (version-history)
- *
DAV:workspace (workspace)
- *
DAV:version-controlled-configuration (baseline)
- *
all DeltaV-compliant resource properties.
- *
- *
- * checked-in vc-resource:
- *
- *
DAV:checked-in
- *
- *
- * checked-out vc-resource:
- *
- *
DAV:checked-out
- *
DAV:predecessor-set
- *
DAV:checkout-fork (in-place-checkout or working resource)
- *
DAV:checkin-fork (in-place-checkout or working resource)
- *
DAV:merge-set (merge)
- *
DAV:auto-merge-set (merge)
- *
DAV:unreserved (activity)
- *
DAV:activity-set (activity)
- *
- *
- * In addition a version-controlled resource must support the following METHODS:
- *
- *
VERSION-CONTROL
- *
MERGE (merge)
- *
all DeltaV-compliant resource METHODS.
- *
- *
- * checked-in vc-resource:
- *
- *
CHECKOUT (checkout-in-place)
- *
UPDATE (update)
- *
all version-controlled resource METHODS.
- *
- *
- * checked-out vc-resource:
- *
- *
CHECKIN (checkout-in-place or working-resource)
- *
UNCHECKOUT (checkout-in-place)
- *
all DeltaV-compliant resource METHODS.
- *
- *
- * @see DeltaVResource
- * @see VersionableResource
- */
-public interface VersionControlledResource extends VersionableResource {
-
- /**
- * Methods defined for a checked-in version-controlled resource: CHECKOUT, UNCHECHKOUT, UPDATE, MERGE, LABEL
- */
- public String methods_checkedIn = "CHECKOUT, UNCHECHKOUT, UPDATE, MERGE, LABEL";
- /**
- * Methods defined for a checked-out version-controlled resource: CHECKIN, MERGE
- */
- public String methods_checkedOut = "CHECKIN, MERGE";
-
- /**
- * The DAV:auto-version property determines how it responds to a method that
- * attempts to modify its content or dead properties. Possible responses
- * include various combinations of automated checkout, write lock and checkin
- * as well as failure until the resource is explicitely checked-out.
- * See RFC 3253 for a detailed
- * description.
- */
- public static final DavPropertyName AUTO_VERSION = DavPropertyName.create("auto-version", DeltaVConstants.NAMESPACE);
-
- /**
- * The computed property DAV:version-history identifies the version history
- * resource for the DAV:checked-in or DAV:checked-out version of this
- * version-controlled resource.
- * The property is defined to have the following format:
- *
- * <!ELEMENT version-history (href)>
- *
- */
- public static final DavPropertyName VERSION_HISTORY = DavPropertyName.create("version-history", DeltaVConstants.NAMESPACE);
-
- /**
- * The DAV:checked-in property appears on a checked-in version-controlled
- * resource, and identifies the base version of this version-controlled
- * resource. This property is removed when the resource is checked out, and
- * then added back (identifying a new version) when the resource is checked
- * back in.
- * This property is defined to have the following format:
- *
- * <!ELEMENT checked-in (href)>
- *
- */
- public static final DavPropertyName CHECKED_IN = DavPropertyName.create("checked-in", DeltaVConstants.NAMESPACE);
-
- /**
- * The DAV:checked-out property identifies the base version of this resource.
- * It is the same that was identified by the DAV:checked-in property at the
- * time the resource was checked out. This property is removed when the
- * resource is checked in.
- * This property is defined to have the following format:
- *
- * <!ELEMENT checked-out (href)>
- *
- *
- * @see #CHECKED_IN
- */
- public static final DavPropertyName CHECKED_OUT = DavPropertyName.create("checked-out", DeltaVConstants.NAMESPACE);
-
- /**
- * The DAV:predecessor-set property of a version-controlled resource points
- * to those version resources, that are scheduled to become the predecessors
- * of this resource when it is back checked-in. This property is not
- * protected, however a server may reject attempts to modify the
- * DAV:predecessor-set of a version-controlled resource.
- * This property is defined to have the following format:
- *
- * <!ELEMENT predecessor-set (href+)>
- *
- *
- * @see #checkin()
- * @see VersionResource#PREDECESSOR_SET
- */
- public static final DavPropertyName PREDECESSOR_SET = DavPropertyName.create("predecessor-set", DeltaVConstants.NAMESPACE);
-
- /**
- * This property determines the DAV:checkin-fork property of the version
- * that results from checking in this resource.
- */
- public static final DavPropertyName CHECKIN_FORK = DavPropertyName.create("checkin-fork", DeltaVConstants.NAMESPACE);
-
- /**
- * This property determines the DAV:checkout-fork property of the version
- * that results from checking in this resource.
- */
- public static final DavPropertyName CHECKOUT_FORK = DavPropertyName.create("checkout-fork", DeltaVConstants.NAMESPACE);
-
- /**
- * This property identifies each version that is to be merged into this
- * checked-out resource. This property is set, whenever a MERGE request
- * with the DAV:no-auto-merge flag succeeded. The client then must confirm
- * each single merge by removing the version from the DAV:merge-set or
- * moving it the the versions DAV:predecessor-set.
- * This property is defined to have the following format:
- *
- * <!ELEMENT merge-set (href*)>
- *
- *
- * @see #merge(MergeInfo)
- * @see #resolveMergeConflict(DavPropertySet, DavPropertyNameSet)
- */
- public static final DavPropertyName MERGE_SET = DavPropertyName.create("merge-set", DeltaVConstants.NAMESPACE);
-
- /**
- * The DAV:auto-merge-set property identifies each version that the server
- * has merged into this checked-out resource. The client should confirm that
- * the merge has been performed correctly before moving a URL from the
- * DAV:auto-merge-set to the DAV:predecessor-set of a checked-out resource.
- * This property is defined to have the following format:
- *
- * <!ELEMENT auto-merge-set (href*)>
- *
- *
- * @see #merge(MergeInfo)
- * @see #resolveMergeConflict(DavPropertySet, DavPropertyNameSet)
- */
- public static final DavPropertyName AUTO_MERGE_SET = DavPropertyName.create("auto-merge-set", DeltaVConstants.NAMESPACE);
-
- /**
- * Perform a checkin on the version controlled resource.
- *
- * @return String representing the location of the version created by the
- * checkin.
- * @throws DavException if an error occurs.
- */
- public String checkin() throws DavException;
-
- /**
- * Perform a checkout on the version controlled resource.
- *
- * @throws DavException
- */
- public void checkout() throws DavException;
-
- /**
- * Perform an uncheckout on the version controlled resource.
- *
- * @throws DavException
- */
- public void uncheckout() throws DavException;
-
- /**
- * Perform an update on this resource using the specified {@link UpdateInfo}.
- *
- * @param updateInfo
- * @return MultiStatus containing the list of resources that
- * have been modified by this update call.
- * @throws DavException
- */
- public MultiStatus update(UpdateInfo updateInfo) throws DavException;
-
- /**
- * Perform a merge on this resource using the specified {@link MergeInfo}.
- *
- * @param mergeInfo
- * @return MultiStatus containing the list of resources that
- * have been modified.
- * @throws DavException
- */
- public MultiStatus merge(MergeInfo mergeInfo) throws DavException;
-
- /**
- * Resolve one or multiple merge conflicts present on this resource. Please
- * note that the 'setProperties' or 'removeProperties' set my contain additional
- * resource properties, that need to be changed. Those properties are left
- * untouched, whereas the {@link #AUTO_MERGE_SET}, {@link #MERGE_SET} and
- * the {@link #PREDECESSOR_SET} are removed from the list upon successful
- * resolution of a merge conflict.
- * If the removeProperties or setProperties set do not contain any of the
- * mentioned resource properties or if the value of those properties do
- * not allow for a resolution of an existing merge conflict, this METHODS
- * returns silently.
- *
- * @param setProperties
- * @param removePropertyNames
- * @throws DavException the set or remove property sets attempt to resolve
- * a non-existing merge conflict of if another error occurs while resolving
- * an existing conflict.
- */
- public void resolveMergeConflict(DavPropertySet setProperties, DavPropertyNameSet removePropertyNames) throws DavException;
-
- /**
- * Modify the labels of the version referenced by the DAV:checked-in property
- * of this checked-in version-controlled resource. If the resource is not
- * checked-in the request must fail.
- *
- * @param labelInfo
- * @throws org.apache.jackrabbit.webdav.DavException
- * @see LabelInfo
- * @see VersionResource#label(LabelInfo) for the pre- and postcondition of
- * a successful LABEL request.
- */
- public void label(LabelInfo labelInfo) throws DavException;
-
- /**
- * Returns the VersionHistoryResource, that is referenced in the
- * '{@link #VERSION_HISTORY version-history}' property.
- *
- * @return
- * @throws DavException
- */
- public VersionHistoryResource getVersionHistory() throws DavException;
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/VersionResource.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/VersionResource.java
deleted file mode 100644
index b1d7a964ef9..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/VersionResource.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.version;
-
-import org.apache.jackrabbit.webdav.property.DavPropertyName;
-import org.apache.jackrabbit.webdav.DavException;
-
-/**
- * VersionResource is a resource that contains a copy of a particular
- * state of a version-controlled resource. A new version resource is created whenever
- * a checked-out version-controlled resource is checked-in. The server allocates
- * a distinct new URL for each new version, and this URL will never be used to
- * identify any resource other than that version. The content and dead properties
- * of a version never change.
- *
- * RFC 3253 defines the following required properties for a version resource:
- *
- *
DAV:predecessor-set (protected)
- *
DAV:successor-set (computed)
- *
DAV:checkout-set
- *
DAV:version-name
- *
DAV:checkout-fork (in-place-checkout or working resource)
- *
DAV:checkin-fork (in-place-checkout or working resource)
- *
DAV:version-history (version-history)
- *
DAV:label-name-set (label)
- *
DAV:activity-set (activity)
- *
all DeltaV-compliant resource properties.
- *
- *
- * In addition a version resource must support the following METHODS:
- *
- *
LABEL (label)
- *
CHECKOUT (working-resource)
- *
all DeltaV-compliant resource METHODS.
- *
- *
- * @see DeltaVResource
- */
-public interface VersionResource extends DeltaVResource {
-
- /**
- * The version resource defines one additional method LABEL.
- *
- * @see DeltaVResource#METHODS
- * @see org.apache.jackrabbit.webdav.DavResource#METHODS
- */
- public String METHODS = "LABEL";
-
- /**
- * Required protected property 'DAV:label-name-set' for a version of a webdav
- * resource introduced with the 'LabelInfo' feature.
- * This property contains the labels that currently select this version.
- * Property structure is defined as follows:
- *
- */
- public static final DavPropertyName LABEL_NAME_SET = DavPropertyName.create("label-name-set", DeltaVConstants.NAMESPACE);
-
- /**
- * The protected DAV:predecessor property identifies each predecessor of
- * this version. Except for the root version, which has no predecessors,
- * each version has at least one predecessor.
- * The property is defined to have the following format:
- *
- * <!ELEMENT predecessor-set (href*)>
- *
- */
- public static final DavPropertyName PREDECESSOR_SET = DavPropertyName.create("predecessor-set", DeltaVConstants.NAMESPACE);
-
- /**
- * The computed property DAV:successor-set identifies each version whose
- * DAV:predecessor-set identifies this version.
- * The property is defined to have the following format:
- *
- * <!ELEMENT successor-set (href*)>
- *
- *
- */
- public static final DavPropertyName SUCCESSOR_SET = DavPropertyName.create("successor-set", DeltaVConstants.NAMESPACE);
-
- /**
- * The computed property DAV:checkout-set identifies each checked-out
- * resource whose DAV:checked-out property identifies this version.
- * The property is defined to have the following format:
- *
- * <!ELEMENT checkout-set (href*)>
- *
- *
- * @see VersionControlledResource#CHECKED_OUT
- */
- public static final DavPropertyName CHECKOUT_SET = DavPropertyName.create("checkout-set", DeltaVConstants.NAMESPACE);
-
- /**
- * The protected property DAV:version-name defines a human readable id for
- * this version. The id defined to be unique within the version-history this
- * version belongs to.
- * The property is defined to have the following format:
- *
- */
- public static final DavPropertyName VERSION_NAME = DavPropertyName.create("version-name", DeltaVConstants.NAMESPACE);
-
- /**
- * The computed property DAV:version-history identifies the version history
- * that contains this version.
- * The property is defined to have the following format:
- *
- * <!ELEMENT version-history (href)>
- *
- */
- public static final DavPropertyName VERSION_HISTORY = DavPropertyName.create("version-history", DeltaVConstants.NAMESPACE);
-
- /**
- * This property controls the behavior of CHECKOUT when a version already
- * is checked out or has a successor.
- */
- public static final DavPropertyName CHECKOUT_FORK = DavPropertyName.create("checkout-fork", DeltaVConstants.NAMESPACE);
-
- /**
- * This property controls the behavior of CHECKIN when a version already
- * has a successor.
- */
- public static final DavPropertyName CHECKIN_FORK = DavPropertyName.create("checkin-fork", DeltaVConstants.NAMESPACE);
-
- /**
- * Modify the labels of this version resource. The modifications (SET, ADD or
- * REMOVE) are listed in the specified LabelInfo object.
- * The case of a label name must be preserved when it is stored and retrieved.
- * If the type of modification is ADD, then the label must not yet occur on
- * any other version within the same version history. In contrast a SET
- * modification will move the indicated label to this version, if it existed
- * with another version before. After a successful LABEL request the label
- * must not appear with any other version in the same version history.
- *
- * @param labelInfo
- * @throws org.apache.jackrabbit.webdav.DavException
- * @see LabelInfo
- */
- public void label(LabelInfo labelInfo) throws DavException;
-
- /**
- * Returns the VersionHistoryResource, that is referenced in the
- * {@link #VERSION_HISTORY DAV:version-history} property.
- *
- * @return
- * @throws DavException
- */
- public VersionHistoryResource getVersionHistory() throws DavException;
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/package.html b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/package.html
deleted file mode 100644
index d384267c86c..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/package.html
+++ /dev/null
@@ -1,4 +0,0 @@
-
-Interfaces and classes used to cover functionality defined by
-RFC 3253: Versioning Extensions to WebDAV.
-
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/report/ExpandPropertyReport.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/report/ExpandPropertyReport.java
deleted file mode 100644
index d54c05a4d06..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/report/ExpandPropertyReport.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.version.report;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.property.DavProperty;
-import org.apache.jackrabbit.webdav.property.DavPropertyName;
-import org.apache.jackrabbit.webdav.property.HrefProperty;
-import org.apache.jackrabbit.webdav.property.AbstractDavProperty;
-import org.apache.jackrabbit.webdav.version.DeltaVConstants;
-import org.apache.jackrabbit.webdav.version.DeltaVResource;
-import org.jdom.Element;
-import org.jdom.Attribute;
-import org.jdom.Namespace;
-import org.jdom.Document;
-
-import java.util.*;
-
-/**
- * ExpandPropertyReport encapsulates the DAV:expand-property report,
- * that provides a mechanism for retrieving in one request the properties from
- * the resources identified by those DAV:href elements. It should be supported by
- * all resources that support the REPORT method.
- *
- * RFC 3253 specifies the following required format for the request body:
- *
- * <!ELEMENT expand-property (property*)>
- * <!ELEMENT property (property*)>
- * <!ATTLIST property name NMTOKEN #REQUIRED>
- * name value: a property element type
- * <!ATTLIST property namespace NMTOKEN "DAV:">
- * namespace value: an XML namespace
- *
- * NOTE: any DAV:property elements defined in the request body, that does not
- * represent {@link HrefProperty} is treated as in a common PROPFIND request.
- *
- * @see DeltaVConstants#XML_EXPAND_PROPERTY
- * @see DeltaVConstants#XML_PROPERTY
- */
-public class ExpandPropertyReport implements Report, DeltaVConstants {
-
- private static Logger log = Logger.getLogger(ExpandPropertyReport.class);
-
- private DeltaVResource resource;
- private ReportInfo info;
- private List properties;
-
- /**
- * Returns {@link ReportType#EXPAND_PROPERTY}.
- *
- * @return
- * @see Report#getType()
- */
- public ReportType getType() {
- return ReportType.EXPAND_PROPERTY;
- }
-
- /**
- * Set the target resource.
- *
- * @param resource
- * @throws IllegalArgumentException if the specified resource is null
- * @see Report#setResource(org.apache.jackrabbit.webdav.version.DeltaVResource)
- */
- public void setResource(DeltaVResource resource) throws IllegalArgumentException {
- if (resource == null) {
- throw new IllegalArgumentException("The resource specified must not be null.");
- }
- this.resource = resource;
- }
-
- /**
- * Set the ReportInfo.
- *
- * @param info
- * @throws IllegalArgumentException if the given ReportInfo
- * does not contain a DAV:expand-property element.
- * @see Report#setInfo(ReportInfo)
- */
- public void setInfo(ReportInfo info) throws IllegalArgumentException {
- if (info == null || !XML_EXPAND_PROPERTY.equals(info.getReportElement().getName())) {
- throw new IllegalArgumentException("DAV:expand-property element expected.");
- }
- this.info = info;
- properties = info.getReportElement().getChildren(XML_PROPERTY, NAMESPACE);
- }
-
- /**
- * Run the report
- *
- * @return Xml Document as defined by
- * RFC 2518
- * @throws DavException
- * @see Report#toXml()
- */
- public Document toXml() throws DavException {
- if (info == null || resource == null) {
- throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR, "Error while running DAV:version-tree report");
- }
-
- MultiStatus ms = new MultiStatus();
- buildMultiStatus(resource, info.getDepth(), ms);
- return ms.toXml();
- }
-
- /**
- * Fills the specified MultiStatus object by generating a
- * MultiStatusResponse for the given resource (and
- * its member according to the depth value).
- *
- * @param res
- * @param depth
- * @param ms
- * @throws DavException
- * @see #getResponse(DavResource, List)
- */
- private void buildMultiStatus(DavResource res, int depth, MultiStatus ms)
- throws DavException {
- MultiStatusResponse response = getResponse(res, properties);
- ms.addResponse(response);
- if (depth > 0) {
- DavResourceIterator it = res.getMembers();
- while (it.hasNext()) {
- buildMultiStatus(it.nextResource(), depth-1, ms);
- }
- }
- }
-
- /**
- * Builds a MultiStatusResponse for the given resource respecting
- * the properties specified. Any property that represents a {@link HrefProperty}
- * is expanded: It's name equals the name of a valid {@link HrefProperty}.
- * However the value of that given property (consisting of one or multiple DAV:href elements)
- * is replaced by the Xml representation of a separate
- * {@link MultiStatusResponse multistatus responses} for the
- * resource referenced by the given DAV:href elements. The responses may
- * themselves have properties, which are defined by the separate list.
- *
- * @param res
- * @param propertyList
- * @return MultiStatusResponse for the given resource.
- * @see ExpandProperty
- */
- private MultiStatusResponse getResponse(DavResource res, List propertyList) {
- MultiStatusResponse resp = new MultiStatusResponse(res.getHref());
- Iterator propIter = propertyList.iterator();
- while (propIter.hasNext()) {
- Element propertyElem = (Element) propIter.next();
- Attribute nameAttr = propertyElem.getAttribute(ATTR_NAME);
- if (nameAttr == null) {
- // NOTE: this is not valid according to the DTD
- continue;
- }
- Attribute namespaceAttr = propertyElem.getAttribute(ATTR_NAMESPACE);
-
- String name = nameAttr.getValue();
- Namespace namespace = (namespaceAttr != null) ? Namespace.getNamespace(namespaceAttr.getValue()) : NAMESPACE;
-
- DavPropertyName propName = DavPropertyName.create(name, namespace);
- DavProperty p = res.getProperty(propName);
- if (p != null) {
- if (p instanceof HrefProperty && res instanceof DeltaVResource) {
- resp.add(new ExpandProperty((DeltaVResource)res, (HrefProperty)p, propertyElem.getChildren(XML_PROPERTY, NAMESPACE)));
- } else {
- resp.add(p);
- }
- } else {
- resp.add(propName, DavServletResponse.SC_NOT_FOUND);
- }
- }
- return resp;
- }
-
- //--------------------------------------------------------< inner class >---
- /**
- * ExpandProperty extends DavProperty. It's name
- * equals the name of a valid {@link HrefProperty}. However the value of
- * that given property (consisting of one or multiple DAV:href elements)
- * is replaced by the Xml representation of a separate
- * {@link MultiStatusResponse multistatus responses} for the
- * resource referenced to by the given DAV.:href elements. The responses may
- * themselves have properties, which are defined by the separate list.
- */
- private class ExpandProperty extends AbstractDavProperty {
-
- private List valueList = new ArrayList();
-
- /**
- * Create a new ExpandProperty.
- *
- * @param hrefProperty
- * @param propertyList
- */
- private ExpandProperty(DeltaVResource deltaVResource, HrefProperty hrefProperty, List propertyList) {
- super(hrefProperty.getName(), hrefProperty.isProtected());
- try {
- DavResource[] refResource = deltaVResource.getReferenceResources(hrefProperty.getName());
- for (int i = 0; i < refResource.length; i++) {
- MultiStatusResponse resp = getResponse(refResource[i], propertyList);
- valueList.add(resp.toXml());
- }
- } catch (DavException e) {
- // invalid references or unknown property
- log.error(e.getMessage());
- }
- }
-
- /**
- * Returns
- * @return
- */
- public Object getValue() {
- return valueList;
- }
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/report/LocateByHistoryReport.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/report/LocateByHistoryReport.java
deleted file mode 100644
index f10da0dc5c1..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/report/LocateByHistoryReport.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.version.report;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.*;
-import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
-import org.apache.jackrabbit.webdav.version.DeltaVConstants;
-import org.apache.jackrabbit.webdav.version.VersionControlledResource;
-import org.apache.jackrabbit.webdav.version.VersionHistoryResource;
-import org.apache.jackrabbit.webdav.version.DeltaVResource;
-import org.jdom.Element;
-import org.jdom.Document;
-
-import java.util.List;
-import java.util.HashSet;
-import java.util.Iterator;
-
-/**
- * LocateByHistoryReport encapsulates the DAV:locate-by-hisotry
- * report, that may be used to locate a version-controlled resource for that
- * version history. The DAV:locate-by-history report can be applied to a collection
- * to locate the collection member that is a version-controlled resource for a
- * specified version history resource.
- *
- *
- */
-public class LocateByHistoryReport implements Report, DeltaVConstants {
-
- private static Logger log = Logger.getLogger(LocateByHistoryReport.class);
-
- private ReportInfo info;
- private HashSet vhHrefSet = new HashSet();
- private DeltaVResource resource;
-
- /**
- *
- * @return
- * @see Report#getType()
- */
- public ReportType getType() {
- return ReportType.LOCATE_BY_HISTORY;
- }
-
- /**
- * Set the DeltaVResource.
- *
- * @param resource
- * @throws IllegalArgumentException if the specified resource is not a {@link VersionControlledResource}.
- * @see Report#setResource(org.apache.jackrabbit.webdav.version.DeltaVResource)
- */
- public void setResource(DeltaVResource resource) throws IllegalArgumentException {
- if (resource instanceof VersionControlledResource) {
- this.resource = resource;
- } else {
- throw new IllegalArgumentException("DAV:version-tree report can only be created for version-controlled resources and version resources.");
- }
- }
-
- /**
- * Set the ReportInfo
- *
- * @param info
- * @throws IllegalArgumentException if the given ReportInfo
- * does not contain a DAV:version-tree element.
- * @see Report#setInfo(ReportInfo)
- */
- public void setInfo(ReportInfo info) throws IllegalArgumentException {
- if (info == null || !XML_LOCATE_BY_HISTORY.equals(info.getReportElement().getName())) {
- throw new IllegalArgumentException("DAV:locate-by-history element expected.");
- }
- Element versionHistorySet = info.getReportElement().getChild(XML_VERSION_HISTORY_SET, NAMESPACE);
- if (versionHistorySet == null) {
- throw new IllegalArgumentException("The DAV:locate-by-history element must contain a DAV:version-history-set child.");
- }
-
- List l = versionHistorySet.getChildren(DavConstants.XML_HREF, DavConstants.NAMESPACE);
- if (l != null && !l.isEmpty()) {
- Iterator it = l.iterator();
- while (it.hasNext()) {
- String href = ((Element)it.next()).getText();
- if (href != null) {
- vhHrefSet.add(href);
- }
- }
- }
- this.info = info;
- }
-
- /**
- * Run the report.
- *
- * @return Xml Document representing the report in the required
- * format.
- * @throws DavException
- * @see Report#toXml()
- */
- public Document toXml() throws DavException {
- if (info == null || resource == null) {
- throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR, "Error while running DAV:locate-by-history report");
- }
-
- MultiStatus ms = new MultiStatus();
- buildResponse(resource, info.getPropertyNameSet(), info.getDepth(), ms);
- return ms.toXml();
- }
-
- /**
- * Fill the MultiStatus with the MultiStatusResponses
- * generated for the specified resource and its members according to the
- * depth value.
- *
- * @param res
- * @param propNameSet
- * @param depth
- * @param ms
- * @throws DavException
- */
- private void buildResponse(DavResource res, DavPropertyNameSet propNameSet,
- int depth, MultiStatus ms) throws DavException {
- // loop over members first, since this report only list members
- DavResourceIterator it = res.getMembers();
- while (!vhHrefSet.isEmpty() && it.hasNext()) {
- DavResource childRes = it.nextResource();
- if (childRes instanceof VersionControlledResource) {
- try {
- VersionHistoryResource vhr = ((VersionControlledResource)childRes).getVersionHistory();
- if (vhHrefSet.remove(vhr.getHref())) {
- if (propNameSet.isEmpty()) {
- ms.addResourceStatus(childRes, DavServletResponse.SC_OK, 0);
- } else {
- ms.addResourceProperties(childRes, propNameSet, 0);
- }
- }
- } catch (DavException e) {
- log.info(e.getMessage());
- }
- }
- // traverse subtree
- if (depth > 0) {
- buildResponse(it.nextResource(), propNameSet, depth-1, ms);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/report/Report.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/report/Report.java
deleted file mode 100644
index eaf3501095b..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/report/Report.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.version.report;
-
-import org.apache.jackrabbit.webdav.DavException;
-import org.apache.jackrabbit.webdav.version.DeltaVResource;
-import org.jdom.Document;
-
-/**
- * The Report interface defines METHODS needed in order to respond
- * to a REPORT request. The REPORT method is a required feature to all
- * DeltaV resources.
- *
- * @see DeltaVResource#getReport(ReportInfo)
- */
-public interface Report {
-
- /**
- * Returns the registered type of this report.
- *
- * @return the type of this report.
- */
- public ReportType getType();
-
- /**
- * Set the DeltaVResource for which this report was requested.
- *
- * @param resource
- */
- public void setResource(DeltaVResource resource);
-
- /**
- * Set the ReportInfo as specified by the REPORT request body,
- * that defines the details for this report.
- *
- * @param info providing in detail requirements for this report.
- */
- public void setInfo(ReportInfo info);
-
- /**
- * Returns the report {@link Document Xml document} defined by the this
- * ReportType. The document will be returned in the response
- * body.
- *
- * @return Xml Document object representing the generated report
- * in the proper format.
- * @throws DavException if an error occurs while running the report or
- * creating the Document.
- */
- public Document toXml() throws DavException;
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/report/ReportInfo.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/report/ReportInfo.java
deleted file mode 100644
index 134274e9b81..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/report/ReportInfo.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.version.report;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.property.DavPropertyNameSet;
-import org.apache.jackrabbit.webdav.DavConstants;
-import org.jdom.Element;
-
-/**
- * The ReportInfo class encapsulates the body of a REPORT request.
- * RFC 3253 the top Xml element
- * being the name of the requested report. In addition a Depth header may
- * be present (default value: {@link DavConstants#DEPTH_0}).
- */
-public class ReportInfo {
-
- private static Logger log = Logger.getLogger(ReportInfo.class);
-
- private final Element reportElement;
- private final int depth;
-
- /**
- * Create a new ReportInfo object.
- *
- * @param reportElement
- * @param depth Depth value as retrieved from the {@link DavConstants#HEADER_DEPTH}.
- */
- public ReportInfo(Element reportElement, int depth) {
- this.reportElement = reportElement;
- this.depth = depth;
- }
-
- /**
- * Returns the Xml element specifying the requested report.
- *
- * @return reportElement
- */
- public Element getReportElement() {
- return reportElement;
- }
-
- /**
- * Returns the depth field. The request must be applied separately to the
- * collection itself and to all members of the collection that satisfy the
- * depth value.
- *
- * @return depth
- */
- public int getDepth() {
- return depth;
- }
-
- /**
- * Returns a DavPropertyNameSet providing the property names present
- * in an eventual {@link DavConstants#XML_PROP} child element. If no such
- * child element is present an empty set is returned.
- *
- * @return {@link DavPropertyNameSet} providing the property names present
- * in an eventual {@link DavConstants#XML_PROP DAV:prop} child element or an empty set.
- */
- public DavPropertyNameSet getPropertyNameSet() {
- Element propElement = reportElement.getChild(DavConstants.XML_PROP, DavConstants.NAMESPACE);
- if (propElement != null) {
- return new DavPropertyNameSet(propElement);
- } else {
- return new DavPropertyNameSet();
- }
- }
-}
\ No newline at end of file
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/report/ReportType.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/report/ReportType.java
deleted file mode 100644
index 3d21bd948ea..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/report/ReportType.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
-* Copyright 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.jackrabbit.webdav.version.report;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.version.DeltaVConstants;
-import org.apache.jackrabbit.webdav.DavException;
-import org.apache.jackrabbit.webdav.DavServletResponse;
-import org.jdom.Element;
-import org.jdom.Namespace;
-
-import java.util.HashMap;
-
-/**
- * ReportType...
- */
-public class ReportType implements DeltaVConstants {
-
- private static Logger log = Logger.getLogger(ReportType.class);
-
- private static final HashMap types = new HashMap();
-
- public static final ReportType VERSION_TREE = register(XML_VERSION_TREE, NAMESPACE, VersionTreeReport.class);
- public static final ReportType EXPAND_PROPERTY = register(XML_EXPAND_PROPERTY, NAMESPACE, ExpandPropertyReport.class);
- public static final ReportType LOCATE_BY_HISTORY = register(XML_LOCATE_BY_HISTORY, NAMESPACE, LocateByHistoryReport.class);
-
- private final String name;
- private final Namespace namespace;
- private final Class reportClass;
-
- /**
- * Private constructor
- *
- * @see #register(String, Namespace, Class)
- */
- private ReportType(String name, Namespace namespace, Class reportClass) {
- this.name = name;
- this.namespace = namespace;
- this.reportClass = reportClass;
- }
-
- /**
- * Creates a new {@link Report} with this type.
- *
- * @return
- * @throws DavException
- */
- public Report createReport() throws DavException {
- try {
- return (Report) reportClass.getConstructor(new Class[0]).newInstance(new Object[0]);
- } catch (Exception e) {
- // should never occur
- throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR, "Failed to register Report.");
- }
- }
-
- /**
- * Returns an Xml element representing this report type
- *
- * @return Xml representation
- */
- public Element toXml() {
- return new Element(name, namespace);
- }
-
- /**
- * Returns true if this ReportType is requested by the given
- * ReportInfo
- *
- * @param reqInfo
- * @return
- */
- public boolean isRequestedReportType(ReportInfo reqInfo) {
- if (reqInfo != null) {
- Element elem = reqInfo.getReportElement();
- if (elem != null) {
- return name.equals(elem.getName()) && namespace.equals(elem.getNamespace());
- }
- }
- return false;
- }
-
- /**
- * Register the report type with the given name, namespace and class, that can
- * run that report.
- *
- * @param name
- * @param namespace
- * @param reportClass
- * @return
- * @throws IllegalArgumentException if either parameter is null or
- * if the given class does not implement the {@link Report} interface or if
- * it does not provide an empty constructor.
- */
- public static ReportType register(String name, Namespace namespace, Class reportClass) {
- if (name == null || namespace == null || reportClass == null) {
- throw new IllegalArgumentException("A ReportType cannot be registered with a null name, namespace or report class");
- }
-
- String key = buildKey(namespace, name);
- if (types.containsKey(key)) {
- return (ReportType) types.get(key);
- } else {
- // test if this report class has an empty constructor and implements Report interface
- boolean isValidClass = false;
- Class[] interfaces = reportClass.getInterfaces();
- for (int i = 0; i < interfaces.length && !isValidClass; i++) {
- isValidClass = (interfaces[i] == Report.class);
- }
- if (!isValidClass) {
- throw new IllegalArgumentException("The specified report class must implement the Report interface.");
- }
-
- try {
- reportClass.getConstructor(new Class[0]);
- } catch (NoSuchMethodException e) {
- throw new IllegalArgumentException("The specified report class must provide a default constructor.");
- }
-
- ReportType type = new ReportType(name, namespace, reportClass);
- types.put(key, type);
- return type;
- }
- }
-
- /**
- * Return the ReportType requested by the given report info object.
- *
- * @param reportInfo
- * @return the requested ReportType
- * @throws IllegalArgumentException if the reportInfo is null or
- * if the requested report type has not been registered yet.
- */
- public static ReportType getType(ReportInfo reportInfo) {
- if (reportInfo == null) {
- throw new IllegalArgumentException("ReportInfo must not be null.");
- }
- String key = buildKey(reportInfo.getReportElement().getNamespace(), reportInfo.getReportElement().getName());
- if (types.containsKey(key)) {
- return (ReportType) types.get(key);
- } else {
- throw new IllegalArgumentException("The request report '"+key+"' has not been registered yet.");
- }
- }
-
- /**
- * Build the key from the given namespace and name.
- *
- * @param namespace
- * @param name
- * @return key identifying the report with the given namespace and name
- */
- private static String buildKey(Namespace namespace, String name) {
- return "{" + namespace.getURI() + "}" + name;
- }
-}
diff --git a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/report/SupportedReportSetProperty.java b/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/report/SupportedReportSetProperty.java
deleted file mode 100644
index edd4ab4b448..00000000000
--- a/contrib/jcr-server/webdav/src/java/org/apache/jackrabbit/webdav/version/report/SupportedReportSetProperty.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2005 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.jackrabbit.webdav.version.report;
-
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.webdav.version.DeltaVConstants;
-import org.apache.jackrabbit.webdav.property.AbstractDavProperty;
-import org.jdom.Element;
-
-import java.util.HashSet;
-import java.util.Iterator;
-
-/**
- * SupportedReportSetProperty represents the DAV:supported-report-set
- * property defined by RFC 3253. It identifies the reports that are supported by
- * the given resource.
- *
- * <!ELEMENT supported-report-set (supported-report*)>
- * <!ELEMENT supported-report report>
- * <!ELEMENT report ANY>
- * ANY value: a report element type
- *
This class represents a child node entry row in the ORM object graph.
- */
-public class ORMChildNodeEntry
- implements Serializable, Comparable {
- private String uuid;
- private String parentUUID;
- private String name;
- private Integer index;
- private Integer dbId;
- private ORMNodeState parent;
- public ORMChildNodeEntry() {
- }
-
- public ORMChildNodeEntry(ORMNodeState parent, ChildNodeEntry childNodeEntry, String parentUUID) {
- this.parent = parent;
- uuid = childNodeEntry.getUUID();
- this.parentUUID = parentUUID;
- name = childNodeEntry.getName().toString();
- index = new Integer(childNodeEntry.getIndex());
- }
-
- public void setUuid(String uuid) {
- this.uuid = uuid;
- }
-
- public void setParentUUID(String parentUUID) {
- this.parentUUID = parentUUID;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public void setIndex(Integer index) {
- this.index = index;
- }
-
- public void setDbId(Integer dbId) {
- this.dbId = dbId;
- }
-
- public void setParent(ORMNodeState parent) {
- this.parent = parent;
- }
-
- public String getUuid() {
- return uuid;
- }
-
- public String getParentUUID() {
- return parentUUID;
- }
-
- public String getName() {
- return name;
- }
-
- public Integer getIndex() {
- return index;
- }
-
- public Integer getDbId() {
- return dbId;
- }
-
- public ORMNodeState getParent() {
- return parent;
- }
-
- public boolean equals(Object obj) {
- if (!(obj instanceof ORMChildNodeEntry)) {
- return false;
- }
- ORMChildNodeEntry right = (ORMChildNodeEntry) obj;
- if (getUuid().equals(right.getUuid()) &&
- getName().equals(right.getName()) &&
- (getIndex().equals(right.getIndex()))) {
- return true;
- } else {
- return false;
- }
- }
-
- public int compareTo(Object obj) {
- if (equals(obj)) {
- return 0;
- }
- ORMChildNodeEntry right = (ORMChildNodeEntry) obj;
- return (getUuid() + getName() + getIndex()).compareTo(right.getUuid() + right.getName() + right.getIndex());
- }
-
- public int hashCode() {
- return (getUuid() + getName() + getIndex()).hashCode();
- }
-}
diff --git a/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ORMNodeMixinType.java b/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ORMNodeMixinType.java
deleted file mode 100644
index cf0355dbaa4..00000000000
--- a/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ORMNodeMixinType.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.core.state.orm;
-
-import java.io.Serializable;
-
-/**
- *
This class represents a single entry of a mixin type for a node.
- */
-public class ORMNodeMixinType
- implements Serializable {
- private String nodeUUID;
- private String mixinTypeName;
- private Integer dbId;
- private ORMNodeState node;
- public ORMNodeMixinType() {
- }
-
- public ORMNodeMixinType(ORMNodeState node, String nodeUUID, String mixinTypeName) {
- this.node = node;
- this.nodeUUID = nodeUUID;
- this.mixinTypeName = mixinTypeName;
- }
-
- public void setNodeUUID(String nodeUUID) {
- this.nodeUUID = nodeUUID;
- }
-
- public void setMixinTypeName(String mixinTypeName) {
-
- this.mixinTypeName = mixinTypeName;
- }
-
- public void setDbId(Integer dbId) {
- this.dbId = dbId;
- }
-
- public void setNode(ORMNodeState node) {
- this.node = node;
- }
-
- public String getNodeUUID() {
- return nodeUUID;
- }
-
- public String getMixinTypeName() {
-
- return mixinTypeName;
- }
-
- public Integer getDbId() {
- return dbId;
- }
-
- public ORMNodeState getNode() {
- return node;
- }
-
- public boolean equals(Object obj) {
- if (!(obj instanceof ORMChildNodeEntry)) {
- return false;
- }
- ORMNodeMixinType right = (ORMNodeMixinType) obj;
- if (getMixinTypeName().equals(right.getMixinTypeName())) {
- return true;
- } else {
- return false;
- }
- }
-
- public int hashCode() {
- return getMixinTypeName().hashCode();
- }
-
-}
diff --git a/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ORMNodeParent.java b/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ORMNodeParent.java
deleted file mode 100644
index 23e89659450..00000000000
--- a/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ORMNodeParent.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.core.state.orm;
-
-import java.io.Serializable;
-
-/**
- *
This class represents a single entry of a node's parents.
- */
-public class ORMNodeParent
- implements Serializable {
- private String nodeUUID;
- private String parentUUID;
- private Integer dbId;
- private ORMNodeState node;
- public ORMNodeParent() {
- }
-
- public ORMNodeParent(ORMNodeState node, String nodeUUID, String parentUUID) {
- this.node = node;
- this.nodeUUID = nodeUUID;
- this.parentUUID = parentUUID;
- }
-
- public void setNodeUUID(String nodeUUID) {
- this.nodeUUID = nodeUUID;
- }
-
- public void setParentUUID(String parentUUID) {
- this.parentUUID = parentUUID;
- }
-
- public void setDbId(Integer dbId) {
- this.dbId = dbId;
- }
-
- public void setNode(ORMNodeState node) {
- this.node = node;
- }
-
- public String getNodeUUID() {
- return nodeUUID;
- }
-
- public String getParentUUID() {
- return parentUUID;
- }
-
- public Integer getDbId() {
- return dbId;
- }
-
- public ORMNodeState getNode() {
- return node;
- }
-
- public boolean equals(Object obj) {
- if (!(obj instanceof ORMNodeParent)) {
- return false;
- }
- ORMNodeParent right = (ORMNodeParent) obj;
- if (getParentUUID().equals(right.getParentUUID())) {
- return true;
- } else {
- return false;
- }
- }
-
- public int hashCode() {
- return getParentUUID().hashCode();
- }
-}
diff --git a/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ORMNodeReference.java b/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ORMNodeReference.java
deleted file mode 100644
index a4f1dc9f002..00000000000
--- a/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ORMNodeReference.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.core.state.orm;
-
-import java.io.Serializable;
-
-/**
- *
This class represents a node reference, that is to say a property that
- * points to a specific node.
- */
-public class ORMNodeReference
- implements Serializable {
- private String targetId;
- private String propertyParentUUID;
- private String propertyName;
- private Integer dbId;
- public ORMNodeReference() {
- }
-
- public ORMNodeReference(String targetId, String propertyParentUUID, String propertyName) {
- this.targetId = targetId;
- this.propertyParentUUID = propertyParentUUID;
- this.propertyName = propertyName;
- }
-
- public void setTargetId(String targetId) {
- this.targetId = targetId;
- }
-
- public void setPropertyParentUUID(String propertyParentUUID) {
- this.propertyParentUUID = propertyParentUUID;
- }
-
- public void setPropertyName(String propertyName) {
- this.propertyName = propertyName;
- }
-
- public void setDbId(Integer dbId) {
- this.dbId = dbId;
- }
-
- public String getTargetId() {
- return targetId;
- }
-
- public String getPropertyParentUUID() {
- return propertyParentUUID;
- }
-
- public String getPropertyName() {
- return propertyName;
- }
-
- public Integer getDbId() {
- return dbId;
- }
-
- public boolean equals(Object obj) {
- if (!(obj instanceof ORMNodeParent)) {
- return false;
- }
- ORMNodeReference right = (ORMNodeReference) obj;
- if (getTargetId().equals(right.getTargetId()) &&
- getPropertyParentUUID().equals(right.getPropertyParentUUID()) &&
- getPropertyName().equals(right.getPropertyName()) ) {
- return true;
- } else {
- return false;
- }
- }
-
- public int hashCode() {
- return (getTargetId() + getPropertyParentUUID() + getPropertyName()).hashCode();
- }
-}
diff --git a/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ORMNodeState.java b/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ORMNodeState.java
deleted file mode 100644
index 43d58c81a2b..00000000000
--- a/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ORMNodeState.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.core.state.orm;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-
-import org.apache.jackrabbit.core.ItemId;
-import org.apache.jackrabbit.core.QName;
-import org.apache.jackrabbit.core.nodetype.NodeDefId;
-import org.apache.jackrabbit.core.state.NodeState;
-import org.apache.jackrabbit.core.state.NodeState.ChildNodeEntry;
-import org.apache.jackrabbit.core.state.NodeState.PropertyEntry;
-import org.apache.log4j.Logger;
-
-/**
- *
This class represents an copy of Jackrabbit's node state, in an ORM
- * compatible format.
- */
-public abstract class ORMNodeState implements Serializable {
-
- private static Logger log = Logger.getLogger(ORMNodeState.class);
-
- protected String uuid;
- protected String parentUUID;
- protected String nodeTypeName;
- protected String definitionId;
-
- public ORMNodeState() {
-
- }
-
- public ORMNodeState(ItemId id) {
- uuid = id.toString();
- }
-
- public ORMNodeState(NodeState state) {
- fromPersistentNodeState(state);
- }
-
- public void fromPersistentNodeState(NodeState state) {
- getChildNodeEntries().clear();
- getPropertyEntries().clear();
- getMixinTypeNames().clear();
- getParentUUIDs().clear();
- uuid = state.getUUID();
- parentUUID = state.getParentUUID();
- if (state.getNodeTypeName() != null) {
- nodeTypeName = state.getNodeTypeName().toString();
- }
- if (state.getDefinitionId() != null) {
- definitionId = state.getDefinitionId().toString();
- }
- Iterator childNodeEntriesIter = state.getChildNodeEntries().iterator();
- while (childNodeEntriesIter.hasNext()) {
- ChildNodeEntry curChildNodeEntry = (ChildNodeEntry) childNodeEntriesIter.next();
- log.debug("childNodeEntry " + curChildNodeEntry.getIndex() + " name=" + curChildNodeEntry.getName() + " uuid=" + curChildNodeEntry.getUUID());
- ORMChildNodeEntry childNode = new ORMChildNodeEntry(this, curChildNodeEntry, uuid);
- getChildNodeEntries().add(childNode);
- }
- Iterator propertyEntryIter = state.getPropertyEntries().iterator();
- while (propertyEntryIter.hasNext()) {
- PropertyEntry curPropertyEntry = (PropertyEntry) propertyEntryIter.next();
- log.debug("propertyEntry " + curPropertyEntry.getName());
- ORMPropertyEntry propertyEntry = new ORMPropertyEntry(this, curPropertyEntry, uuid);
- getPropertyEntries().add(propertyEntry);
- }
- Iterator mixinTypeIter = state.getMixinTypeNames().iterator();
- while (mixinTypeIter.hasNext()) {
- QName curName = (QName) mixinTypeIter.next();
- getMixinTypeNames().add(new ORMNodeMixinType(this, uuid, curName.toString()));
- }
- Iterator parentIter = state.getParentUUIDs().iterator();
- while (parentIter.hasNext()) {
- String parentId = (String) parentIter.next();
- getParentUUIDs().add(new ORMNodeParent(this, uuid, parentId));
- }
- }
-
- public String getUuid() {
- return uuid;
- }
-
- public String getParentUUID() {
- return parentUUID;
- }
-
- public String getNodeTypeName() {
- return nodeTypeName;
- }
-
- public String getDefinitionId() {
-
- return definitionId;
- }
-
- public abstract Collection getChildNodeEntries();
-
- public abstract Collection getPropertyEntries();
-
- public abstract Collection getMixinTypeNames();
-
- public abstract Collection getParentUUIDs();
-
- public void setUuid(String uuid) {
- this.uuid = uuid;
- }
-
- public void setParentUUID(String parentUUID) {
- this.parentUUID = parentUUID;
- }
-
- public void setNodeTypeName(String nodeTypeName) {
- this.nodeTypeName = nodeTypeName;
- }
-
- public void setDefinitionId(String definitionId) {
-
- this.definitionId = definitionId;
- }
-
- public abstract void setChildNodeEntries(Collection childNodeEntries);
-
- public abstract void setPropertyEntries(Collection propertyEntries);
-
- public abstract void setMixinTypeNames(Collection mixinTypeNames);
-
- public abstract void setParentUUIDs(Collection parentUUIDs);
-
- public void toPersistentNodeState(NodeState state) {
- state.setDefinitionId(NodeDefId.valueOf(getDefinitionId()));
- state.setNodeTypeName(QName.valueOf(getNodeTypeName()));
- state.setParentUUID(getParentUUID());
-
- Iterator childNodeEntryIter = getChildNodeEntries().iterator();
- while (childNodeEntryIter.hasNext()) {
- ORMChildNodeEntry curChildNodeEntry = (ORMChildNodeEntry) childNodeEntryIter.next();
- log.debug(" Loaded child node " + QName.valueOf(curChildNodeEntry.getName()) + " uuid=" + curChildNodeEntry.getUuid());
- state.addChildNodeEntry(QName.valueOf(curChildNodeEntry.getName()), curChildNodeEntry.getUuid());
- }
- Iterator propertyEntryIter = getPropertyEntries().iterator();
- while (propertyEntryIter.hasNext()) {
- ORMPropertyEntry curPropertyEntry = (ORMPropertyEntry) propertyEntryIter.next();
- log.debug(" Loaded property " + QName.valueOf(curPropertyEntry.getName()));
- state.addPropertyEntry(QName.valueOf(curPropertyEntry.getName()));
- }
- Iterator mixinTypeNameIter = getMixinTypeNames().iterator();
- Set mixinTypeQNames = new HashSet();
- while (mixinTypeNameIter.hasNext()) {
- ORMNodeMixinType curMixinType = (ORMNodeMixinType) mixinTypeNameIter.next();
- mixinTypeQNames.add(QName.valueOf(curMixinType.getMixinTypeName()));
- }
- state.setMixinTypeNames(mixinTypeQNames);
- Iterator parentUUIDIter = getParentUUIDs().iterator();
- List nParentUUIDs = new ArrayList();
- while (parentUUIDIter.hasNext()) {
- ORMNodeParent curNodeParent = (ORMNodeParent) parentUUIDIter.next();
- nParentUUIDs.add(curNodeParent.getParentUUID());
- }
- state.setParentUUIDs(nParentUUIDs);
- }
-
- public boolean equals(Object obj) {
- if (!(obj instanceof ORMNodeState)) {
- return false;
- }
- ORMNodeState right = (ORMNodeState) obj;
- if (getUuid().equals(right.getUuid())) {
- return true;
- } else {
- return false;
- }
- }
-
- public int hashCode() {
- return getUuid().hashCode();
- }
-}
diff --git a/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ORMPropertyEntry.java b/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ORMPropertyEntry.java
deleted file mode 100644
index 86f26356b6b..00000000000
--- a/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ORMPropertyEntry.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.core.state.orm;
-
-import java.io.Serializable;
-
-import org.apache.jackrabbit.core.state.NodeState.PropertyEntry;
-
-/**
- *
This class represents a single entry of a property in a node. This
- * class only stores the name of the property, the actual property and it's
- * values are stored in the ORMPropertyState class.
- */
-public class ORMPropertyEntry
- implements Serializable {
- private String parentUUID;
- private String name;
- private Integer dbId;
- private ORMNodeState parent;
- public ORMPropertyEntry() {
- }
-
- public ORMPropertyEntry(ORMNodeState parent, PropertyEntry propertyEntry, String parentUUID) {
- this.parent = parent;
- this.parentUUID = parentUUID;
- this.name = propertyEntry.getName().toString();
- }
-
- public void setParentUUID(String parentUUID) {
- this.parentUUID = parentUUID;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public void setDbId(Integer dbId) {
-
- this.dbId = dbId;
- }
-
- public void setParent(ORMNodeState parent) {
- this.parent = parent;
- }
-
- public String getParentUUID() {
- return parentUUID;
- }
-
- public String getName() {
- return name;
- }
-
- public Integer getDbId() {
-
- return dbId;
- }
-
- public ORMNodeState getParent() {
- return parent;
- }
-
- public boolean equals(Object obj) {
- if (!(obj instanceof ORMPropertyEntry)) {
- return false;
- }
- ORMPropertyEntry right = (ORMPropertyEntry) obj;
- if (getName().equals(right.getName())) {
- return true;
- } else {
- return false;
- }
- }
-
- public int hashCode() {
- return (getName()).hashCode();
- }
-
-}
diff --git a/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ORMPropertyState.java b/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ORMPropertyState.java
deleted file mode 100644
index 16bdab6bb10..00000000000
--- a/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ORMPropertyState.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.core.state.orm;
-
-import java.io.Serializable;
-
-import org.apache.jackrabbit.core.InternalValue;
-import org.apache.jackrabbit.core.ItemId;
-import org.apache.jackrabbit.core.PropertyId;
-import org.apache.jackrabbit.core.nodetype.PropDefId;
-import org.apache.jackrabbit.core.state.ItemStateException;
-import org.apache.jackrabbit.core.state.PropertyState;
-import org.apache.jackrabbit.core.state.orm.ojb.ValuesToStringFieldConversion;
-import org.apache.ojb.broker.accesslayer.conversions.ConversionException;
-import javax.jcr.PropertyType;
-
-/**
- *
This class represents a property state in an ORM-compatible format.
- */
-public class ORMPropertyState implements Serializable {
- private String values;
- private Integer type;
- private String definitionId;
- private Boolean multiValued;
- private String itemId;
- private String name;
- private String parentUUID;
-
- public ORMPropertyState() {
- }
-
- public ORMPropertyState(ItemId id) throws ItemStateException {
- if (id instanceof PropertyId) {
- PropertyId propId = (PropertyId) id;
- this.itemId = propId.toString();
- name = propId.getName().toString();
- parentUUID = propId.getParentUUID();
- } else {
- throw new ItemStateException("PropertyId expected, instead got " + id.getClass());
- }
- }
-
- public ORMPropertyState(PropertyState state) {
- fromPersistentPropertyState(state);
- }
-
- public void fromPersistentPropertyState(PropertyState state) throws
- ConversionException {
- this.itemId = state.getId().toString();
- name = state.getName().toString();
- parentUUID = state.getParentUUID();
- values = (String) new ValuesToStringFieldConversion().javaToSql(state.getValues());
- type = new Integer(state.getType());
- if (state.getDefinitionId() != null) {
- definitionId = state.getDefinitionId().toString();
- }
- multiValued = new Boolean(state.isMultiValued());
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public void setValues(String values) {
- this.values = values;
- }
-
- public void setParentUUID(String parentUUID) {
- this.parentUUID = parentUUID;
- }
-
- public void setType(Integer type) {
- this.type = type;
- }
-
- public void setDefinitionId(String definitionId) {
-
- this.definitionId = definitionId;
- }
-
- public void setMultiValued(Boolean multiValued) {
- this.multiValued = multiValued;
- }
-
- public void setItemId(String itemId) {
-
- this.itemId = itemId;
- }
-
- public String getName() {
- return name;
- }
-
- public String getValues() {
- return values;
- }
-
- public String getParentUUID() {
- return parentUUID;
- }
-
- public Integer getType() {
- return type;
- }
-
- public String getDefinitionId() {
-
- return definitionId;
- }
-
- public Boolean getMultiValued() {
- return multiValued;
- }
-
- public String getItemId() {
-
- return itemId;
- }
-
- public void toPersistentPropertyState(PropertyState state) {
- if (getDefinitionId() != null) {
- state.setDefinitionId(PropDefId.valueOf(getDefinitionId()));
- }
- if (getType() != null) {
- state.setType(getType().intValue());
- }
- if (getType().intValue() != PropertyType.BINARY) {
- ValuesToStringFieldConversion vts = new
- ValuesToStringFieldConversion(getType().intValue());
- InternalValue[] values = (InternalValue[]) vts.sqlToJava(getValues());
- if (values.length > 1) {
- state.setMultiValued(true);
- } else {
- state.setMultiValued(multiValued.booleanValue());
- }
- state.setValues(values);
- } else {
- state.setMultiValued(multiValued.booleanValue());
- }
- }
-
- public boolean equals(Object obj) {
- if (!(obj instanceof ORMPropertyState)) {
- return false;
- }
- ORMPropertyState right = (ORMPropertyState) obj;
- if (itemId.equals(right.getItemId())) {
- return true;
- } else {
- return false;
- }
- }
-
- public int hashCode() {
- return getItemId().hashCode();
- }
-}
diff --git a/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/hibernate/HibernateNodeState.java b/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/hibernate/HibernateNodeState.java
deleted file mode 100644
index 61f4f47f74d..00000000000
--- a/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/hibernate/HibernateNodeState.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.core.state.orm.hibernate;
-
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.apache.jackrabbit.core.ItemId;
-import org.apache.jackrabbit.core.state.NodeState;
-import org.apache.jackrabbit.core.state.orm.ORMNodeState;
-
-/**
- *
Hibernate-specific node state class. This is necessary because
- * in this implementation we use a set to represent lists.
- */
-public class HibernateNodeState extends ORMNodeState {
-
- private Set setChildNodeEntries = new HashSet();
- private Set setParentUUIDs = new HashSet();
- private Set setMixinTypeNames = new HashSet();
- private Set setPropertyEntries = new HashSet();
-
- public HibernateNodeState() {
- }
- public HibernateNodeState(ItemId id) {
- super(id);
- }
- public HibernateNodeState(NodeState state) {
- super();
- fromPersistentNodeState(state);
- }
- public Collection getChildNodeEntries() {
- return setChildNodeEntries;
- }
- public void setChildNodeEntries(Collection childNodeEntries) {
- this.setChildNodeEntries.clear();
- this.setChildNodeEntries.addAll(childNodeEntries);
- }
-
- public Collection getPropertyEntries() {
- return setPropertyEntries;
- }
-
- public Collection getMixinTypeNames() {
- return setMixinTypeNames;
- }
-
- public Collection getParentUUIDs() {
- return setParentUUIDs;
- }
-
- public void setPropertyEntries(Collection propertyEntries) {
- this.setPropertyEntries.clear();
- this.setPropertyEntries.addAll(propertyEntries);
- }
-
- public void setMixinTypeNames(Collection mixinTypeNames) {
- this.setMixinTypeNames.clear();
- this.setMixinTypeNames.addAll(mixinTypeNames);
- }
-
- public void setParentUUIDs(Collection parentUUIDs) {
- this.setParentUUIDs.clear();
- this.setParentUUIDs.addAll(parentUUIDs);
- }
-
- public Set getSetChildNodeEntries() {
- return setChildNodeEntries;
- }
-
- public void setSetChildNodeEntries(Set setChildNodeEntries) {
- this.setChildNodeEntries = setChildNodeEntries;
- }
-
- public Set getSetPropertyEntries() {
- return setPropertyEntries;
- }
-
- public void setSetPropertyEntries(Set setPropertyEntries) {
- this.setPropertyEntries = setPropertyEntries;
- }
-
- public Set getSetMixinTypeNames() {
- return setMixinTypeNames;
- }
-
- public void setSetMixinTypeNames(Set setMixinTypeNames) {
- this.setMixinTypeNames = setMixinTypeNames;
- }
-
- public Set getSetParentUUIDs() {
- return setParentUUIDs;
- }
-
- public void setSetParentUUIDs(Set setParentUUIDs) {
- this.setParentUUIDs = setParentUUIDs;
- }
-
-}
diff --git a/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/hibernate/HibernatePersistenceManager.java b/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/hibernate/HibernatePersistenceManager.java
deleted file mode 100644
index 2cad00aeece..00000000000
--- a/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/hibernate/HibernatePersistenceManager.java
+++ /dev/null
@@ -1,703 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.core.state.orm.hibernate;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import javax.jcr.PropertyType;
-
-import org.apache.jackrabbit.core.BLOBFileValue;
-import org.apache.jackrabbit.core.InternalValue;
-import org.apache.jackrabbit.core.NodeId;
-import org.apache.jackrabbit.core.PropertyId;
-import org.apache.jackrabbit.core.QName;
-import org.apache.jackrabbit.core.state.AbstractPersistenceManager;
-import org.apache.jackrabbit.core.state.ItemState;
-import org.apache.jackrabbit.core.state.ItemStateException;
-import org.apache.jackrabbit.core.state.NoSuchItemStateException;
-import org.apache.jackrabbit.core.state.NodeReferences;
-import org.apache.jackrabbit.core.state.NodeReferencesId;
-import org.apache.jackrabbit.core.state.NodeState;
-import org.apache.jackrabbit.core.state.PMContext;
-import org.apache.jackrabbit.core.state.PropertyState;
-import org.apache.jackrabbit.core.state.orm.ORMBlobValue;
-import org.apache.jackrabbit.core.state.orm.ORMNodeReference;
-import org.apache.jackrabbit.core.state.orm.ORMPropertyState;
-import org.apache.log4j.Logger;
-import net.sf.hibernate.Hibernate;
-import net.sf.hibernate.HibernateException;
-import net.sf.hibernate.ObjectNotFoundException;
-import net.sf.hibernate.Session;
-import net.sf.hibernate.SessionFactory;
-import net.sf.hibernate.Transaction;
-import net.sf.hibernate.cfg.Configuration;
-import net.sf.hibernate.type.Type;
-
-/**
- * Hibernate implementation of a Jackrabbit persistence manager.
- */
-public class HibernatePersistenceManager extends AbstractPersistenceManager {
-
- private static Logger log = Logger.getLogger(HibernatePersistenceManager.class);
-
- private SessionFactory sessionFactory;
-
- public HibernatePersistenceManager() {
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.PersistenceManager#init
- */
- public void init(PMContext context) throws Exception {
- try {
- // Create the SessionFactory
- sessionFactory = new Configuration().configure().
- buildSessionFactory();
- } catch (Throwable ex) {
- log.error("Initial SessionFactory creation failed.", ex);
- throw new ExceptionInInitializerError(ex);
- }
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.PersistenceManager#close
- */
- public void close() throws Exception {
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.PersistenceManager#load(NodeId)
- */
- public NodeState load(NodeId nodeId) throws NoSuchItemStateException,
- ItemStateException {
- log.debug("Request for " + nodeId.getUUID());
-
- NodeState state = null;
- Session session = null;
- Transaction tx = null;
- try {
- session = sessionFactory.openSession();
- tx = session.beginTransaction();
- List nodeList = session.find(
- "from org.apache.jackrabbit.core.state.orm.hibernate.HibernateNodeState as node WHERE " +
- "node.uuid = ?",
- new Object[] {nodeId.getUUID()},
- new Type[] {Hibernate.STRING});
-
- tx.commit();
- if (nodeList.size() != 1) {
- throw new NoSuchItemStateException("Couldn't find unique node " +
- nodeId.getUUID() + ", found " +
- nodeList.size() +
- " results instead");
- }
- HibernateNodeState result = (HibernateNodeState) nodeList.get(0);
- state = createNew(nodeId);
- result.toPersistentNodeState(state);
- } catch (HibernateException he) {
- try {
- if (tx != null)
- tx.rollback();
- } catch (HibernateException he2) {
- log.error("Error while rolling back transaction", he2);
- }
- throw new ItemStateException("Error loading " + nodeId.getUUID(),
- he);
- } finally {
- if (session != null) {
- try {
- session.close();
- } catch (HibernateException he) {
- throw new ItemStateException(
- "Error while closing hibernate session", he);
- }
- }
- }
- return state;
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.PersistenceManager#load(PropertyId)
- */
- public PropertyState load(PropertyId propId) throws
- NoSuchItemStateException, ItemStateException {
-
- PropertyState state = null;
- Session session = null;
- try {
- session = sessionFactory.openSession();
- Transaction tx = session.beginTransaction();
- ORMPropertyState propState = null;
- try {
-
- List propertyList = session.find(
- "from org.apache.jackrabbit.core.state.orm.ORMPropertyState as prop WHERE " +
- "prop.parentUUID = ? and prop.name = ?",
- new Object[] {propId.getParentUUID(),
- propId.getName().toString()},
- new Type[] {Hibernate.STRING, Hibernate.STRING});
-
- tx.commit();
- if (propertyList.size() != 1) {
- throw new NoSuchItemStateException(
- "Couldn't find unique property " + propId + ", found " +
- propertyList.size() + " results instead");
- }
- propState = (ORMPropertyState) propertyList.get(0);
- state = createNew(propId);
- propState.toPersistentPropertyState(state);
- if (propState.getType().intValue() == PropertyType.BINARY) {
- // we must now load the binary values.
- ArrayList internalValueList = new ArrayList();
- List blobValueList = session.find(
- "from org.apache.jackrabbit.core.state.orm.ORMBlobValue as bv WHERE " +
- "bv.parentUUID = ? and bv.propertyName = ?",
- new Object[] {propId.getParentUUID(),
- propId.getName().toString()},
- new Type[] {Hibernate.STRING, Hibernate.STRING});
-
- Iterator resultIter = blobValueList.iterator();
- while (resultIter.hasNext()) {
- ORMBlobValue ormBlobValue = (ORMBlobValue) resultIter.
- next();
- ByteArrayInputStream in = new ByteArrayInputStream(
- ormBlobValue.getBlobValue());
- try {
- BLOBFileValue blobValue = new BLOBFileValue(in);
- internalValueList.add(blobValue);
- } catch (Throwable t) {
- throw new ItemStateException(
- "Error while trying to load blob value", t);
- }
- }
- state.setValues( (InternalValue[]) internalValueList.
- toArray(new
- InternalValue[internalValueList.
- size()]));
- }
- } catch (ObjectNotFoundException onfe) {
- throw new NoSuchItemStateException("Couldn't find " + propId,
- onfe);
- }
- } catch (HibernateException he) {
- throw new ItemStateException("Error loading " + propId, he);
- } finally {
- if (session != null) {
- try {
- session.close();
- } catch (HibernateException he) {
- throw new ItemStateException(
- "Error while closing hibernate session", he);
- }
- }
- }
- return state;
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.PersistenceManager#load(NodeReferencesId)
- */
- public NodeReferences load(NodeReferencesId targetId) throws
- NoSuchItemStateException, ItemStateException {
- log.debug("Loading node references for targetId=" +
- targetId.toString());
- NodeReferences refs = null;
- Session session = null;
- Transaction tx = null;
- try {
- session = sessionFactory.openSession();
- tx = session.beginTransaction();
- Iterator nodeRefIter = session.iterate("from org.apache.jackrabbit.core.state.orm.ORMNodeReference as nf where nf.targetId='" +
- targetId.toString() +
- "'");
- refs = new NodeReferences(targetId);
- while (nodeRefIter.hasNext()) {
- ORMNodeReference curNodeReference = (ORMNodeReference)
- nodeRefIter.
- next();
- refs.addReference(new PropertyId(curNodeReference.
- getPropertyParentUUID(),
- QName.
- valueOf(curNodeReference.
- getPropertyName())));
- }
- tx.commit();
- } catch (HibernateException he) {
- try {
- if (tx != null)
- tx.rollback();
- } catch (HibernateException he2) {
- log.error("Error while rolling back transaction", he2);
- }
- log.error("Error while loading node reference for targetId=" +
- targetId.toString(), he);
- } finally {
- if (session != null) {
- try {
- session.close();
- } catch (HibernateException he) {
- throw new ItemStateException(
- "Error while closing hibernate session", he);
- }
- }
- }
- return refs;
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.PersistenceManager#exists(NodeId)
- */
- public boolean exists(NodeId id) throws ItemStateException {
- HibernateNodeState result = null;
- Session session = null;
- Transaction tx = null;
- try {
- session = sessionFactory.openSession();
- tx = session.beginTransaction();
- List nodeList = session.find(
- "from org.apache.jackrabbit.core.state.orm.hibernate.HibernateNodeState as node WHERE " +
- "node.uuid = ?",
- new Object[] {id.toString()},
- new Type[] {Hibernate.STRING});
-
- tx.commit();
- if (nodeList.size() < 1) {
- return false;
- } else {
- if (nodeList.size() > 1) {
- log.warn("Node " + id +
- " exists more than once in database !");
- }
- return true;
- }
- } catch (HibernateException he) {
- try {
- if (tx != null)
- tx.rollback();
- } catch (HibernateException he2) {
- log.error("Error while rolling back transaction", he2);
- }
- throw new ItemStateException("Error loading " + id, he);
- } finally {
- if (session != null) {
- try {
- session.close();
- } catch (HibernateException he) {
- throw new ItemStateException(
- "Error while closing hibernate session", he);
- }
- }
- }
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.PersistenceManager#exists(PropertyId)
- */
- public boolean exists(PropertyId id) throws ItemStateException {
- boolean result = false;
- Session session = null;
- Transaction tx = null;
- try {
- session = sessionFactory.openSession();
- tx = session.beginTransaction();
- ORMPropertyState propState = null;
- PropertyId propId = (PropertyId) id;
- List propertyList = session.find(
- "from org.apache.jackrabbit.core.state.orm.ORMPropertyState as prop WHERE " +
- "prop.parentUUID = ? and prop.name = ?",
- new Object[] {propId.getParentUUID(),
- propId.getName().toString()},
- new Type[] {Hibernate.STRING, Hibernate.STRING});
-
- tx.commit();
- if (propertyList.size() < 1) {
- return false;
- } else {
- if (propertyList.size() > 1) {
- log.warn("Property " + id +
- " exists more than once in database !");
- }
- return true;
- }
- } catch (HibernateException he) {
- try {
- if (tx != null)
- tx.rollback();
- } catch (HibernateException he2) {
- log.error("Error while rolling back transaction", he2);
- }
- throw new ItemStateException("Error loading " + id, he);
- } finally {
- if (session != null) {
- try {
- session.close();
- } catch (HibernateException he) {
- throw new ItemStateException(
- "Error while closing hibernate session", he);
- }
- }
- }
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.PersistenceManager#exists(NodeReferencesId)
- */
- public boolean exists(NodeReferencesId targetId) throws ItemStateException {
- boolean result = false;
- Session session = null;
- Transaction tx = null;
- try {
- session = sessionFactory.openSession();
- tx = session.beginTransaction();
- Iterator nodeRefIter = session.iterate("from org.apache.jackrabbit.core.state.orm.ORMNodeReference as nf where nf.targetId='" +
- targetId.toString() +
- "'");
- NodeReferences refs = new NodeReferences(targetId);
- if (nodeRefIter.hasNext()) {
- result = true;
- }
- tx.commit();
- } catch (HibernateException he) {
- try {
- if (tx != null)
- tx.rollback();
- } catch (HibernateException he2) {
- log.error("Error while rolling back transaction", he2);
- }
- throw new ItemStateException(
- "Error while testing reference existence for targetId=" +
- targetId, he);
- } finally {
- if (session != null) {
- try {
- session.close();
- } catch (HibernateException he) {
- throw new ItemStateException(
- "Error while closing hibernate session", he);
- }
- }
- }
- return result;
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.AbstractPersistenceManager#store(NodeState)
- */
- public void store(NodeState state) throws ItemStateException {
- log.debug("Request to store " + state.getId());
- boolean isUpdate = true;
- Session session = null;
- Transaction tx = null;
- try {
- session = sessionFactory.openSession();
- tx = session.beginTransaction();
- HibernateNodeState nodeState = new HibernateNodeState(state);
- if (state.getStatus() == ItemState.STATUS_NEW) {
- session.save(nodeState);
- } else {
- session.update(nodeState);
- }
- tx.commit();
- } catch (HibernateException he) {
- try {
- if (tx != null)
- tx.rollback();
- } catch (HibernateException he2) {
- log.error("Error while rolling back transaction", he2);
- }
- throw new ItemStateException("Error saving " + state.getId(), he);
- } finally {
- if (session != null) {
- try {
- session.close();
- } catch (HibernateException he) {
- throw new ItemStateException(
- "Error while closing hibernate session", he);
- }
- }
- }
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.AbstractPersistenceManager#store(PropertyState)
- */
- public void store(PropertyState state) throws ItemStateException {
- log.debug("Request to store " + state.getId());
- boolean isUpdate = true;
- Session session = null;
- Transaction tx = null;
- try {
- session = sessionFactory.openSession();
- tx = session.beginTransaction();
- ORMPropertyState propState = new ORMPropertyState(state);
-
- InternalValue[] values = state.getValues();
- if (values != null) {
- for (int i = 0; i < values.length; i++) {
-
- // first we delete any existing blob values (this is faster
- // than trying to load and update each value seperately)
- session.delete("from org.apache.jackrabbit.core.state.orm.ORMBlobValue as bv where bv.parentUUID=? AND bv.propertyName=?",
- new Object[] {state.getParentUUID(),
- state.getName().toString()},
- new Type[] {Hibernate.STRING,
- Hibernate.STRING});
-
- InternalValue val = values[i];
- if (val != null) {
- if (state.getType() == PropertyType.BINARY) {
- ORMBlobValue ormBlobValue = null;
- ormBlobValue = new ORMBlobValue();
- ormBlobValue.setParentUUID(state.getParentUUID());
- ormBlobValue.setPropertyName(state.getName().
- toString());
- ormBlobValue.setIndex(new Integer(i));
- BLOBFileValue blobVal = (BLOBFileValue) val.
- internalValue();
- propState.setValues("");
- ByteArrayOutputStream out = new
- ByteArrayOutputStream();
- try {
- blobVal.spool(out);
- } catch (Throwable t) {
- tx.rollback();
- session.close();
- throw new ItemStateException(t.getMessage(), t);
- }
- ormBlobValue.setSize(new Long(blobVal.getLength()));
- ormBlobValue.setBlobValue(out.toByteArray());
- session.save(ormBlobValue);
- }
- }
- }
- }
-
- if (state.getStatus() == ItemState.STATUS_NEW) {
- session.save(propState);
- } else {
- session.update(propState);
- }
- tx.commit();
- } catch (HibernateException he) {
- try {
- if (tx != null)
- tx.rollback();
- } catch (HibernateException he2) {
- log.error("Error while rolling back transaction", he2);
- }
- throw new ItemStateException("Error saving " + state.getId(), he);
- } finally {
- if (session != null) {
- try {
- session.close();
- } catch (HibernateException he) {
- throw new ItemStateException(
- "Error while closing hibernate session", he);
- }
- }
- }
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.AbstractPersistenceManager#store(NodeReferences)
- */
- public void store(NodeReferences refs) throws ItemStateException {
- Iterator nodeRefPropIdIter = refs.getReferences().iterator();
- log.debug("Request to store node references for targetId=" +
- refs.getTargetId());
- Session session = null;
- Transaction tx = null;
- try {
- session = sessionFactory.openSession();
- tx = session.beginTransaction();
- int i = 0;
- while (nodeRefPropIdIter.hasNext()) {
- PropertyId curPropertyId = (PropertyId) nodeRefPropIdIter.next();
- ORMNodeReference curNodeReference = new ORMNodeReference(refs.
- getTargetId().toString(), curPropertyId.getParentUUID(),
- curPropertyId.getName().toString());
- session.save(curNodeReference);
- i++;
- if (i % 20 == 0) {
- session.flush();
- session.clear();
- }
- }
- tx.commit();
- } catch (HibernateException he) {
- try {
- if (tx != null)
- tx.rollback();
- } catch (HibernateException he2) {
- log.error("Error while rolling back transaction", he2);
- }
- throw new ItemStateException(
- "Error storing node references for targetId=" +
- refs.getTargetId(), he);
- } finally {
- if (session != null) {
- try {
- session.close();
- } catch (HibernateException he) {
- throw new ItemStateException(
- "Error while closing hibernate session", he);
- }
- }
- }
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.AbstractPersistenceManager#destroy(NodeState)
- */
- public void destroy(NodeState state) throws ItemStateException {
- log.debug("Deleting node " + state.getUUID());
- Session session = null;
- Transaction tx = null;
- try {
- session = sessionFactory.openSession();
- tx = session.beginTransaction();
- HibernateNodeState nodeState = null;
- try {
- List nodeList = session.find(
- "from org.apache.jackrabbit.core.state.orm.hibernate.HibernateNodeState as node WHERE " +
- "node.uuid = ?",
- new Object[] {state.getId().toString()},
- new Type[] {Hibernate.STRING});
-
- if (nodeList.size() != 1) {
- } else {
- nodeState = (HibernateNodeState) nodeList.get(0);
- session.delete(nodeState);
- }
- } catch (ObjectNotFoundException onfe) {
- }
- tx.commit();
- } catch (HibernateException he) {
- try {
- if (tx != null)
- tx.rollback();
- } catch (HibernateException he2) {
- log.error("Error while rolling back transaction", he2);
- }
- throw new ItemStateException("Error deleting " + state.getId(), he);
- } finally {
- if (session != null) {
- try {
- session.close();
- } catch (HibernateException he) {
- throw new ItemStateException(
- "Error while closing hibernate session", he);
- }
- }
- }
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.AbstractPersistenceManager#destroy(PropertyState)
- */
- public void destroy(PropertyState state) throws ItemStateException {
- log.debug("Deleting property " + state.getId());
- Session session = null;
- Transaction tx = null;
- try {
- session = sessionFactory.openSession();
- tx = session.beginTransaction();
- ORMPropertyState propState = null;
- try {
- List propertyList = session.find(
- "from org.apache.jackrabbit.core.state.orm.ORMPropertyState as prop WHERE " +
- "prop.itemId = ?",
- new Object[] {state.getId().toString()},
- new Type[] {Hibernate.STRING});
-
- if (propertyList.size() != 1) {
- } else {
- propState = (ORMPropertyState) propertyList.get(0);
- session.delete(propState);
- if (state.getType() == PropertyType.BINARY) {
- session.delete("from org.apache.jackrabbit.core.state.orm.ORMBlobValue as bv where bv.parentUUID=? AND bv.propertyName=?",
- new Object[] {state.getParentUUID(),
- state.getName().toString()},
- new Type[] {Hibernate.STRING,
- Hibernate.STRING});
- }
- }
- } catch (ObjectNotFoundException onfe) {
- }
- tx.commit();
- } catch (HibernateException he) {
- try {
- if (tx != null)
- tx.rollback();
- } catch (HibernateException he2) {
- log.error("Error while rolling back transaction", he2);
- }
- throw new ItemStateException("Error deleting " + state.getId(), he);
- } finally {
- if (session != null) {
- try {
- session.close();
- } catch (HibernateException he) {
- throw new ItemStateException(
- "Error while closing hibernate session", he);
- }
- }
- }
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.AbstractPersistenceManager#destroy(NodeReferences)
- */
- public void destroy(NodeReferences refs) throws ItemStateException {
- log.debug("Deleting node refences for targetId=" +
- refs.getTargetId().toString());
- Session session = null;
- Transaction tx = null;
- try {
- session = sessionFactory.openSession();
- tx = session.beginTransaction();
- session.delete("from org.apache.jackrabbit.core.state.orm.ORMNodeReference as nf where nf.targetId='" +
- refs.getTargetId().toString() +
- "'");
- refs.clearAllReferences();
- tx.commit();
- } catch (HibernateException he) {
- try {
- if (tx != null)
- tx.rollback();
- } catch (HibernateException he2) {
- log.error("Error while rolling back transaction", he2);
- }
- throw new ItemStateException(
- "Error deleting node references for targetId=" +
- refs.getTargetId().toString(), he);
- } finally {
- if (session != null) {
- try {
- session.close();
- } catch (HibernateException he) {
- throw new ItemStateException(
- "Error while closing hibernate session", he);
- }
- }
- }
- }
-
-}
diff --git a/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ojb/OJBNodeState.java b/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ojb/OJBNodeState.java
deleted file mode 100644
index 477eb4f053f..00000000000
--- a/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ojb/OJBNodeState.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.core.state.orm.ojb;
-
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.List;
-
-import org.apache.jackrabbit.core.ItemId;
-import org.apache.jackrabbit.core.state.NodeState;
-import org.apache.jackrabbit.core.state.orm.ORMNodeState;
-import org.apache.ojb.broker.util.collections.RemovalAwareList;
-
-/**
- *
OJB specific node state. In order to properly track list
- * modifications, we use an OJB specific list implementation.
- */
-public class OJBNodeState extends ORMNodeState implements Serializable {
-
- private List awareChildNodeEntries = new RemovalAwareList();
- private List awarePropertyEntries = new RemovalAwareList();
- private List awareMixinTypeNames = new RemovalAwareList();
- private List awareParentUUIDs = new RemovalAwareList();
-
- public OJBNodeState() {
- }
- public OJBNodeState(ItemId id) {
- super(id);
- }
- public OJBNodeState(NodeState state) {
- super();
- fromPersistentNodeState(state);
- }
- public Collection getChildNodeEntries() {
- return awareChildNodeEntries;
- }
- public void setChildNodeEntries(Collection childNodeEntries) {
- this.awareChildNodeEntries.clear();
- this.awareChildNodeEntries.addAll(childNodeEntries);
- }
-
- public List getAwareChildNodeEntries() {
- return awareChildNodeEntries;
- }
-
- public void setAwareChildNodeEntries(List awareChildNodeEntries) {
- this.awareChildNodeEntries = awareChildNodeEntries;
- }
-
- public Collection getPropertyEntries() {
- return awarePropertyEntries;
- }
-
- public Collection getMixinTypeNames() {
- return awareMixinTypeNames;
- }
-
- public Collection getParentUUIDs() {
- return awareParentUUIDs;
- }
-
- public void setPropertyEntries(Collection propertyEntries) {
- this.awarePropertyEntries.clear();
- this.awarePropertyEntries.addAll(propertyEntries);
- }
-
- public void setMixinTypeNames(Collection mixinTypeNames) {
- this.awareMixinTypeNames.clear();
- this.awareMixinTypeNames.addAll(mixinTypeNames);
- }
-
- public void setParentUUIDs(Collection parentUUIDs) {
- this.awareParentUUIDs.clear();
- this.awareParentUUIDs.addAll(parentUUIDs);
- }
-
-}
diff --git a/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ojb/OJBPersistenceManager.java b/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ojb/OJBPersistenceManager.java
deleted file mode 100644
index a2014968472..00000000000
--- a/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ojb/OJBPersistenceManager.java
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.core.state.orm.ojb;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.util.ArrayList;
-import java.util.Iterator;
-
-import javax.jcr.PropertyType;
-
-import org.apache.jackrabbit.core.BLOBFileValue;
-import org.apache.jackrabbit.core.InternalValue;
-import org.apache.jackrabbit.core.NodeId;
-import org.apache.jackrabbit.core.PropertyId;
-import org.apache.jackrabbit.core.QName;
-import org.apache.jackrabbit.core.state.ChangeLog;
-import org.apache.jackrabbit.core.state.ItemState;
-import org.apache.jackrabbit.core.state.ItemStateException;
-import org.apache.jackrabbit.core.state.NoSuchItemStateException;
-import org.apache.jackrabbit.core.state.NodeReferences;
-import org.apache.jackrabbit.core.state.NodeReferencesId;
-import org.apache.jackrabbit.core.state.NodeState;
-import org.apache.jackrabbit.core.state.PMContext;
-import org.apache.jackrabbit.core.state.PersistenceManager;
-import org.apache.jackrabbit.core.state.PropertyState;
-import org.apache.jackrabbit.core.state.orm.ORMBlobValue;
-import org.apache.jackrabbit.core.state.orm.ORMNodeReference;
-import org.apache.jackrabbit.core.state.orm.ORMPropertyState;
-import org.apache.log4j.Logger;
-import org.apache.ojb.broker.PersistenceBroker;
-import org.apache.ojb.broker.PersistenceBrokerException;
-import org.apache.ojb.broker.PersistenceBrokerFactory;
-import org.apache.ojb.broker.query.Criteria;
-import org.apache.ojb.broker.query.QueryByCriteria;
-import org.apache.ojb.broker.query.QueryByIdentity;
-
-/**
- * OJB implementation of a Jackrabbit persistence manager.
- */
-public class OJBPersistenceManager implements PersistenceManager
-{
-
- private static Logger log = Logger.getLogger(OJBPersistenceManager.class);
-
- private boolean initialized = false;
-
- public OJBPersistenceManager()
- {
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.PersistenceManager#init
- */
- public void init(PMContext context) throws Exception
- {
- // FIXME: A config param to set the broker name would be handy
- if (initialized)
- {
- throw new IllegalStateException("already initialized");
- }
- initialized = true;
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.PersistenceManager#close
- */
- public void close() throws Exception
- {
- // Nothing to do
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.PersistenceManager#load(NodeId)
- */
- public NodeState load(NodeId nodeId) throws NoSuchItemStateException,
- ItemStateException
- {
- PersistenceBroker broker = PersistenceBrokerFactory
- .defaultPersistenceBroker();
- try
- {
- log.debug("Request for " + nodeId.getUUID());
- OJBNodeState nodeState = new OJBNodeState();
- nodeState.setUuid(nodeId.getUUID());
- QueryByIdentity query = new QueryByIdentity(nodeState);
- OJBNodeState result = (OJBNodeState) broker.getObjectByQuery(query);
- if (result == null)
- {
- throw new NoSuchItemStateException(nodeId.getUUID());
- }
- NodeState state = createNew(nodeId);
- result.toPersistentNodeState(state);
- return state;
- } catch (PersistenceBrokerException e)
- {
- throw new ItemStateException(e);
- } finally
- {
- if (broker != null)
- broker.close();
- }
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.PersistenceManager#load(PropertyId)
- */
- public PropertyState load(PropertyId propId)
- throws NoSuchItemStateException, ItemStateException
- {
- PersistenceBroker broker = PersistenceBrokerFactory
- .defaultPersistenceBroker();
- try
- {
- log.debug("Request for property " + propId);
- ORMPropertyState propState = new ORMPropertyState(propId);
- QueryByIdentity query = new QueryByIdentity(propState);
- PropertyState state = createNew(propId);
- ORMPropertyState result = (ORMPropertyState) broker
- .getObjectByQuery(query);
- if (result == null)
- {
- throw new NoSuchItemStateException("Couldn't find property "
- + propId);
- }
- result.toPersistentPropertyState(state);
- if (result.getType().intValue() == PropertyType.BINARY)
- {
- // we must now load the binary values.
- ArrayList internalValueList = new ArrayList();
- Criteria criteria = new Criteria();
- criteria.addEqualTo("parentUUID", state.getParentUUID());
- criteria.addEqualTo("propertyName", state.getName().toString());
- QueryByCriteria blobQuery = new QueryByCriteria(
- ORMBlobValue.class, criteria);
- Iterator resultIter = broker.getCollectionByQuery(blobQuery)
- .iterator();
- while (resultIter.hasNext())
- {
- ORMBlobValue ormBlobValue = (ORMBlobValue) resultIter
- .next();
- ByteArrayInputStream in = new ByteArrayInputStream(
- ormBlobValue.getBlobValue());
- try
- {
- internalValueList.add(InternalValue.create(in));
- } catch (Throwable t)
- {
- throw new ItemStateException(
- "Error while trying to load blob value", t);
- }
- }
- state.setValues((InternalValue[]) internalValueList
- .toArray(new InternalValue[internalValueList.size()]));
- }
- return state;
- } catch (PersistenceBrokerException e)
- {
- throw new ItemStateException(e);
- } finally
- {
- if (broker != null)
- broker.close();
- }
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.PersistenceManager#load(NodeReferencesId)
- */
- public NodeReferences load(NodeReferencesId targetId)
- throws NoSuchItemStateException, ItemStateException
- {
- PersistenceBroker broker = PersistenceBrokerFactory
- .defaultPersistenceBroker();
- try
- {
- ORMNodeReference nodeRef = new ORMNodeReference();
- nodeRef.setTargetId(targetId.toString());
- QueryByCriteria query = new QueryByCriteria(nodeRef);
- Iterator resultIter = broker.getCollectionByQuery(query).iterator();
- NodeReferences refs = new NodeReferences(targetId);
- while (resultIter.hasNext())
- {
- ORMNodeReference curNodeReference = (ORMNodeReference) resultIter
- .next();
- refs.addReference(new PropertyId(curNodeReference
- .getPropertyParentUUID(), QName
- .valueOf(curNodeReference.getPropertyName())));
- }
- return refs;
- } catch (PersistenceBrokerException e)
- {
- throw new ItemStateException(e);
- } finally
- {
- if (broker != null)
- broker.close();
- }
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.PersistenceManager#exists(NodeId)
- */
- public boolean exists(NodeId id) throws ItemStateException
- {
- PersistenceBroker broker = PersistenceBrokerFactory
- .defaultPersistenceBroker();
- try
- {
- OJBNodeState nodeState = new OJBNodeState(id);
- QueryByIdentity query = new QueryByIdentity(nodeState);
- OJBNodeState result = (OJBNodeState) broker.getObjectByQuery(query);
- if (result == null)
- {
- return false;
- } else
- {
- return true;
- }
- } catch (PersistenceBrokerException e)
- {
- throw new ItemStateException(e);
- } finally
- {
- if (broker != null)
- broker.close();
- }
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.PersistenceManager#exists(PropertyId)
- */
- public boolean exists(PropertyId id) throws ItemStateException
- {
- PersistenceBroker broker = PersistenceBrokerFactory
- .defaultPersistenceBroker();
- try
- {
- ORMPropertyState propState = new ORMPropertyState(id);
- // QueryByCriteria query = new QueryByCriteria(propState);
- QueryByIdentity query = new QueryByIdentity(propState);
- ORMPropertyState result = (ORMPropertyState) broker
- .getObjectByQuery(query);
- if (result == null)
- {
- return false;
- } else
- {
- return true;
- }
- } catch (PersistenceBrokerException e)
- {
- throw new ItemStateException(e);
- } finally
- {
- if (broker != null)
- broker.close();
- }
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.PersistenceManager#exists(NodeReferencesId)
- */
- public boolean exists(NodeReferencesId targetId) throws ItemStateException
- {
- PersistenceBroker broker = PersistenceBrokerFactory
- .defaultPersistenceBroker();
- try
- {
-
- ORMNodeReference nodeRef = new ORMNodeReference();
- nodeRef.setTargetId(targetId.toString());
- QueryByCriteria query = new QueryByCriteria(nodeRef);
- Iterator resultIter = broker.getCollectionByQuery(query).iterator();
- NodeReferences refs = new NodeReferences(targetId);
- if (resultIter.hasNext())
- {
- return true;
- }
- return false;
- } catch (PersistenceBrokerException e)
- {
- throw new ItemStateException(e);
- } finally
- {
- if (broker != null)
- broker.close();
- }
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.AbstractPersistenceManager#store(NodeState)
- */
- private void store(NodeState state, PersistenceBroker broker)
- throws ItemStateException
- {
- log.debug("Request to store node " + state.getId());
- OJBNodeState nodeState = new OJBNodeState(state.getId());
- QueryByIdentity query = new QueryByIdentity(nodeState);
- OJBNodeState result = (OJBNodeState) broker.getObjectByQuery(query);
- if (result == null)
- {
- result = new OJBNodeState();
- }
- result.fromPersistentNodeState(state);
- broker.store(result);
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.AbstractPersistenceManager#store(PropertyState)
- */
- private void store(PropertyState state, PersistenceBroker broker)
- throws ItemStateException
- {
- log.debug("Request to store property " + state.getId());
- ORMPropertyState propState = new ORMPropertyState(state.getId());
- QueryByIdentity query = new QueryByIdentity(propState);
- ORMPropertyState result = (ORMPropertyState) broker
- .getObjectByQuery(query);
- if (result == null)
- {
- result = new ORMPropertyState();
- }
- result.fromPersistentPropertyState(state);
-
- InternalValue[] values = state.getValues();
- if (values != null)
- {
- for (int i = 0; i < values.length; i++)
- {
- InternalValue val = values[i];
- if (val != null)
- {
- if (state.getType() == PropertyType.BINARY)
- {
- Criteria criteria = new Criteria();
- criteria
- .addEqualTo("parentUUID", state.getParentUUID());
- criteria.addEqualTo("propertyName", state.getName()
- .toString());
- criteria.addEqualTo("index", new Integer(i));
- QueryByCriteria blobQuery = new QueryByCriteria(
- ORMBlobValue.class, criteria);
- Iterator resultIter = broker.getCollectionByQuery(
- blobQuery).iterator();
- ORMBlobValue ormBlobValue = null;
- if (resultIter.hasNext())
- {
- ormBlobValue = (ORMBlobValue) resultIter.next();
- } else
- {
- ormBlobValue = new ORMBlobValue();
- ormBlobValue.setParentUUID(state.getParentUUID());
- ormBlobValue.setPropertyName(state.getName()
- .toString());
- ormBlobValue.setIndex(new Integer(i));
- }
- BLOBFileValue blobVal = (BLOBFileValue) val
- .internalValue();
- result.setValues("");
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- try
- {
- blobVal.spool(out);
- } catch (Throwable t)
- {
- // The caller is responsible of aborting the
- // transaction
- // broker.abortTransaction();
- throw new ItemStateException(t.getMessage(), t);
- }
- ormBlobValue.setSize(new Long(blobVal.getLength()));
- ormBlobValue.setBlobValue(out.toByteArray());
- broker.store(ormBlobValue);
- }
- }
- }
- }
- broker.store(result);
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.AbstractPersistenceManager#store(NodeReferences)
- */
- private void store(NodeReferences refs, PersistenceBroker broker)
- throws ItemStateException
- {
- // destroy all the references before saving
- destroy(refs, broker);
-
- Iterator nodeRefPropIdIter = refs.getReferences().iterator();
- while (nodeRefPropIdIter.hasNext())
- {
- PropertyId curPropertyId = (PropertyId) nodeRefPropIdIter.next();
- ORMNodeReference curNodeReference = new ORMNodeReference(refs
- .getTargetId().toString(), curPropertyId.getParentUUID(),
- curPropertyId.getName().toString());
- broker.store(curNodeReference);
- }
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.AbstractPersistenceManager#destroy(NodeState)
- */
- private void destroy(NodeState state, PersistenceBroker broker)
- throws ItemStateException
- {
- log.debug("Deleting node " + state.getId());
-
- // Destroy node
- OJBNodeState nodeState = new OJBNodeState(state.getId());
- QueryByIdentity query = new QueryByIdentity(nodeState);
- OJBNodeState result = (OJBNodeState) broker.getObjectByQuery(query);
- if (result == null)
- {
- result = new OJBNodeState();
- }
- broker.delete(result);
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.AbstractPersistenceManager#destroy(PropertyState)
- */
- private void destroy(PropertyState state, PersistenceBroker broker)
- throws ItemStateException
- {
- ORMPropertyState propState = new ORMPropertyState(state);
- broker.delete(propState);
- if (state.getType() == PropertyType.BINARY)
- {
- Criteria criteria = new Criteria();
- criteria.addEqualTo("parentUUID", state.getParentUUID());
- criteria.addEqualTo("propertyName", state.getName().toString());
- QueryByCriteria blobQuery = new QueryByCriteria(ORMBlobValue.class,
- criteria);
- broker.deleteByQuery(blobQuery);
- }
- }
-
- /**
- * @see org.apache.jackrabbit.core.state.AbstractPersistenceManager#destroy(NodeReferences)
- */
- private void destroy(NodeReferences refs, PersistenceBroker broker)
- throws ItemStateException
- {
- ORMNodeReference nodeRef = new ORMNodeReference();
- nodeRef.setTargetId(refs.getTargetId().toString());
- QueryByCriteria query = new QueryByCriteria(nodeRef);
- Iterator resultIter = broker.getCollectionByQuery(query).iterator();
- while (resultIter.hasNext())
- {
- ORMNodeReference curNodeReference = (ORMNodeReference) resultIter
- .next();
- broker.delete(curNodeReference);
- }
- }
-
- /**
- * @see PersistenceManager#createNew
- */
- public NodeState createNew(NodeId id)
- {
- return new NodeState(id.getUUID(), null, null, NodeState.STATUS_NEW,
- false);
- }
-
- /**
- * @see PersistenceManager#createNew
- */
- public PropertyState createNew(PropertyId id)
- {
- return new PropertyState(id.getName(), id.getParentUUID(),
- PropertyState.STATUS_NEW, false);
- }
-
- /**
- * @see PersistenceManager#store(ChangeLog)
- *
- * This method ensures that changes are either written completely to the
- * underlying persistence layer, or not at all.
- */
- public void store(ChangeLog changeLog) throws ItemStateException
- {
- PersistenceBroker broker = PersistenceBrokerFactory
- .defaultPersistenceBroker();
- try
- {
- broker.beginTransaction() ;
- Iterator iter = changeLog.deletedStates();
- while (iter.hasNext())
- {
- ItemState state = (ItemState) iter.next();
- if (state.isNode())
- {
- destroy((NodeState) state, broker);
- } else
- {
- destroy((PropertyState) state, broker);
- }
- }
- iter = changeLog.addedStates();
- while (iter.hasNext())
- {
- ItemState state = (ItemState) iter.next();
- if (state.isNode())
- {
- store((NodeState) state, broker);
- } else
- {
- store((PropertyState) state, broker);
- }
- }
- iter = changeLog.modifiedStates();
- while (iter.hasNext())
- {
- ItemState state = (ItemState) iter.next();
- if (state.isNode())
- {
- store((NodeState) state, broker);
- } else
- {
- store((PropertyState) state, broker);
- }
- }
- iter = changeLog.modifiedRefs();
- while (iter.hasNext())
- {
- NodeReferences refs = (NodeReferences) iter.next();
- if (refs.hasReferences())
- {
- store(refs, broker);
- } else
- {
- destroy(refs, broker);
- }
- }
- broker.commitTransaction() ;
- } catch (ItemStateException e)
- {
- if (broker != null)
- broker.abortTransaction();
- throw e;
- } catch (PersistenceBrokerException e)
- {
- if (broker != null)
- broker.abortTransaction();
- throw new ItemStateException("Unable to store", e);
- } finally
- {
- if (broker != null)
- broker.close();
- }
-
- }
-
-}
diff --git a/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ojb/ValuesToStringFieldConversion.java b/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ojb/ValuesToStringFieldConversion.java
deleted file mode 100644
index 93594c2e8be..00000000000
--- a/contrib/orm-persistence/src/java/org/apache/jackrabbit/core/state/orm/ojb/ValuesToStringFieldConversion.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.core.state.orm.ojb;
-
-import java.util.ArrayList;
-import java.util.StringTokenizer;
-
-import org.apache.jackrabbit.core.InternalValue;
-import org.apache.ojb.broker.accesslayer.conversions.ConversionException;
-import org.apache.ojb.broker.accesslayer.conversions.FieldConversion;
-
-/**
- *
Helper class to convert multi-valued properties into an encoded
- * string stored in a single database column.
- */
-public class ValuesToStringFieldConversion
- implements FieldConversion {
-
- private int type;
-
- public ValuesToStringFieldConversion() {
- }
-
- public ValuesToStringFieldConversion(int type) {
- this.type = type;
- }
-
- public Object javaToSql(Object object) throws ConversionException {
- InternalValue[] values = (InternalValue[]) object;
- StringBuffer buffer = new StringBuffer();
- for (int i=0; i < values.length; i++) {
- buffer.append(values[i].toString());
- if (i < values.length - 1) {
- buffer.append(",");
- }
- }
- return buffer.toString();
- }
-
- public Object sqlToJava(Object object) throws ConversionException {
- ArrayList valueList = new ArrayList();
- StringTokenizer tokenizer = new StringTokenizer((String) object, ",");
- while (tokenizer.hasMoreTokens()) {
- InternalValue curValue = InternalValue.valueOf(tokenizer.nextToken(), type);
- valueList.add(curValue);
- }
- return (InternalValue[]) valueList.toArray(new InternalValue[valueList.size()]);
- }
-}
diff --git a/contrib/orm-persistence/src/test/org/apache/jackrabbit/test/orm/BlobTest.java b/contrib/orm-persistence/src/test/org/apache/jackrabbit/test/orm/BlobTest.java
deleted file mode 100644
index 05ad50d2931..00000000000
--- a/contrib/orm-persistence/src/test/org/apache/jackrabbit/test/orm/BlobTest.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.test.orm;
-
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import java.io.InputStream;
-import javax.jcr.StringValue;
-import java.io.ByteArrayInputStream;
-import java.io.BufferedInputStream;
-
-import org.apache.jackrabbit.test.AbstractJCRTest;
-
-/**
- * BLOB insertion/retrieval test case.
- */
-public class BlobTest extends AbstractJCRTest {
-
- private final static int BLOB_SIZE = 1*1024*1024;
- byte[] blobContent = new byte[BLOB_SIZE];
-
- public BlobTest() {
- }
-
- public void testBlob() throws Exception {
- Node rn = superuser.getRootNode();
-
- NodeIterator nodeIter = rn.getNodes();
- while (nodeIter.hasNext()) {
- Node curNode = nodeIter.nextNode();
- }
-
- log.println("Creating BLOB data of " + BLOB_SIZE + " bytes...");
- for (int i=0; i < BLOB_SIZE; i++) {
- blobContent[i] = (byte) (i % 256);
- }
- log.println("Adding BLOB node...");
- if (!rn.hasNode("blobnode")) {
- ByteArrayInputStream inputStream = new ByteArrayInputStream(blobContent);
- Node n = rn.addNode("blobnode", "nt:unstructured");
- n.setProperty("testprop", new StringValue("Hello, World."));
- n.setProperty("blobTest", inputStream);
- superuser.save();
- }
- log.println("Verifying BLOB node...");
- InputStream readInputStream = rn.getProperty("blobnode/blobTest").
- getStream();
- int ch = -1;
- int i=0;
- BufferedInputStream buf = new BufferedInputStream(readInputStream);
- while ((ch = buf.read()) != -1) {
- assertEquals((byte) ch, blobContent[i]);
- i++;
- }
- log.println("Removing BLOB node...");
- rn.getNode("blobnode").remove();
- superuser.save();
- }
-
-}
diff --git a/contrib/orm-persistence/src/test/org/apache/jackrabbit/test/orm/TestAll.java b/contrib/orm-persistence/src/test/org/apache/jackrabbit/test/orm/TestAll.java
deleted file mode 100644
index fc03d699e01..00000000000
--- a/contrib/orm-persistence/src/test/org/apache/jackrabbit/test/orm/TestAll.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.test.orm;
-
-import junit.framework.TestCase;
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-/**
- * Test suite that includes all testcases for the package
- * javax.jcr.
- */
-public class TestAll extends TestCase {
-
- /**
- * Returns a Test suite that executes all tests inside this
- * package.
- *
- * @return a Test suite that executes all tests inside this
- * package.
- */
- public static Test suite() {
- TestSuite suite = new TestSuite("Jackrabbit ORM persistence tests");
-
- suite.addTestSuite(BlobTest.class);
- suite.addTestSuite(XMLImportSpeedTest.class);
-
- return suite;
- }
-}
diff --git a/contrib/orm-persistence/src/test/org/apache/jackrabbit/test/orm/XMLImportSpeedTest.java b/contrib/orm-persistence/src/test/org/apache/jackrabbit/test/orm/XMLImportSpeedTest.java
deleted file mode 100644
index 0d76713d605..00000000000
--- a/contrib/orm-persistence/src/test/org/apache/jackrabbit/test/orm/XMLImportSpeedTest.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.test.orm;
-
-import java.io.FileInputStream;
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.Property;
-import javax.jcr.PropertyIterator;
-import javax.jcr.PropertyType;
-import javax.jcr.RepositoryException;
-import javax.jcr.Value;
-
-import org.apache.jackrabbit.test.AbstractJCRTest;
-import org.dom4j.Document;
-import org.dom4j.Element;
-import org.dom4j.io.SAXReader;
-
-/**
- * Test suite for XML import speed benchmarking.
- */
-public class XMLImportSpeedTest extends AbstractJCRTest {
-
- private static final int BLOB_NODE_COUNT = 2;
- private static final int XML_IMPORT_NODE_COUNT = 1;
-
- private final String XML_IMPORT_FILENAME = "applications/test/import.xml";
-
- private int totalNodeCount = 0;
- private int totalElementCount = 0;
- private int totalAttributeCount = 0;
-
- public void treeWalk(Document document) {
- treeWalk(document.getRootElement());
- }
-
- public void treeWalk(Element element) {
- totalElementCount++;
- totalAttributeCount += element.attributeCount();
- for (int i = 0, size = element.nodeCount(); i < size; i++) {
- totalNodeCount++;
- org.dom4j.Node node = element.node(i);
- if (node instanceof Element) {
- treeWalk( (Element) node);
- } else {
- // do something....
- }
- }
- }
-
- public void testXMLImportSpeed() throws Exception {
- Node rn = superuser.getRootNode();
-
- if (!rn.hasNode("importxml0")) {
- log.println("importing xml");
-
- SAXReader reader = new SAXReader();
- Document document = reader.read(new FileInputStream(
- XML_IMPORT_FILENAME));
- treeWalk(document);
- log.println("XML file " + XML_IMPORT_FILENAME + " has " +
- totalElementCount + " elements, " + totalNodeCount +
- " nodes and " + totalAttributeCount +
- " attributes");
-
- log.println("Now performing XML import " +
- XML_IMPORT_NODE_COUNT +
- " time(s)...");
- long xmlImportTestStart = System.currentTimeMillis();
- for (int i = 0; i < XML_IMPORT_NODE_COUNT; i++) {
- Node nl = rn.addNode("importxml" + i, "nt:unstructured");
- superuser.importXML("/importxml" + i,
- new FileInputStream(
- XML_IMPORT_FILENAME));
- log.println("Saving...");
- superuser.save();
- }
- long xmlImportTestTime = System.currentTimeMillis() -
- xmlImportTestStart;
- log.println("Imported XML " + XML_IMPORT_NODE_COUNT +
- " time(s) in " +
- xmlImportTestTime + "ms average=" +
- xmlImportTestTime / XML_IMPORT_NODE_COUNT +
- "ms/node");
-
- log.println("Removing imported node(s)...");
- for (int i = 0; i < XML_IMPORT_NODE_COUNT; i++) {
- Node curXMLImportNode = rn.getNode("importxml" + i);
- curXMLImportNode.remove();
- }
- superuser.save();
- } else {
- log.println(
- "XML import has already been run previously, not reimporting on same nodes");
- }
-
- // dump(rn);
-
- }
-
- public void dump(Node n) throws RepositoryException {
- log.println(n.getPath());
- PropertyIterator pit = n.getProperties();
- while (pit.hasNext()) {
- Property p = pit.nextProperty();
- if (!p.getDefinition().isMultiple()) {
- Value curValue = p.getValue();
- if (curValue.getType() == PropertyType.BINARY) {
- log.println(p.getPath() + "=BINARY[" + p.getLength() + "]");
- } else {
- log.println(p.getPath() + "=" + p.getString());
- }
- } else {
- log.println("Multi-value for " + p.getPath());
- }
- }
- NodeIterator nit = n.getNodes();
- while (nit.hasNext()) {
- Node cn = nit.nextNode();
- dump(cn);
- }
- }
-
-}
diff --git a/contrib/tck-webapp/maven.xml b/contrib/tck-webapp/maven.xml
deleted file mode 100644
index b9df7ca37aa..00000000000
--- a/contrib/tck-webapp/maven.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/contrib/tck-webapp/project.properties b/contrib/tck-webapp/project.properties
deleted file mode 100644
index 502c15b8254..00000000000
--- a/contrib/tck-webapp/project.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-# ------------------------------------------------------------------------
-maven.repo.remote = http://www.ibiblio.org/maven/,http://www.day.com/maven/
-maven.test.skip = true
-
-
diff --git a/contrib/tck-webapp/project.xml b/contrib/tck-webapp/project.xml
deleted file mode 100644
index d2742df27b9..00000000000
--- a/contrib/tck-webapp/project.xml
+++ /dev/null
@@ -1,166 +0,0 @@
-
-
-
-
-
-
- tck-webapp
-
- Day TCK web application
- 0.1
-
-
-
-
-
-
-
-
-
- concurrent
- 1.3.4
-
- true
-
-
-
- commons-collections
- 2.1
-
- true
-
-
-
- lucene
- lucene
- 1.4.3
-
- true
-
-
-
- xerces
- xercesImpl
- 2.6.2
-
- true
-
-
-
-
-
- jsr170
- jcr
- 0.16.2
- http://www.day.com/maven/jsr170/jars/jcr-0.16.2.jar
-
-
-
- jackrabbit
- 0.16.2-dev
-
- true
-
-
-
-
- cqfs
- cqfs-jackrabbit
- 3.5.6
- http://www.day.com/maven/cqfs/jars/cqfs-jackrabbit-3.5.6.jar
-
- true
-
-
-
-
- cqfs
- 3.5.6
-
- true
-
-
-
- commons-logging
- 1.0
-
- true
-
-
-
-
-
-
- jdom
- 1.0
-
- true
-
-
-
- log4j
- 1.2.8
-
- true
-
-
-
-
-
-
- servletapi
- 2.3
-
-
- junit
- 3.8.1
-
- true
-
-
-
-
-
-
-
-
-
- ${basedir}/src/java
-
-
- fakeClass
-
- **/test/observation/*.java
- **/test/search/*.java
-
-
-
-
-
- src/java
-
- **/api/**/*.java
- **/*.xml
- **/*.xsd
- **/*.properties
- **/*.dtd
-
-
-
-
-
diff --git a/contrib/tck-webapp/src/java/org/apache/jackrabbit/tck/TckHelper.java b/contrib/tck-webapp/src/java/org/apache/jackrabbit/tck/TckHelper.java
deleted file mode 100644
index 33360848a71..00000000000
--- a/contrib/tck-webapp/src/java/org/apache/jackrabbit/tck/TckHelper.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.tck;
-
-/**
- * Just a helper class
- */
-public class TckHelper {
- public static String getStatus(int state) {
- String status = "UNDEFINED";
-
- switch (state) {
- case TestResult.SUCCESS:
- status = "SUCCESS";
- break;
- case TestResult.ERROR:
- status = "ERROR";
- break;
- case TestResult.FAILURE:
- status = "FAILURE";
- }
- return status;
- }
-}
diff --git a/contrib/tck-webapp/src/java/org/apache/jackrabbit/tck/TckTestRunner.java b/contrib/tck-webapp/src/java/org/apache/jackrabbit/tck/TckTestRunner.java
deleted file mode 100644
index 821190eea70..00000000000
--- a/contrib/tck-webapp/src/java/org/apache/jackrabbit/tck/TckTestRunner.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.tck;
-
-import junit.framework.Test;
-import junit.runner.BaseTestRunner;
-import javax.servlet.jsp.JspWriter;
-import java.io.IOException;
-import java.io.Writer;
-import java.util.Map;
-import java.util.HashMap;
-import java.text.MessageFormat;
-
-import org.apache.jackrabbit.test.NotExecutableException;
-
-/**
- * The TckTestRunner class implements the TestListener interface.
- */
-public class TckTestRunner extends BaseTestRunner {
- /** Test state */
- int state;
-
- /** The test */
- Test test;
-
- /** the writer */
- Writer writer;
-
- /*** contains all results from all tests */
- Map results;
-
- /** test start time */
- long startTime;
-
- /** time that a test took */
- long testTime;
-
- /** Result of a test */
- TestResult result;
-
- /** String containing defined log output */
- private String logString;
-
- /** String containing defined interaction output */
- private String interactionString;
-
- /** current testclass */
- private String currentTestClass;
-
- /** new test identifier string */
- private String newTestString;
-
- /**
- * The constructor inits the result map and sets the writer
- *
- * @param writer
- */
- public TckTestRunner(JspWriter writer) {
- this.writer = writer;
- results = new HashMap();
- currentTestClass = "";
- }
-
- /**
- * This method is called everytime a test is executed.
- * The result object is "reset". the state is "reset" to its default value.
- * The startTime is set.
- *
- * @param test The Test which will be executed
- */
- public synchronized void startTest(Test test) {
- result = new TestResult();
- state = TestResult.SUCCESS;
- startTime = System.currentTimeMillis();
- }
-
- /**
- * The test could not be started. This should not happen...
- *
- * @param message error message
- */
- protected void runFailed(String message) {
- String msg = "RUN FAILED:" + message;
- write(msg, false);
- }
-
- /**
- * This method is called everytime a test is finished. it does not matter if the
- * test was successful or not. The TestResult is added to the results list.
- *
- * @param test the current Test
- */
- public synchronized void endTest(Test test) {
- testTime = System.currentTimeMillis() - startTime;
- result.setTest(test);
- result.setTestTime(testTime);
- result.setStatus(state);
- results.put(test.toString(), result);
- if (!currentTestClass.equals(test.getClass().getName())) {
- currentTestClass = test.getClass().getName();
- write(test.toString(), true);
- } else {
- write(test.toString(), false);
- }
- }
-
- /**
- * This method is called when a Test failed.
- * The "error" code is passed:
- *
- an error occured while testing
- *
- the test failed
- * And the Throwable object with the information why the test failed is passed as well.
- *
- * @param status "error" code
- * @param test current Test
- * @param t Throwable of error/failure
- */
- public void testFailed(int status, Test test, Throwable t) {
- if (t instanceof NotExecutableException) {
- state = TestResult.NOT_EXECUTABLE;
- } else {
- state = status;
- }
- result.setErrorMsg(t.toString());
- }
-
- /**
- * Writes test logging information to output
- *
- * @param msg
- */
- private void write(String msg, boolean newTestClass) {
- if (writer != null) {
- try {
- String html = "";
- if (logString!= null && !"".equals(logString)) {
- html = MessageFormat.format(logString, new String[]{msg, TckHelper.getStatus(state)});
- writer.write(html);
- }
-
- String color;
- switch (state) {
- case TestResult.SUCCESS:
- color = "pass";
- break;
- case TestResult.ERROR:
- case TestResult.FAILURE:
- color = "failure";
- break;
- case TestResult.NOT_EXECUTABLE:
- color = "error";
- break;
- default:
- color = "clear";
- }
-
- if (interactionString!= null && !"".equals(interactionString)) {
- html = MessageFormat.format(interactionString, new String[]{msg, color, String.valueOf(testTime)});
- if (newTestClass) {
- html += newTestString;
- }
- writer.write(html);
- }
- writer.flush();
- } catch (IOException e) {
- // ignore
- }
- } else {
- System.out.println(msg);
- }
- }
-
- /**
- * Returns all results
- * @return all test results
- */
- public Map getResults() {
- return results;
- }
-
- public void setLogString(String logString) {
- this.logString = logString;
- }
-
- public void setInteractionString(String interactionString) {
- this.interactionString = interactionString;
- }
-
- public void setNewTestString(String newTestString) {
- this.newTestString = newTestString;
- }
-
- public void testStarted(String testName) {
- }
-
- public void testEnded(String testName) {
- }
-}
-
diff --git a/contrib/tck-webapp/src/java/org/apache/jackrabbit/tck/TestFinder.java b/contrib/tck-webapp/src/java/org/apache/jackrabbit/tck/TestFinder.java
deleted file mode 100644
index 9239f263d34..00000000000
--- a/contrib/tck-webapp/src/java/org/apache/jackrabbit/tck/TestFinder.java
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.tck;
-
-import junit.framework.TestSuite;
-import junit.framework.Test;
-import java.io.*;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.*;
-
-/**
- * The TestFinder class is responsible to find all TestCases which are
- * in a jar. The information which jar has to be searched is passed in the constructor.
- */
-public class TestFinder {
- /** Jar file to search the test classes */
- private JarFile jarFile;
-
- /** all tests */
- private Map allTests;
-
- /** all test suites */
- private Map suites;
-
- /**
- * The path where the jar containing the test classes and its sources is residing is passed here.
- *
- * @throws IOException
- */
- public TestFinder() throws IOException {
- allTests = new HashMap();
- suites = new HashMap();
- }
-
- /**
- * This method searches all tests.
- *
- * @param exclude file(class) name (e.g. allTests) of tests which should be excluded.
- * @param in InputStream of jar file containing the test class sources
- * @throws IOException
- * @throws ClassNotFoundException
- */
- public void find(InputStream in, String exclude) throws IOException, ClassNotFoundException {
- File tmpFile = null;
- try {
- // save to a temp file
- tmpFile = File.createTempFile("tck-tests", "jar");
- OutputStream out = null;
- try {
- out = new FileOutputStream(tmpFile);
- byte[] buf = new byte[1024];
- int len;
- while ((len = in.read(buf)) > 0) {
- out.write(buf, 0, len);
- }
- } finally {
- in.close();
- out.close();
- }
-
- jarFile = new JarFile(tmpFile);
-
- // go through all jar file entries and take the one we are interessted in.
- Enumeration enum = jarFile.entries();
-
- while (enum.hasMoreElements()) {
- JarEntry entry = (JarEntry) enum.nextElement();
- String name = entry.getName();
-
- if (!entry.isDirectory() && name.endsWith(".java")) {
- // only source files are from interesst
- String classname = name.replace('/','.').substring(0, name.lastIndexOf(".java"));
-
- Class testclass = Class.forName(classname);
-
- // check if class is really a testsuite
- if (!isTestSuite(testclass)) {
- continue;
- }
-
- // check for files to be excluded
- if (name.endsWith(exclude)) {
- continue;
- }
-
- // retrieve keyword from source file
- String keyword = getKeyword(entry);
-
- // classify testsuite (level1, level2,...)
- if (suites.containsKey(keyword)) {
- TestSuite suite = (TestSuite) suites.get(keyword);
- suite.addTestSuite(testclass);
- } else {
- TestSuite suite = new TestSuite(keyword);
- suite.addTestSuite(testclass);
- suites.put(keyword, suite);
- }
-
- // memorize tests
- allTests.put(classname, keyword);
- }
- }
- } finally {
- if (tmpFile != null) {
- tmpFile.delete();
- }
- }
- }
-
- /**
- * Check if the passed test class is a "real" test suite
- *
- * @param testclass class to check
- * @return true if a test suite
- */
- private boolean isTestSuite(Class testclass) {
- TestSuite ts = new TestSuite(testclass);
- if (ts.countTestCases() > 0) {
- Test t = (Test) ts.tests().nextElement();
- if (t.toString().startsWith("warning")) {
- return false;
- }
- } else {
- return false;
- }
- return true;
- }
-
- /**
- * Reads the keyword from the java source.
- *
- * @param entry JarEntry to parse
- * @return returns the existing keyword or "unspecified"
- * @throws IOException
- */
- private String getKeyword(JarEntry entry) throws IOException {
- InputStream input = jarFile.getInputStream(entry);
- InputStreamReader isr = new InputStreamReader(input);
- BufferedReader reader = new BufferedReader(isr);
- String line;
- while ((line = reader.readLine()) != null) {
- String keyword = null;
- if ((keyword = parseLine(line)) != null) {
- return keyword;
- }
- }
- reader.close();
- return "unspecified";
- }
-
- /**
- * Parses a line and checks for the "keywords" keyword
- *
- * @param line line to parse
- * @return the kewyword string or null
- */
- private String parseLine(String line) {
- int pos = line.indexOf("keywords");
- int len = "keywords".length();
- String word = "";
-
- if ( pos >= 0) {
- char l[] = line.toCharArray();
- pos += len;
-
- while (pos < l.length) {
- char c = l[pos];
-
- switch (c) {
- case 9: // '\t'
- case 10: // '\n'
- case 12: // '\f'
- case 13: // '\r'
- case 32: // ' '
- if (!"".equals(word)) {
- return word;
- }
- break;
- default:
- word += c;
- }
- pos++;
- }
- }
- return ("".equals(word)) ? null : word;
- }
-
- /**
- * Returns all tests categorized by it's keyword
- * @return all tests
- */
- public Map getTests() {
- return allTests;
- }
-
- /**
- * Returns all built test suites. the suites are categorized:
- *
- level1
- *
- level 2
- *
- optional...
- *
- * @return test suites
- */
- public Map getSuites() {
- return suites;
- }
-}
\ No newline at end of file
diff --git a/contrib/tck-webapp/src/java/org/apache/jackrabbit/tck/TestResult.java b/contrib/tck-webapp/src/java/org/apache/jackrabbit/tck/TestResult.java
deleted file mode 100644
index 9c3153532f8..00000000000
--- a/contrib/tck-webapp/src/java/org/apache/jackrabbit/tck/TestResult.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.tck;
-
-import junit.framework.Test;
-
-/**
- * The TestResult class is just a helper class to store test results.
- */
-public class TestResult {
-
- /** Test succeeded */
- public static final int SUCCESS = 0;
-
- /** An error occured while testing */
- public static final int ERROR = 1;
-
- /** The test failed */
- public static final int FAILURE = 2;
-
- /** The test cannot be executed */
- public static final int NOT_EXECUTABLE = 4;
-
- /** The test */
- private Test test;
-
- /** Test status */
- private int status;
-
- /** Error message */
- private String errorMsg;
-
- /** Time that consumed while testing */
- private long testTime;
-
- public TestResult() {
- // do nothing
- }
-
- public long getTestTime() {
- return testTime;
- }
-
- public void setTestTime(long testTime) {
- this.testTime = testTime;
- }
-
- public Test getTest() {
- return test;
- }
-
- public void setTest(Test test) {
- this.test = test;
- }
-
- public int getStatus() {
- return status;
- }
-
- public void setStatus(int status) {
- this.status = status;
- }
-
- public String getErrorMsg() {
- return errorMsg;
- }
-
- public void setErrorMsg(String errorMsg) {
- this.errorMsg = errorMsg;
- }
-}
diff --git a/contrib/tck-webapp/src/java/org/apache/jackrabbit/tck/Tester.java b/contrib/tck-webapp/src/java/org/apache/jackrabbit/tck/Tester.java
deleted file mode 100644
index 5646330012d..00000000000
--- a/contrib/tck-webapp/src/java/org/apache/jackrabbit/tck/Tester.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.tck;
-
-import junit.framework.TestSuite;
-import junit.framework.TestResult;
-import javax.jcr.*;
-import javax.jcr.nodetype.ConstraintViolationException;
-import javax.servlet.jsp.JspWriter;
-import java.util.*;
-import java.io.IOException;
-import java.text.MessageFormat;
-
-import org.apache.jackrabbit.test.AbstractJCRTest;
-import org.apache.jackrabbit.test.RepositoryHelper;
-
-/**
- * The Tester starts the all tests and saves all tests.
- */
-public class Tester {
-
- /** Object containing all tests */
- TestFinder tests;
-
- /** all test results are stored here */
- Map results;
-
- /** the test listener */
- TckTestRunner runner;
-
- /** the jsp writer */
- JspWriter writer;
-
- /** The string to be writen after finishing a suite */
- String finishedSuiteString;
-
- /**
- * The constructor...
- *
- * @param tests All tests found using TestFinder
- */
- public Tester(TestFinder tests, TckTestRunner runner, JspWriter writer) {
- this.tests = tests;
- results = new HashMap();
- this.runner = runner;
- this.writer = writer;
-
- // set the configuration for the to be tested repository
- AbstractJCRTest.helper = new RepositoryHelper(WebAppTestConfig.getCurrentConfig());
- }
-
- /**
- * Calling this method starts the testing. All test results will be stored in the
- * results hashmap for further use.
- *
- * @return the result list (map)
- */
- public Map run() {
-
- // get suites (level1, level2, ...)
- Iterator suites = tests.getSuites().keySet().iterator();
-
- while (suites.hasNext()) {
- TestSuite suite = (TestSuite) tests.getSuites().get(suites.next());
-
- TestResult result = new TestResult();
- result.addListener(runner);
- try {
- suite.run(result);
- results.putAll(runner.getResults());
- write(suite);
- } catch (Exception e) {
- // ignore
- }
- }
- return results;
- }
-
-
- public void setfinishedSuiteString(String line) {
- finishedSuiteString = line;
- }
-
- /**
- * Writes a predefined string to the output after finishing a test suite
- */
- private void write(TestSuite suite) throws IOException {
- if (writer != null) {
- writer.write(MessageFormat.format(finishedSuiteString, new String[]{suite.toString(), String.valueOf(suite.testCount())}));
- }
- }
-
- /**
- * This method stores the result underneath the passed node in this structure:
- *
- * node
- * + suite name 1
- * + test 1
- * + test 2
- * ...
- * + suite name 2
- * + test a
- * + test b
- * ...
- * ....
- *
- * @param node parent Node for storage
- * @throws RepositoryException
- * @throws ConstraintViolationException
- * @throws InvalidItemStateException
- * @throws AccessDeniedException
- */
- public void storeResults(Node node) throws RepositoryException, ConstraintViolationException, InvalidItemStateException, AccessDeniedException {
- // create categories: level1, level2....
- Iterator keyItr = tests.getSuites().keySet().iterator();
- while (keyItr.hasNext()) {
- node.addNode((String) keyItr.next());
- }
-
- // save test results here
- Iterator itr = results.keySet().iterator();
- while (itr.hasNext()) {
- String key = (String) itr.next();
- org.apache.jackrabbit.tck.TestResult tr = (org.apache.jackrabbit.tck.TestResult) results.get(key);
- String className = tr.getTest().getClass().getName();
- String testName = key.substring(0, key.indexOf("("));
- String keyword = (String) tests.getTests().get(className);
- if (keyword != null) {
- Node testResNode = node.addNode(keyword + "/" + key);
- testResNode.setProperty("name", testName);
- testResNode.setProperty("status", tr.getStatus());
- if (tr.getErrorMsg() != null) {
- testResNode.setProperty("errrormsg", tr.getErrorMsg());
- }
- testResNode.setProperty("testtime", tr.getTestTime());
- }
- }
- node.save();
- }
-}
diff --git a/contrib/tck-webapp/src/java/org/apache/jackrabbit/tck/WebAppTestConfig.java b/contrib/tck-webapp/src/java/org/apache/jackrabbit/tck/WebAppTestConfig.java
deleted file mode 100644
index ac6fda65dee..00000000000
--- a/contrib/tck-webapp/src/java/org/apache/jackrabbit/tck/WebAppTestConfig.java
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.tck;
-
-import org.apache.jackrabbit.tck.j2ee.RepositoryServlet;
-import org.apache.jackrabbit.test.JNDIRepositoryStub;
-import org.apache.jackrabbit.test.RepositoryStub;
-
-import javax.jcr.*;
-import javax.servlet.http.HttpServletRequest;
-import java.util.*;
-import java.io.InputStream;
-import java.io.IOException;
-
-import junit.framework.TestSuite;
-import junit.framework.TestCase;
-
-
-/**
- * The WebAppTestConfig class reads and saves the config in the tck web app specific way.
- */
-public class WebAppTestConfig {
- /** default property names */
- public final static String[] propNames = {JNDIRepositoryStub.PROP_PREFIX + "." + JNDIRepositoryStub.PROP_WORKSPACE_NAME,
- JNDIRepositoryStub.REPOSITORY_LOOKUP_PROP,
- "java.naming.provider.url",
- "java.naming.factory.initial",
- JNDIRepositoryStub.PROP_PREFIX + "." + JNDIRepositoryStub.PROP_SUPERUSER_NAME,
- JNDIRepositoryStub.PROP_PREFIX + "." + JNDIRepositoryStub.PROP_SUPERUSER_PWD,
- JNDIRepositoryStub.PROP_PREFIX + "." + JNDIRepositoryStub.PROP_READWRITE_NAME,
- JNDIRepositoryStub.PROP_PREFIX + "." + JNDIRepositoryStub.PROP_READWRITE_PWD,
- JNDIRepositoryStub.PROP_PREFIX + "." + JNDIRepositoryStub.PROP_READONLY_NAME,
- JNDIRepositoryStub.PROP_PREFIX + "." + JNDIRepositoryStub.PROP_READONLY_PWD,
- JNDIRepositoryStub.PROP_PREFIX + "." + JNDIRepositoryStub.PROP_TESTROOT,
- JNDIRepositoryStub.PROP_PREFIX + "." + JNDIRepositoryStub.PROP_NODE_NAME1,
- JNDIRepositoryStub.PROP_PREFIX + "." + JNDIRepositoryStub.PROP_NODE_NAME2,
- JNDIRepositoryStub.PROP_PREFIX + "." + JNDIRepositoryStub.PROP_NODE_NAME3,
- JNDIRepositoryStub.PROP_PREFIX + "." + JNDIRepositoryStub.PROP_NODE_NAME4,
- JNDIRepositoryStub.PROP_PREFIX + "." + JNDIRepositoryStub.PROP_PROP_NAME1,
- JNDIRepositoryStub.PROP_PREFIX + "." + JNDIRepositoryStub.PROP_PROP_NAME2,
- JNDIRepositoryStub.PROP_PREFIX + "." + JNDIRepositoryStub.PROP_NAMESPACES,
- JNDIRepositoryStub.PROP_PREFIX + "." + JNDIRepositoryStub.PROP_NODETYPE};
-
- /**
- * Reads the config entries from the repository
- *
- * @return test config
- */
- public static Map getConfig() {
- Map config = new HashMap();
- try {
- Session repSession = RepositoryServlet.getSession();
- Node configNode = repSession.getRootNode().getNode("testconfig");
- PropertyIterator pitr = configNode.getProperties();
-
- while (pitr.hasNext()) {
- Property p = pitr.nextProperty();
- config.put(p.getName(), p.getString());
- }
- } catch (RepositoryException e) {
- return new HashMap();
- }
- return config;
- }
-
- /**
- * Reads the original config from the property file.
- *
- * @return original read only config
- */
- public static Map getOriConfig() {
- Properties props = new Properties();
- InputStream is = WebAppTestConfig.class.getClassLoader().getResourceAsStream(JNDIRepositoryStub.STUB_IMPL_PROPS);
- if (is != null) {
- try {
- props.load(is);
- } catch (IOException e) {
- // ignore
- }
- }
-
- // add additional props
- props.put(JNDIRepositoryStub.REPOSITORY_LOOKUP_PROP, "");
- props.put("java.naming.provider.url", "");
- props.put("java.naming.factory.initial", "");
-
- return props;
- }
-
- /**
- * Saves the configuration entries which needs to be set.
- *
- * @param request request with config changes
- * @param repSession Session used to write config
- * @throws RepositoryException
- */
- public static void save(HttpServletRequest request, Session repSession) throws RepositoryException {
- // create config node if not yet existing
- Node testConfig;
- if (repSession.getRootNode().hasNode("testconfig")) {
- testConfig = repSession.getRootNode().getNode("testconfig");
- } else {
- testConfig = repSession.getRootNode().addNode("testconfig", "nt:unstructured");
- repSession.getRootNode().save();
- }
-
- // save config entries
- Iterator allPropNames = getCurrentConfig().keySet().iterator();
-
- while (allPropNames.hasNext()) {
- String pName = (String) allPropNames.next();
- setEntry(pName, request, testConfig);
- }
-
- // save
- testConfig.save();
- }
-
- /**
- * This method saves a single property
- *
- * @param propName property name
- * @param propValue property value
- * @param repSession session
- * @throws RepositoryException
- */
- public static void saveProperty(String propName, String propValue, Session repSession) throws RepositoryException {
- // create config node if not yet existing
- Node testConfig;
- if (repSession.getRootNode().hasNode("testconfig")) {
- testConfig = repSession.getRootNode().getNode("testconfig");
- } else {
- testConfig = repSession.getRootNode().addNode("testconfig", "nt:unstructured");
- repSession.getRootNode().save();
- }
-
- testConfig.setProperty(propName, propValue);
-
- // save
- testConfig.save();
- }
-
- /**
- * Set config entry
- *
- * @param propname config property name
- * @param request request to read property value
- * @param testConfig test config Node
- * @throws RepositoryException
- */
- private static void setEntry(String propname, HttpServletRequest request, Node testConfig) throws RepositoryException {
- if (request.getParameter(propname) != null) {
- testConfig.setProperty(propname, request.getParameter(propname));
- }
- }
-
- /**
- * Returns all test case specific configuration entries
- *
- * @param suite test suite
- * @return all test case specific conf entries
- */
- public static Map getTestCaseSpecificConfigs(TestSuite suite) {
- Map currentConfig = getCurrentConfig();
- Map configs = new HashMap();
-
- // check for "package" defined props
- String pname = suite.getName();
- if ("versioning".equals(pname)) {
- pname = "version";
- }
- configs.putAll(getProperties(pname, currentConfig));
-
- Enumeration allTestClasses = suite.tests();
-
- while (allTestClasses.hasMoreElements()) {
- TestSuite aTest = (TestSuite) allTestClasses.nextElement();
- String name = aTest.getName();
- name = name.substring(name.lastIndexOf(".") + 1);
-
- // check for class defined props
- configs.putAll(getProperties(name, currentConfig));
-
- // goto methods
- Enumeration testMethods = aTest.tests();
-
- while (testMethods.hasMoreElements()) {
- TestCase tc = (TestCase) testMethods.nextElement();
- String methodname = tc.getName();
- String fullName = name + "." + methodname;
- configs.putAll(getProperties(fullName, currentConfig));
- }
- }
- return configs;
- }
-
- /**
- * Returns the current configuration
- * @return
- */
- public static Map getCurrentConfig() {
- Map conf = getOriConfig();
- conf.putAll(getConfig());
- return conf;
- }
-
- /**
- * Returns all properties which property name starts with "javax.jcr.tck." + name
- *
- * @param name property name "extension"
- * @param config configuration
- * @return all properties which apply the above mentioned rule
- */
- private static Map getProperties(String name, Map config) {
- Map props = new HashMap();
-
- String pname = RepositoryStub.PROP_PREFIX + "." + name;
-
- Iterator itr = config.keySet().iterator();
-
- while (itr.hasNext()) {
- String key = (String) itr.next();
- if (key.startsWith(pname)) {
- props.put(key, config.get(key));
- }
- }
- return props;
- }
-
- /**
- * Removes the custom config entries
- *
- * @throws RepositoryException
- */
- public static void resetConfiguration() throws RepositoryException {
- Session repSession = RepositoryServlet.getSession();
- if (repSession.getRootNode().hasNode("testconfig")) {
- repSession.getRootNode().getNode("testconfig").remove();
- }
- repSession.getRootNode().save();
- }
-}
diff --git a/contrib/tck-webapp/src/java/org/apache/jackrabbit/tck/j2ee/RepositoryServlet.java b/contrib/tck-webapp/src/java/org/apache/jackrabbit/tck/j2ee/RepositoryServlet.java
deleted file mode 100644
index 841e8de4eba..00000000000
--- a/contrib/tck-webapp/src/java/org/apache/jackrabbit/tck/j2ee/RepositoryServlet.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.tck.j2ee;
-
-import org.apache.log4j.PropertyConfigurator;
-import org.apache.log4j.Logger;
-import org.apache.jackrabbit.core.config.RepositoryConfig;
-import org.apache.jackrabbit.core.RepositoryImpl;
-import org.xml.sax.InputSource;
-
-import javax.servlet.http.HttpServlet;
-import javax.servlet.ServletException;
-import javax.jcr.*;
-import java.io.*;
-import java.util.Properties;
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * The RepositoryServlet connects (starts) to a jsr170 repository and
- * puts the reference into the application context
- */
-public class RepositoryServlet extends HttpServlet {
-
- /** the logger */
- private static Logger log;// = Logger.getLogger(RepositoryServlet.class);
-
- /** repository configuration path */
- public final static String INIT_PARAM_REPOSITORY_CONFIG = "repository-config";
-
- /** repository home */
- public final static String INIT_PARAM_REPOSITORY_HOME = "repository-home";
-
- /** repository name */
- public final static String INIT_PARAM_REPOSITORY_NAME = "repository-name";
-
- /** jaas configuration file path */
- public static final String JAAS_CONFIG_FILE = "jaas-config-file";
-
- /** user id name */
- public static final String USER_ID = "jcr-userid";
-
- /** user password name */
- public static final String USER_PASSWORD = "jcr-password";
-
- /** log4j config */
- public final static String PARAM_LOG4J_CONFIG = "log4j-config";
-
- /** the repository to read/write test results and config */
- private static RepositoryImpl repository;
-
- /** the user id */
- private static String uid;
-
- /** the password */
- private static String pw;
-
- /**
- * The init method starts the repository to read/write test results and configuration,
- * sets the jaas config and the user id and the user password
- *
- * @throws ServletException
- */
- public void init() throws ServletException {
- super.init();
-
- try {
- // setup log4j
- // todo: do correctly
- String log4jConfig = getServletConfig().getInitParameter(PARAM_LOG4J_CONFIG);
- InputStream in = getServletContext().getResourceAsStream(log4jConfig);
- if (in == null) {
- // try normal init
- PropertyConfigurator.configure(log4jConfig);
- } else {
- try {
- Properties log4jProperties = new Properties();
- log4jProperties.load(in);
- in.close();
- PropertyConfigurator.configure(log4jProperties);
- } catch (IOException e) {
- throw new ServletException("Unable to load log4jProperties: " + e.toString());
- }
- }
- log_info("RepositoryServlet initializing..");
-
- // setup home directory
- String repHome = getServletConfig().getInitParameter(INIT_PARAM_REPOSITORY_HOME);
- if (repHome == null) {
- log_info(INIT_PARAM_REPOSITORY_HOME + " missing.");
- throw new ServletException(INIT_PARAM_REPOSITORY_HOME + " missing.");
- }
- File repositoryHome;
- try {
- repositoryHome = new File(repHome).getCanonicalFile();
- } catch (IOException e) {
- log_info(INIT_PARAM_REPOSITORY_HOME + " invalid." + e.toString());
- throw new ServletException(INIT_PARAM_REPOSITORY_HOME + " invalid." + e.toString());
- }
- log_info(" repository-home = " + repositoryHome.getPath());
-
- // setup repository
- String repConfig = getServletConfig().getInitParameter(INIT_PARAM_REPOSITORY_CONFIG);
- if (repConfig == null) {
- log_info(INIT_PARAM_REPOSITORY_CONFIG + " missing.");
- throw new ServletException(INIT_PARAM_REPOSITORY_CONFIG + " missing.");
- }
- log_info(" repository-config = " + repConfig);
-
- in = getServletContext().getResourceAsStream(repConfig);
- if (in == null) {
- try {
- in = new FileInputStream(new File(repositoryHome, repConfig));
- } catch (FileNotFoundException e) {
- log_info(INIT_PARAM_REPOSITORY_CONFIG + " invalid." + e.toString());
- throw new ServletException(INIT_PARAM_REPOSITORY_CONFIG + " invalid." + e.toString());
- }
- }
-
- // get repository name
- String repositoryName = getServletConfig().getInitParameter(INIT_PARAM_REPOSITORY_NAME);
- if (repositoryName == null) {
- repositoryName = "default";
- }
- log_info(" repository-name = " + repositoryName);
-
- InputSource is = new InputSource(in);
- RepositoryConfig config = RepositoryConfig.create(is, repositoryHome.getPath());
- repository = RepositoryImpl.create(config);
-
- log_info("JSR170 RI Repository initialized.");
-
- // set jaas config file path
- String jaasConfigFile = getServletConfig().getInitParameter(JAAS_CONFIG_FILE);
- if (jaasConfigFile != null && !"".equals(jaasConfigFile)) {
- System.setProperty("java.security.auth.login.config", jaasConfigFile);
- log_info("JAAS config path set by the tck webapp. java.security.auth.login.config = " + jaasConfigFile);
- } else {
- log_info("No JAAS config path set by the tck webapp.");
- }
-
-
- // set user id and password to read/write test results and configuration
- uid = getServletConfig().getInitParameter(USER_ID);
- pw = getServletConfig().getInitParameter(USER_PASSWORD);
-
- } catch (RepositoryException e) {
- log_info("Unable to initialize repository: " + e.toString(), e);
- throw new ServletException("Unable to initialize repository: " + e.toString(), e);
- }
-
- }
-
- public void destroy() {
- super.destroy();
- log_info("RepositoryServlet shutting down...");
- }
-
- private void log_info(String msg) {
- if (log != null) {
- log.info(msg);
- } else {
- log(msg);
- }
- }
-
- private void log_info(String msg, Throwable t) {
- if (log != null) {
- log.info(msg, t);
- } else {
- log(msg, t);
- }
- }
- /**
- * Returns the JSR170 repository
- * @return a jsr170 repository
- */
- public static Repository getRepository() {
- return repository;
- }
-
- /**
- * Returns the jcr session
- *
- * @return
- */
- public static Session getSession() {
- try {
- return login();
- } catch (RepositoryException e) {
- log.error("Unable to retrieve session: " + e.toString());
- }
- return null;
- }
-
- /**
- * Logs in to the repository. The user to login is specified in the servlet config.
- * @throws RepositoryException
- */
- public static Session login()
- throws RepositoryException {
-
- // login
- Session repSession = repository.login(new SimpleCredentials(uid, pw.toCharArray()), null);
- return repSession;
- }
-
-}
diff --git a/contrib/tck-webapp/src/webapp/WEB-INF/classes/repositoryStubImpl.properties b/contrib/tck-webapp/src/webapp/WEB-INF/classes/repositoryStubImpl.properties
deleted file mode 100644
index 4887807befb..00000000000
--- a/contrib/tck-webapp/src/webapp/WEB-INF/classes/repositoryStubImpl.properties
+++ /dev/null
@@ -1,323 +0,0 @@
-#
-# This is the configuration file for the jackrabbit repository test stub.
-#
-
-# Stub implementation class
-javax.jcr.tck.repository_stub_impl=org.apache.jackrabbit.test.JNDIRepositoryStub
-
-# repository specific configuration
-org.apache.jackrabbit.repository.config=applications/test/repository.xml
-org.apache.jackrabbit.repository.name=repo
-org.apache.jackrabbit.repository.home=applications/test
-org.apache.jackrabbit.repository.jaas.config=applications/test/jaas.config
-
-# credential configuration
-javax.jcr.tck.superuser.name=superuser
-javax.jcr.tck.superuser.pwd=
-javax.jcr.tck.readwrite.name=user
-javax.jcr.tck.readwrite.pwd=
-javax.jcr.tck.readonly.name=anonymous
-javax.jcr.tck.readonly.pwd=
-
-# global test configuration
-javax.jcr.tck.testroot=/testroot
-javax.jcr.tck.nodetype=nt:unstructured
-javax.jcr.tck.nodename1=node1
-javax.jcr.tck.nodename2=node2
-javax.jcr.tck.nodename3=node3
-javax.jcr.tck.nodename4=node4
-javax.jcr.tck.propertyname1=prop1
-javax.jcr.tck.propertyname2=prop2
-javax.jcr.tck.workspacename=test
-
-# namespace configuration
-javax.jcr.tck.namespaces=test
-javax.jcr.tck.namespaces.test=http://www.apache.org/jackrabbit/test
-
-# sample for per test case config overriding
-# Test class: AddNodeText
-# Test method: testName
-javax.jcr.tck.AddNodeTest.testName.nodename1=myname
-
-# ==============================================================================
-# JAVAX.JCR CONFIGURATION
-# ==============================================================================
-
-# Test class: ItemDefTest
-javax.jcr.tck.ItemDefTest.testroot=/testdata
-
-# Test class: ItemReadMethodsTest
-javax.jcr.tck.ItemReadMethodsTest.testroot=/testdata
-
-# Test class: NodeReadMethodsTest
-javax.jcr.tck.NodeReadMethodsTest.testroot=/testdata
-
-# Test class: PropertyTypeTest
-javax.jcr.tck.PropertyTypeTest.testroot=/testdata
-
-# Test class: BinaryPropertyTest
-javax.jcr.tck.BinaryPropertyTest.testroot=/testdata
-
-# Test class: BooleanPropertyTest
-javax.jcr.tck.BooleanPropertyTest.testroot=/testdata
-
-# Test class: DatePropertyTest
-javax.jcr.tck.DatePropertyTest.testroot=/testdata
-
-# Test class: DoublePropertyTest
-javax.jcr.tck.DoublePropertyTest.testroot=/testdata
-
-# Test class: LongPropertyTest
-javax.jcr.tck.LongPropertyTest.testroot=/testdata
-
-# Test class: NamePropertyTest
-javax.jcr.tck.NamePropertyTest.testroot=/testdata
-
-# Test class: PathPropertyTest
-javax.jcr.tck.PathPropertyTest.testroot=/testdata
-
-# Test class: ReferencePropertyTest
-javax.jcr.tck.ReferencePropertyTest.testroot=/testdata
-
-# Test class: StringPropertyTest
-javax.jcr.tck.StringPropertyTest.testroot=/testdata
-
-# Test class: UndefinedPropertyTest
-javax.jcr.tck.UndefinedPropertyTest.testroot=/testdata
-
-# Test class: PropertyReadMethodsTest
-javax.jcr.tck.PropertyReadMethodsTest.testroot=/testdata
-
-# Test class: NodeIteratorTest
-javax.jcr.tck.NodeIteratorTest.testroot=/testdata
-
-# Test class: NodeDiscoveringNodeTypesTest
-javax.jcr.tck.NodeDiscoveringNodeTypesTest.testroot=/testdata
-
-# Test class: RepositoryDescriptorTest
-javax.jcr.tck.RepositoryDescriptorTest.testroot=/testdata
-
-# Test class: WorkspaceReadMethodsTest
-javax.jcr.tck.WorkspaceReadMethodsTest.testroot=/testdata
-
-# Test class: SessionReadMethodsTest
-javax.jcr.tck.SessionReadMethodsTest.testroot=/testdata
-
-# Test class: NamespaceRegistryReadMethodsTest
-javax.jcr.tck.NamespaceRegistryReadMethodsTest.testroot=/testdata
-
-# Test class: NamespaceRemappingTest
-javax.jcr.tck.NamespaceRemappingTest.testroot=/testdata
-
-# Test class: SessionTest
-# Test method: testMoveItemExistsException
-# nodetype that does not allow same name siblings
-javax.jcr.tck.SessionTest.testMoveItemExistsException.nodetype2=nt:folder
-# valid node type that can be added as child of nodetype2
-javax.jcr.tck.SessionTest.testMoveItemExistsException.nodetype3=nt:hierarchyNode
-
-# Test class: SessionTest
-# Test method: testSaveContstraintViolationException
-# nodetype that has a property that is mandatory but not autocreated
-javax.jcr.tck.SessionTest.testSaveContstraintViolationException.nodetype2=nt:file
-
-# Test class: SessionUUIDTest
-# node type that has a property of type PropertyType.REFERENCE
-javax.jcr.tck.SessionUUIDTest.nodetype=nt:unstructured
-# name of the property that is of type PropertyType.REFERENCE
-javax.jcr.tck.SessionUUIDTest.propertyname1=foobar
-# nodetype that has nodetype mix:referenceable assigned
-javax.jcr.tck.SessionUUIDTest.nodetype2=test:refTargetNode
-
-# Test class: SessionUUIDTest
-# Test method: testSaveMovedRefNode
-# name of the property that can be modified
-javax.jcr.tck.SessionUUIDTest.testSaveMovedRefNode.propertyname1=foobar
-
-# Test class: NodeTest
-# Test method: testAddNodeItemExistsException
-# nodetype that does not allow same name siblings and allows child nodes of
-# the same type
-javax.jcr.tck.NodeTest.testAddNodeItemExistsException.nodetype=nt:folder
-
-# Test class: NodeTest
-# Test method: testRemoveMandatoryNode
-# nodetype that has a mandatory child node definition
-javax.jcr.tck.NodeTest.testRemoveMandatoryNode.nodetype2=nt:file
-# nodetype of the mandatory child
-javax.jcr.tck.NodeTest.testRemoveMandatoryNode.nodetype3=nt:base
-# name of the mandatory node
-javax.jcr.tck.NodeTest.testRemoveMandatoryNode.nodename3=jcr:content
-
-# Test class: NodeTest
-# Test method: testSaveContstraintViolationException
-# nodetype that has a property that is mandatory but not autocreated
-javax.jcr.tck.NodeTest.testSaveContstraintViolationException.nodetype2=nt:file
-
-# Test class: NodeUUIDTest
-# node type that has a property of type PropertyType.REFERENCE
-javax.jcr.tck.NodeUUIDTest.nodetype=nt:unstructured
-# name of the property that is of type PropertyType.REFERENCE
-javax.jcr.tck.NodeUUIDTest.propertyname1=ref
-# nodetype that has nodetype mix:referenceable assigned
-javax.jcr.tck.NodeUUIDTest.nodetype2=test:refTargetNode
-
-# Test class: NodeUUIDTest
-# Test method: testSaveMovedRefNode
-# name of the property that can be modified
-javax.jcr.tck.NodeUUIDTest.testSaveMovedRefNode.propertyname1=foobar
-# nodetype that has nodetype mix:referenceable assigned
-
-# Test class: NodeOrderableChildNodesTest
-# nodetype that supports orderable child nodes
-javax.jcr.tck.NodeOrderableChildNodesTest.nodetype2=nt:unstructured
-# valid node type that can be added as child of nodetype 2
-javax.jcr.tck.NodeOrderableChildNodesTest.nodetype3=nt:unstructured
-
-# Test class: NodeOrderableChildNodesTest
-# Test method: testOrderBeforeUnsupportedRepositoryOperationException
-# nodetype that does not allow ordering of child nodes
-javax.jcr.tck.NodeOrderableChildNodesTest.testOrderBeforeUnsupportedRepositoryOperationException.nodetype2=nt:folder
-# valid node type that can be added as child of nodetype 2
-javax.jcr.tck.NodeOrderableChildNodesTest.testOrderBeforeUnsupportedRepositoryOperationException.nodetype3=nt:hierarchyNode
-
-# ------------------------------------------------------------------------------
-# observation configuration
-# ------------------------------------------------------------------------------
-
-# Configuration settings for the serialization.
-# Note that the serialization test tries to use as many features of the repository
-# as possible, but fails silently if a feature is not available. You have to
-# specify all of the following configuration entries, even if your repository does
-# not support the feature that is associated with them.
-
-# Root node for the example tree
-javax.jcr.tck.SerializationTest.testroot=/testdata/serialization
-
-# Node type to use for the example tree. Specify a node type that allows complex trees and all property types if possible
-javax.jcr.tck.SerializationTest.nodetype=nt:unstructured
-
-# Name of the nodes for source and target tree
-javax.jcr.tck.SerializationTest.sourceFolderName=source
-javax.jcr.tck.SerializationTest.targetFolderName=target
-javax.jcr.tck.SerializationTest.rootNodeName=test
-
-# List the properties whose values may change during serialization/deserialization. For example,
-# the UUID of a node is unique in the repository, so it will have to change when you re-import
-# a tree at a different location.
-javax.jcr.tck.SerializationTest.propertyValueMayChange= jcr:created jcr:uuid jcr:versionHistory jcr:baseVersion jcr:predecessors P_Reference
-
-# The name of the test node types. For easier diagnostics, the node types have names
-# that tell you the kind of information they store
-javax.jcr.tck.SerializationTest.nodeTypesTestNode=NodeTypes
-javax.jcr.tck.SerializationTest.mixinTypeTestNode=MixinTypes
-javax.jcr.tck.SerializationTest.propertyTypesTestNode=PropertyTypes
-javax.jcr.tck.SerializationTest.sameNameChildrenTestNode=SameNameChildren
-javax.jcr.tck.SerializationTest.multiValuePropertiesTestNode=MultiValueProperties
-javax.jcr.tck.SerializationTest.referenceableNodeTestNode=ReferenceableNode
-javax.jcr.tck.SerializationTest.orderChildrenTestNode=OrderChildren
-javax.jcr.tck.SerializationTest.namespaceTestNode=Namespace
-
-# The name of the test property types.
-javax.jcr.tck.SerializationTest.stringTestProperty=P_String
-javax.jcr.tck.SerializationTest.binaryTestProperty=P_Binary
-javax.jcr.tck.SerializationTest.dateTestProperty=P_Date
-javax.jcr.tck.SerializationTest.longTestProperty=P_Long
-javax.jcr.tck.SerializationTest.doubleTestProperty=P_Double
-javax.jcr.tck.SerializationTest.booleanTestProperty=P_Boolean
-javax.jcr.tck.SerializationTest.nameTestProperty=P_Name
-javax.jcr.tck.SerializationTest.pathTestProperty=P_Path
-javax.jcr.tck.SerializationTest.referenceTestProperty=P_Reference
-javax.jcr.tck.SerializationTest.multiValueTestProperty=P_MultiValue
-
-# Test method: testVersioningExceptionSessionFileChild
-# specified nodetype must be versionable and allow child nodes of the same type.
-javax.jcr.tck.SerializationTest.testVersioningExceptionSessionFileChild.nodetype=test:versionable
-
-# Test method: testVersioningExceptionSessionFileParent
-# specified nodetype must be versionable and allow child nodes of the same type.
-javax.jcr.tck.SerializationTest.testVersioningExceptionSessionFileParent.nodetype=test:versionable
-
-# ==============================================================================
-# JAVAX.JCR.QUERY CONFIGURATION
-# ==============================================================================
-
-# Test class: SaveTest
-# Test method: testConstraintViolationException
-# Specified node type must not allow child nodes.
-javax.jcr.tck.SaveTest.testConstraintViolationException.nodetype=nt:query
-
-# Test class: XPathQueryLevel1Test
-javax.jcr.tck.XPathQueryLevel1Test.testroot=/testdata/query
-
-# Test class: XPathDocOrderTest
-javax.jcr.tck.XPathDocOrderTest.testroot=/testdata/query
-
-# Test class: XPathPosIndexTest
-javax.jcr.tck.XPathPosIndexTest.testroot=/testdata/query
-
-# Test class: XPathOrderByTest
-javax.jcr.tck.XPathOrderByTest.testroot=/testdata/query
-
-# Test class: XPathSyntaxTest
-javax.jcr.tck.XPathSyntaxTest.testroot=/testdata/query
-
-# Test class: SQLQueryLevel1Test
-javax.jcr.tck.SQLQueryLevel1Test.testroot=/testdata/query
-
-# Test class: SQLSyntaxTest
-javax.jcr.tck.SQLSyntaxTest.testroot=/testdata/query
-
-# Test class: SQLOrderByTest
-javax.jcr.tck.SQLOrderByTest.testroot=/testdata/query
-
-# ==============================================================================
-# JAVAX.JCR.VERSIONING CONFIGURATION
-# ==============================================================================
-
-# nodetye that is versionable. if it is not, an attempt is made to create versionable nodes
-# by adding a mix:versionable mixin-type.
-# NOTE: javax.jcr.tck.nodetype must define a non-versionable nodetype!
-javax.jcr.tck.version.versionableNodeType=test:versionable
-javax.jcr.tck.version.propertyValue=aPropertyValue
-
-# testroot for the version package
-# the test root must allow versionable and non-versionable nodes being created below
-javax.jcr.tck.version.testroot=/testroot
-
-# 3 nodes (nodeName1, nodeName2, nodeName3 with nt=versionableNodeType / nt=nonVersionableNodeType will be cloned to 2nd workspace
-# nodename1 > used to persistently create versionable node below testroot
-# nodename2 > used to create second versionable node below testroot (used for restore/workspace.restore with uuid-conflict)
-# nodename3 > used to persistently create non-versionable node below testroot
-javax.jcr.tck.version.nodename1=versionableNodeName1
-javax.jcr.tck.version.nodename2=versionableNodeName2
-javax.jcr.tck.version.nodename3=nonVersionableNodeName1
-
-# nodename 4: versionabel child-node of the first versionable node with nodeName1 and nodetype 'versionableNodeType'
-# used for:
-# + creation of a node in the 2nd workspace, that does not exist in the first workspace
-# + creation of a node in the 2nd workspace, in order to test uuid-conflicts with Workspace.restore.
-# + creation of a sub-node in the default workspace, in order to test uuid-conflicts with Node.restore.
-# + NOTE: the nodetype with 'versionableNodeType' must define its children nodes to either have COPY or VERSION
-# OPV behaviour in order to successfully test Node.restore and Workspace.restore with uuid conflict.
-javax.jcr.tck.version.nodename4=childNodeName
-
-# path to existing String-properties and a new value for the property, that allows to test the indicated OPV behaviour
-javax.jcr.tck.OnParentVersionAbortTest.propertyname1=test:abortOnParentVersionProp
-javax.jcr.tck.OnParentVersionComputeTest.propertyname1=test:computeOnParentVersionProp
-javax.jcr.tck.OnParentVersionCopyTest.propertyname1=test:copyOnParentVersionProp
-javax.jcr.tck.OnParentVersionIgnoreTest.propertyname1=test:ignoreOnParentVersionProp
-javax.jcr.tck.OnParentVersionInitializeTest.propertyname1=test:initializeOnParentVersionProp
-
-# config for nodes that show the indicated OPV behaviour:
-# nodes are added in order to test the versioning behaviour indicated by the test-class name.
-# NOTE:
-# - nodename4 is uses as name for the childnode
-# - nodetype is used as nodetype name for the childnode
-# - the specified child node is created below nodename1 with versionableNodeType
-# the versionableNodeType and/or nodename1 may be overwritten with the individual
-# testclass below.
-javax.jcr.tck.OnParentVersionCopyTest.nodename4=test:copyOnParentVersion
-javax.jcr.tck.OnParentVersionCopyTest.nodetype=nt:unstructured
-javax.jcr.tck.OnParentVersionAbortTest.nodename4=test:abortOnParentVersion
-javax.jcr.tck.OnParentVersionAbortTest.nodetype=nt:unstructured
diff --git a/contrib/tck-webapp/src/webapp/WEB-INF/content-repository/log4j.properties b/contrib/tck-webapp/src/webapp/WEB-INF/content-repository/log4j.properties
deleted file mode 100644
index 2728ce9be0d..00000000000
--- a/contrib/tck-webapp/src/webapp/WEB-INF/content-repository/log4j.properties
+++ /dev/null
@@ -1,20 +0,0 @@
-# Set root logger level to DEBUG and its only appender to A1.
-log4j.rootLogger=INFO, stdout
-#log4j.rootLogger=DEBUG, stdout, file
-#log4j.rootLogger=ERROR, stdout, file
-
-# 'stdout' is set to be a ConsoleAppender.
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-
-# 'stdout' uses PatternLayout
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=%d{dd.MM.yyyy HH:mm:ss} *%-5p* [%t] %c{1}: %m (%F, line %L)\n
-
-# 'file' is set to be a FileAppender.
-log4j.appender.file=org.apache.log4j.FileAppender
-log4j.appender.file.File=jcr.log
-
-# 'file' uses PatternLayout.
-log4j.appender.file.layout=org.apache.log4j.PatternLayout
-log4j.appender.file.layout.ConversionPattern=%d{dd.MM.yyyy HH:mm:ss} *%-5p* [%t] %c{1}: %m (%F, line %L)\n
-
diff --git a/contrib/tck-webapp/src/webapp/WEB-INF/content-repository/repository.xml b/contrib/tck-webapp/src/webapp/WEB-INF/content-repository/repository.xml
deleted file mode 100644
index cd35dc49e6d..00000000000
--- a/contrib/tck-webapp/src/webapp/WEB-INF/content-repository/repository.xml
+++ /dev/null
@@ -1,234 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-]>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/contrib/tck-webapp/src/webapp/WEB-INF/tck/log4j.properties b/contrib/tck-webapp/src/webapp/WEB-INF/tck/log4j.properties
deleted file mode 100644
index 057f2048a0a..00000000000
--- a/contrib/tck-webapp/src/webapp/WEB-INF/tck/log4j.properties
+++ /dev/null
@@ -1,27 +0,0 @@
-# Set root logger level to DEBUG and its only appender to A1.
-log4j.rootLogger=INFO, stdout
-#log4j.rootLogger=DEBUG, stdout, file
-#log4j.rootLogger=ERROR, stdout, file
-log4j.logger.org.apache.jackrabbit.test.testwebapp.j2ee.TesterServlet.login=INFO, login
-
-# 'stdout' is set to be a ConsoleAppender.
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-
-# 'stdout' uses PatternLayout
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=%d{dd.MM.yyyy HH:mm:ss} *%-5p* [%t] %c{1}: %m (%F, line %L)\n
-
-# 'file' is set to be a FileAppender.
-log4j.appender.file=org.apache.log4j.FileAppender
-log4j.appender.file.File=jcr.log
-
-# 'file' uses PatternLayout.
-log4j.appender.file.layout=org.apache.log4j.PatternLayout
-log4j.appender.file.layout.ConversionPattern=%d{dd.MM.yyyy HH:mm:ss} *%-5p* [%t] %c{1}: %m (%F, line %L)\n
-
-# 'login' is set to be a FileAppender.
-log4j.appender.login=org.apache.log4j.FileAppender
-log4j.appender.login.File=tck/home/login.log
-log4j.appender.login.layout=org.apache.log4j.PatternLayout
-log4j.appender.login.layout.ConversionPattern=%d{dd.MM.yyyy HH:mm:ss} *%-5p* [%t] %c{1}: %m (%F, line %L)\n
-
diff --git a/contrib/tck-webapp/src/webapp/WEB-INF/web.xml b/contrib/tck-webapp/src/webapp/WEB-INF/web.xml
deleted file mode 100644
index 67bbdfb8a17..00000000000
--- a/contrib/tck-webapp/src/webapp/WEB-INF/web.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
-
-
- TCK web application
-
-
-
-
-
- Repository
- repository servlet that starts the repository and registers it to JNDI.
- org.apache.jackrabbit.tck.j2ee.RepositoryServlet
-
-
- log4j-config
- /WEB-INF/content-repository/log4j.properties
- initial log4j configuration
-
-
-
- repository-config
- /WEB-INF/content-repository/repository.xml
- the repository config location
-
-
-
- repository-home
- tck/content-repository
- the repository home
-
-
-
- repository-name
- tck.repository
- Repository Name under which the repository is registered via JNDI
-
-
-
- jaas-config-file
- etc/jaas.config
- Path of the jaas config file
-
-
-
- jcr-userid
- superuser
- User to read/write from the repository where test results and config is stored
-
-
-
- jcr-password
- superuser
- User password
-
-
- 1
-
-
\ No newline at end of file
diff --git a/contrib/tck-webapp/src/webapp/config.jsp b/contrib/tck-webapp/src/webapp/config.jsp
deleted file mode 100644
index 8d760d9b217..00000000000
--- a/contrib/tck-webapp/src/webapp/config.jsp
+++ /dev/null
@@ -1,168 +0,0 @@
-<%--
-Copyright 2004-2005 The Apache Software Foundation or its licensors,
- as applicable.
-
-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.
---%><%@ page import="javax.jcr.Session,
- javax.jcr.Node,
- javax.jcr.NodeIterator,
- java.text.SimpleDateFormat,
- java.util.*,
- org.apache.jackrabbit.tck.WebAppTestConfig,
- org.apache.jackrabbit.test.JNDIRepositoryStub,
- org.apache.jackrabbit.tck.WebAppTestConfig,
- org.apache.jackrabbit.tck.j2ee.RepositoryServlet,
- org.apache.jackrabbit.tck.TestFinder,
- junit.framework.TestSuite"
-%><%@page session="false" %><%
-
-// get path from jar where the test sources are stored
-String TEST_JCR_PATH = "/WEB-INF/lib/tck-webapp-0.1.jar";
-
-Session repSession = RepositoryServlet.getSession();
-if (repSession == null) {
- return;
-}
-
-String mode = request.getParameter("mode");
-
-%>
-
-
-
-
-
");
- out.write("");
- out.write("");
- }
- %>
-
-
\ No newline at end of file
diff --git a/contrib/tck-webapp/src/webapp/index.jsp b/contrib/tck-webapp/src/webapp/index.jsp
deleted file mode 100644
index cca418f7f40..00000000000
--- a/contrib/tck-webapp/src/webapp/index.jsp
+++ /dev/null
@@ -1,69 +0,0 @@
-<%--
-Copyright 2004-2005 The Apache Software Foundation or its licensors,
- as applicable.
-
-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.
---%><%@ page import="javax.jcr.Session,
- java.util.List,
- java.util.ArrayList"
-%><%@page session="false" %><%
-
- String parent = request.getRequestURI();
- if (parent.length() > 1) {
- parent = parent.substring(0,parent.lastIndexOf('/'));
- }
-
-%>
- TCK for JSR170
-
-
-
-
-
-
-
-
-
TCK for JSR 170 Content Repository Standard
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/contrib/tck-webapp/src/webapp/status.jsp b/contrib/tck-webapp/src/webapp/status.jsp
deleted file mode 100644
index a3ac44b59cf..00000000000
--- a/contrib/tck-webapp/src/webapp/status.jsp
+++ /dev/null
@@ -1,24 +0,0 @@
-<%--
-Copyright 2004-2005 The Apache Software Foundation or its licensors,
- as applicable.
-
-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.
---%><%@page session="false" %><%
-
-%>
-
-
-
-
-
-
diff --git a/contrib/vfs/05-03-03-repository.xml b/contrib/vfs/05-03-03-repository.xml
deleted file mode 100644
index 05cca38b8ba..00000000000
--- a/contrib/vfs/05-03-03-repository.xml
+++ /dev/null
@@ -1,228 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-]>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/contrib/vfs/README.txt b/contrib/vfs/README.txt
deleted file mode 100644
index eb0e5d74409..00000000000
--- a/contrib/vfs/README.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-For testing you can use tmp provider. This provider will delete
-all the files and folders on repository shutdown.
-
-The providers configuration file (providers.xml) must be in the classpath.
-
-repository.xml Example:
-
-
-
-
-
-
-
-
diff --git a/contrib/vfs/src/java/org/apache/jackrabbit/core/fs/vfs/VFSFileSystem.java b/contrib/vfs/src/java/org/apache/jackrabbit/core/fs/vfs/VFSFileSystem.java
deleted file mode 100644
index 3298c7ff5a5..00000000000
--- a/contrib/vfs/src/java/org/apache/jackrabbit/core/fs/vfs/VFSFileSystem.java
+++ /dev/null
@@ -1,631 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.core.fs.vfs;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Collection;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.commons.vfs.AllFileSelector;
-import org.apache.commons.vfs.FileObject;
-import org.apache.commons.vfs.FileSelector;
-import org.apache.commons.vfs.FileSystemException;
-import org.apache.commons.vfs.FileType;
-import org.apache.commons.vfs.FileUtil;
-import org.apache.commons.vfs.RandomAccessContent;
-import org.apache.commons.vfs.cache.SoftRefFilesCache;
-import org.apache.commons.vfs.impl.StandardFileSystemManager;
-import org.apache.commons.vfs.util.RandomAccessMode;
-import org.apache.jackrabbit.core.fs.FileSystem;
-import org.apache.jackrabbit.core.fs.RandomAccessOutputStream;
-
-/**
- * FileSystem backed by Commons VFS
- *
- * @author Edgar Poce
- */
-public class VFSFileSystem implements FileSystem
-{
- /**
- * Logger
- */
- private Log log = LogFactory.getLog(VFSFileSystem.class);
-
- /**
- * File selector
- */
- public final static FileSelector ALL = new AllFileSelector() ;
-
- /**
- * VFS manager
- */
- StandardFileSystemManager fsManager;
-
- /**
- * Scheme
- */
- private String prefix;
-
- /**
- * Path
- */
- private String path;
-
- /**
- * The config file
- */
- private String config;
-
- /**
- *
- */
- public VFSFileSystem()
- {
- super();
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jackrabbit.core.fs.FileSystem#init()
- */
- public void init() throws org.apache.jackrabbit.core.fs.FileSystemException
- {
-
- if (this.path == null)
- {
- String msg = "Path is not set";
- log.error(msg);
- throw new org.apache.jackrabbit.core.fs.FileSystemException(msg);
- }
-
- if (this.config == null)
- {
- String msg = "Configuration file name is not set (\"config\" parameter ).";
- log.error(msg);
- throw new org.apache.jackrabbit.core.fs.FileSystemException(msg);
- }
-
- try
- {
- // Init file system
- fsManager = new StandardFileSystemManager();
-
- // Set class loader for resource retrieval
- fsManager.setClassLoader(this.getClass().getClassLoader());
-
- // Configuration file name
- fsManager.setConfiguration(this.getClass().getClassLoader()
- .getResource(this.config).toExternalForm());
-
- // Set the logger
- fsManager.setLogger(log);
-
- // Cache strategy
- // FIXME: set through configuration
- fsManager.setFilesCache(new SoftRefFilesCache());
- fsManager.init();
-
- // Set the base folder
- FileObject fo = fsManager
- .resolveFile(this.prefix + ":" + this.path);
- fsManager.setBaseFile(fo);
-
- } catch (FileSystemException e)
- {
- String msg = "Unable to init VFS FileSystem";
- log.error(msg, e);
- throw new org.apache.jackrabbit.core.fs.FileSystemException(msg, e);
- }
-
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jackrabbit.core.fs.FileSystem#close()
- */
- public void close()
- throws org.apache.jackrabbit.core.fs.FileSystemException
- {
- this.fsManager.close() ;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jackrabbit.core.fs.FileSystem#getInputStream(java.lang.String)
- */
- public InputStream getInputStream(String filePath)
- throws org.apache.jackrabbit.core.fs.FileSystemException
- {
- try
- {
- FileObject file = this.getFile(filePath);
- this.validateFile(file);
- return file.getContent().getInputStream();
- } catch (FileSystemException e)
- {
- throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jackrabbit.core.fs.FileSystem#getOutputStream(java.lang.String)
- */
- public OutputStream getOutputStream(String filePath)
- throws org.apache.jackrabbit.core.fs.FileSystemException
- {
- try
- {
- FileObject file = this.getFile(filePath);
- if (!file.exists())
- {
- file.createFile();
- }
- this.validateFile(file);
- return file.getContent().getOutputStream();
- } catch (FileSystemException e)
- {
- throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jackrabbit.core.fs.FileSystem#getRandomAccessOutputStream(java.lang.String)
- */
- public RandomAccessOutputStream getRandomAccessOutputStream(String filePath)
- throws org.apache.jackrabbit.core.fs.FileSystemException
- {
- try
- {
- FileObject file = this.getFile(filePath);
- this.validateFile(file);
- RandomAccessContent raf = file.getContent().getRandomAccessContent(
- RandomAccessMode.READWRITE);
- return new VFSRAFOutputStream(raf);
- } catch (FileSystemException e)
- {
- throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jackrabbit.core.fs.FileSystem#createFolder(java.lang.String)
- */
- public void createFolder(String folderPath)
- throws org.apache.jackrabbit.core.fs.FileSystemException
- {
- try
- {
- FileObject folder = this.getFile(folderPath);
- folder.createFolder();
- } catch (FileSystemException e)
- {
- throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jackrabbit.core.fs.FileSystem#exists(java.lang.String)
- */
- public boolean exists(String path)
- throws org.apache.jackrabbit.core.fs.FileSystemException
- {
- try
- {
- return this.getFile(path).exists();
- } catch (FileSystemException e)
- {
- throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jackrabbit.core.fs.FileSystem#isFile(java.lang.String)
- */
- public boolean isFile(String path)
- throws org.apache.jackrabbit.core.fs.FileSystemException
- {
- try
- {
- return this.getFile(path).getType().equals(FileType.FILE);
- } catch (FileSystemException e)
- {
- throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jackrabbit.core.fs.FileSystem#isFolder(java.lang.String)
- */
- public boolean isFolder(String path)
- throws org.apache.jackrabbit.core.fs.FileSystemException
- {
- try
- {
- return this.getFile(path).getType().equals(FileType.FOLDER);
- } catch (FileSystemException e)
- {
- throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jackrabbit.core.fs.FileSystem#hasChildren(java.lang.String)
- */
- public boolean hasChildren(String path)
- throws org.apache.jackrabbit.core.fs.FileSystemException
- {
- try
- {
- return this.getFile(path).getChildren().length > 0;
- } catch (FileSystemException e)
- {
- throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jackrabbit.core.fs.FileSystem#length(java.lang.String)
- */
- public long length(String filePath)
- throws org.apache.jackrabbit.core.fs.FileSystemException
- {
- try
- {
- FileObject file = this.getFile(filePath);
- this.validateFile(file);
- return file.getContent().getSize();
- } catch (FileSystemException e)
- {
- throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jackrabbit.core.fs.FileSystem#lastModified(java.lang.String)
- */
- public long lastModified(String path)
- throws org.apache.jackrabbit.core.fs.FileSystemException
- {
- try
- {
- return this.getFile(path).getContent().getLastModifiedTime();
- } catch (FileSystemException e)
- {
- throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jackrabbit.core.fs.FileSystem#touch(java.lang.String)
- */
- public void touch(String filePath)
- throws org.apache.jackrabbit.core.fs.FileSystemException
- {
- try
- {
- FileObject file = this.getFile(filePath);
- this.validateFile(file);
- file.getContent().setLastModifiedTime(
- Calendar.getInstance().getTimeInMillis());
- } catch (FileSystemException e)
- {
- throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jackrabbit.core.fs.FileSystem#list(java.lang.String)
- */
- public String[] list(String folderPath)
- throws org.apache.jackrabbit.core.fs.FileSystemException
- {
- return this.list(this.getFile(folderPath), null);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jackrabbit.core.fs.FileSystem#listFiles(java.lang.String)
- */
- public String[] listFiles(String folderPath)
- throws org.apache.jackrabbit.core.fs.FileSystemException
- {
- return this.list(this.getFile(folderPath), FileType.FILE);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jackrabbit.core.fs.FileSystem#listFolders(java.lang.String)
- */
- public String[] listFolders(String folderPath)
- throws org.apache.jackrabbit.core.fs.FileSystemException
- {
- return this.list(this.getFile(folderPath), FileType.FOLDER);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jackrabbit.core.fs.FileSystem#deleteFile(java.lang.String)
- */
- public void deleteFile(String filePath)
- throws org.apache.jackrabbit.core.fs.FileSystemException
- {
- try
- {
- FileObject file = this.getFile(filePath);
- this.validateFile(file);
- this.delete(file);
- } catch (FileSystemException e)
- {
- throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jackrabbit.core.fs.FileSystem#deleteFolder(java.lang.String)
- */
- public void deleteFolder(String folderPath)
- throws org.apache.jackrabbit.core.fs.FileSystemException
- {
- try
- {
- FileObject folder = this.getFile(folderPath);
- this.validateFolder(folder);
- this.delete(folder);
- } catch (FileSystemException e)
- {
- throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jackrabbit.core.fs.FileSystem#move(java.lang.String,
- * java.lang.String)
- */
- public void move(String srcPath, String destPath)
- throws org.apache.jackrabbit.core.fs.FileSystemException
- {
- try
- {
- FileObject src = this.getFile(srcPath);
- FileObject dest = this.getFile(destPath);
- src.moveTo(dest);
- } catch (FileSystemException e)
- {
- throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jackrabbit.core.fs.FileSystem#copy(java.lang.String,
- * java.lang.String)
- */
- public void copy(String srcPath, String destPath)
- throws org.apache.jackrabbit.core.fs.FileSystemException
- {
- try
- {
- FileObject src = this.getFile(srcPath);
- FileObject dest = this.getFile(destPath);
- FileUtil.copyContent(src, dest);
- } catch (FileSystemException e)
- {
- throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
- } catch (IOException e)
- {
- throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
- }
- }
-
- /**
- * Gets the FileObject for the given path
- *
- * @param path
- * @return FileSystem
- * @throws FileSystemException
- */
- private FileObject getFile(String path)
- throws org.apache.jackrabbit.core.fs.FileSystemException
- {
- try
- {
- if (path.startsWith("/")) {
- path = path.substring(1, path.length()) ;
- }
- return fsManager.resolveFile(path);
- } catch (FileSystemException e)
- {
- String msg = "Unable to get file " + path;
- log.error(msg, e);
- throw new org.apache.jackrabbit.core.fs.FileSystemException(msg, e);
- }
- }
-
- /**
- * Validates Folder Type
- *
- * @param folder
- * @throws FileSystemException
- */
- private void validateFolder(FileObject folder) throws FileSystemException
- {
- if (!folder.getType().equals(FileType.FOLDER))
- {
- String msg = folder.getName().getPath()
- + " does not denote a folder";
- log.error(msg);
- throw new FileSystemException(msg);
- }
- }
-
- /**
- * Validates File Type
- *
- * @param folder
- * @throws FileSystemException
- */
- private void validateFile(FileObject file) throws FileSystemException
- {
- if (!file.getType().equals(FileType.FILE))
- {
- String msg = file.getName().getPath() + " does not denote a file";
- log.error(msg);
- throw new FileSystemException(msg);
- }
- }
-
- /**
- * List the children for the given Type.
- *
- * @param path
- * @param type
- * @return
- * @throws org.apache.jackrabbit.core.fs.FileSystemException
- */
- private String[] list(FileObject folder, FileType type)
- throws org.apache.jackrabbit.core.fs.FileSystemException
- {
- try
- {
- this.validateFolder(folder);
- FileObject[] fo = folder.getChildren();
- Collection c = new ArrayList();
- for (int i = 0; i < fo.length; i++)
- {
- if (type == null)
- {
- c.add(fo[i].getName().getBaseName());
- } else
- {
- if (fo[i].getType().equals(type))
- {
- c.add(fo[i].getName().getBaseName());
- }
- }
- }
- return (String[]) c.toArray(new String[c.size()]);
- } catch (FileSystemException e)
- {
- throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
- }
- }
-
- /**
- * Deletes the given File
- */
- private void delete(FileObject file)
- throws org.apache.jackrabbit.core.fs.FileSystemException
- {
- try
- {
- file.delete(ALL);
- } catch (FileSystemException e)
- {
- throw new org.apache.jackrabbit.core.fs.FileSystemException(e);
- }
- }
-
- public String getPath()
- {
- return path;
- }
-
- public void setPath(String path)
- {
- this.path = path;
- }
-
- /**
- * Makes a file canonical
- */
- public static File getCanonicalFile(final File file)
- {
- try
- {
- return file.getCanonicalFile();
- } catch (IOException e)
- {
- return file.getAbsoluteFile();
- }
- }
-
- public String getConfig()
- {
- return config;
- }
-
- public void setConfig(String config)
- {
- this.config = config;
- }
-
- /**
- * @return Returns the scheme.
- */
- public String getPrefix()
- {
- return prefix;
- }
-
- /**
- * @param scheme
- * The scheme to set.
- */
- public void setPrefix(String prefix)
- {
- this.prefix = prefix;
- }
-}
\ No newline at end of file
diff --git a/contrib/vfs/src/java/org/apache/jackrabbit/core/fs/vfs/VFSRAFOutputStream.java b/contrib/vfs/src/java/org/apache/jackrabbit/core/fs/vfs/VFSRAFOutputStream.java
deleted file mode 100644
index ec06b5c239d..00000000000
--- a/contrib/vfs/src/java/org/apache/jackrabbit/core/fs/vfs/VFSRAFOutputStream.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.core.fs.vfs;
-
-import java.io.IOException;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.commons.vfs.RandomAccessContent;
-import org.apache.jackrabbit.core.fs.RandomAccessOutputStream;
-
-/**
- * Wrapper of VFS output stream on a random access file.
- *
- * @author Edgar Poce
- */
-class VFSRAFOutputStream extends RandomAccessOutputStream
-{
-
- private Log log = LogFactory.getLog(VFSRAFOutputStream.class);
-
- /**
- * The default size of the write buffer in bytes.
- */
- static final int DEFAULT_BUFFER_SIZE = 1024;
-
- /**
- * The write buffer.
- */
- private final byte[] buffer;
-
- /**
- * The underlying RandomAccessContent.
- */
- protected RandomAccessContent rac;
-
- /**
- * The starting position of the buffer in the code.
- */
- private long bufferStart;
-
- /**
- * The end of valid data in the buffer.
- */
- private int bufferEnd;
-
- /**
- * Dummy buffer for {@link #write(int)}.
- */
- private byte[] one = new byte[1];
-
- /**
- * Constructor
- */
- public VFSRAFOutputStream(RandomAccessContent rac, int size)
- {
- super();
- this.rac = rac;
- this.buffer = new byte[size];
- try
- {
- bufferStart = rac.getFilePointer();
- } catch (IOException e)
- {
- log.error("Unable to get file pointer");
- }
- }
-
- /**
- * Constructor
- */
- public VFSRAFOutputStream(RandomAccessContent rac)
- {
- this(rac, DEFAULT_BUFFER_SIZE);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.jackrabbit.core.fs.RandomAccessOutputStream#seek(long)
- */
- public void seek(long position) throws IOException
- {
- flush();
- rac.seek(position);
- bufferStart = position;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see java.io.OutputStream#write(int)
- */
- public void write(int b) throws IOException
- {
- one[0] = (byte) b;
- write(one, 0, 1);
- }
-
- public void close() throws IOException
- {
- flush();
- rac.close();
- rac = null;
- }
-
- public void flush() throws IOException
- {
- rac.write(buffer, 0, bufferEnd);
- bufferEnd = 0;
- bufferStart = rac.getFilePointer();
- }
-
- public void write(byte b[], int off, int len) throws IOException
- {
- if (len > buffer.length - bufferEnd)
- {
- flush();
- rac.write(b, off, len);
- } else
- {
- System.arraycopy(b, off, buffer, bufferEnd, len);
- bufferEnd += len;
- }
- }
-
- public void write(byte[] b) throws IOException
- {
- write(b, 0, b.length);
- }
-}
\ No newline at end of file
diff --git a/contrib/vfs/src/java/providers.xml b/contrib/vfs/src/java/providers.xml
deleted file mode 100644
index 8b57883d3ef..00000000000
--- a/contrib/vfs/src/java/providers.xml
+++ /dev/null
@@ -1,107 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/contrib/vfs/src/test/org/apache/jackrabbit/core/fs/vfs/VFSFileSystemTest.java b/contrib/vfs/src/test/org/apache/jackrabbit/core/fs/vfs/VFSFileSystemTest.java
deleted file mode 100644
index 5be1ff0f2f9..00000000000
--- a/contrib/vfs/src/test/org/apache/jackrabbit/core/fs/vfs/VFSFileSystemTest.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright 2004-2005 The Apache Software Foundation or its licensors,
- * as applicable.
- *
- * 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.jackrabbit.core.fs.vfs;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Arrays;
-
-import org.apache.jackrabbit.core.fs.RandomAccessOutputStream;
-import org.apache.jackrabbit.test.JUnitTest;
-
-/**
- *
- * FileSystem backed by Commons VFS Tests
- *
- *
- *
- * In order to run the following VM arguments must be set:
- *
- *
fs.prefix = [provider prefix]
- *
fs.path = [root path]
- *
fs.config = [providers config file]
- *
- *
- * @author Edgar Poce
- */
-public class VFSFileSystemTest extends JUnitTest
-{
- private static final String PREFIX = "fs.prefix";
-
- private static final String PATH = "fs.path";
-
- private static final String CONFIG = "fs.config";
-
- private static final String TEST_FOLDER = "testFolder1";
-
- private static final String TEST_FILE = "testFile1.txt";
-
- private static final String TEST_FOLDER2 = TEST_FOLDER + "/testFolder2";
-
- private static final String TEST_FILE2 = TEST_FOLDER2 + "/testFile2.txt";
-
- private static final String TEST_FILE3 = TEST_FOLDER2 + "/testFile3.txt";
-
- /**
- * VFS fs
- */
- private VFSFileSystem fs;
-
- /*
- * (non-Javadoc)
- *
- * @see junit.framework.TestCase#setUp()
- */
- protected void setUp() throws Exception
- {
- super.setUp();
- fs = new VFSFileSystem();
- fs.setPrefix(System.getProperty(PREFIX));
- fs.setPath(System.getProperty(PATH));
- fs.setConfig(System.getProperty(CONFIG));
- fs.init();
- }
-
- /*
- * (non-Javadoc)
- *
- * @see junit.framework.TestCase#tearDown()
- */
- protected void tearDown() throws Exception
- {
- super.tearDown();
- fs.close();
- fs = null;
- }
-
- public void testFileSystem() throws Exception
- {
- /*
- * Create folder
- */
- // depth = 0
- fs.createFolder(TEST_FOLDER);
- assertTrue(fs.exists(TEST_FOLDER));
- assertTrue(fs.isFolder(TEST_FOLDER));
- // depth = 1
- fs.createFolder(TEST_FOLDER2);
- assertTrue(fs.exists(TEST_FOLDER2));
- assertTrue(fs.isFolder(TEST_FOLDER2));
- // Children
- assertTrue(fs.hasChildren(TEST_FOLDER));
- assertTrue(fs.list(TEST_FOLDER)[0].equals(getName(TEST_FOLDER2)));
- assertTrue(fs.listFiles(TEST_FOLDER).length == 0);
- assertTrue(fs.listFolders(TEST_FOLDER)[0].equals(getName(TEST_FOLDER2)));
-
- /*
- * Create file
- */
- // depth = 1
- byte[] write = "hello world".getBytes();
- byte[] read = new byte[write.length];
-
- OutputStream out = fs.getOutputStream(TEST_FILE);
- out.write(write);
- out.flush();
- out.close();
- assertTrue(fs.exists(TEST_FILE));
- fs.getInputStream(TEST_FILE).read(read);
- assertTrue(Arrays.equals(write, read));
- // depth = 2
- out = fs.getOutputStream(TEST_FILE2);
- out.write(write);
- out.flush();
- out.close();
- assertTrue(fs.exists(TEST_FILE2));
- InputStream in = fs.getInputStream(TEST_FILE2);
- in.read(read);
- in.close();
- assertTrue(Arrays.equals(write, read));
-
- /*
- * Delete file
- */
- fs.deleteFile(TEST_FILE2);
- assertFalse(fs.exists(TEST_FILE2));
-
- /*
- * Delete folder
- */
- fs.deleteFolder(TEST_FOLDER2);
- assertFalse(fs.exists(TEST_FOLDER2));
-
- /*
- * Copy file
- */
- fs.copy(TEST_FILE, TEST_FILE2);
- assertTrue(fs.exists(TEST_FILE2));
- assertTrue(fs.isFile(TEST_FILE2));
-
- /*
- * Move file
- */
- fs.move(TEST_FILE2, TEST_FILE3);
- assertFalse(fs.exists(TEST_FILE2));
- assertTrue(fs.exists(TEST_FILE3));
- assertTrue(fs.isFile(TEST_FILE3));
-
- /* Radom access content */
- RandomAccessOutputStream rout = fs
- .getRandomAccessOutputStream(TEST_FILE);
- rout.seek(100);
- rout.write(10);
- rout.flush();
- rout.close();
-
- in = fs.getInputStream(TEST_FILE);
- in.skip(100);
- assertTrue(in.read() == 10);
- in.close();
-
- }
-
- /**
- * Get the name
- *
- * @param path
- * @return
- */
- private String getName(String path)
- {
- return path.substring(path.lastIndexOf("/") + 1, path.length());
- }
-
-}
\ No newline at end of file
diff --git a/examples/jackrabbit-firsthops/pom.xml b/examples/jackrabbit-firsthops/pom.xml
new file mode 100644
index 00000000000..5ba02bf7f3b
--- /dev/null
+++ b/examples/jackrabbit-firsthops/pom.xml
@@ -0,0 +1,91 @@
+
+
+
+ 4.0.0
+
+ org.apache.jackrabbit
+ jackrabbit-firsthops
+ 0.1-SNAPSHOT
+ First Hops
+ First Hops Example Page
+ http://jackrabbit.apache.org/first-hops.html
+
+
+
+
+
+ javax.jcr
+ jcr
+ 2.0
+
+
+
+
+ org.apache.jackrabbit
+ jackrabbit-core
+ 2.12.1
+
+
+
+
+
+
+
+
+ org.slf4j
+ slf4j-log4j12
+ 1.7.5
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 2.3.2
+
+ 1.5
+ 1.5
+ 1.5
+ true
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
diff --git a/examples/jackrabbit-firsthops/src/main/java/org/apache/jackrabbit/firsthops/FirstHop.java b/examples/jackrabbit-firsthops/src/main/java/org/apache/jackrabbit/firsthops/FirstHop.java
new file mode 100644
index 00000000000..23ef4daed09
--- /dev/null
+++ b/examples/jackrabbit-firsthops/src/main/java/org/apache/jackrabbit/firsthops/FirstHop.java
@@ -0,0 +1,51 @@
+/*
+ * 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.jackrabbit.firsthops;
+
+import javax.jcr.GuestCredentials;
+import javax.jcr.Repository;
+import javax.jcr.Session;
+
+import org.apache.jackrabbit.commons.JcrUtils;
+
+/**
+ * First hop example. Logs in to a content repository and prints a status
+ * message.
+ */
+public class FirstHop {
+
+ /**
+ * The main entry point of the example application.
+ *
+ * @param args
+ * command line arguments (ignored)
+ * @throws Exception
+ * if an error occurs
+ */
+ public static void main(String[] args) throws Exception {
+ Repository repository = JcrUtils.getRepository();
+ Session session = repository.login(new GuestCredentials());
+ try {
+ String user = session.getUserID();
+ String name = repository.getDescriptor(Repository.REP_NAME_DESC);
+ System.out.println("Logged in as " + user + " to a " + name
+ + " repository.");
+ } finally {
+ session.logout();
+ }
+ }
+}
diff --git a/examples/jackrabbit-firsthops/src/main/java/org/apache/jackrabbit/firsthops/SecondHop.java b/examples/jackrabbit-firsthops/src/main/java/org/apache/jackrabbit/firsthops/SecondHop.java
new file mode 100644
index 00000000000..61a3bdeafaf
--- /dev/null
+++ b/examples/jackrabbit-firsthops/src/main/java/org/apache/jackrabbit/firsthops/SecondHop.java
@@ -0,0 +1,65 @@
+/*
+ * 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.jackrabbit.firsthops;
+
+import javax.jcr.Repository;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.Node;
+
+import org.apache.jackrabbit.commons.JcrUtils;
+
+/**
+ * Second hop example. Stores, retrieves, and removes example content.
+ */
+public class SecondHop {
+
+ /**
+ * The main entry point of the example application.
+ *
+ * @param args
+ * command line arguments (ignored)
+ * @throws Exception
+ * if an error occurs
+ */
+ public static void main(String[] args) throws Exception {
+ Repository repository = JcrUtils.getRepository();
+ Session session = repository.login(new SimpleCredentials("admin",
+ "admin".toCharArray()));
+ try {
+ Node root = session.getRootNode();
+
+ // Store content
+ Node hello = root.addNode("hello");
+ Node world = hello.addNode("world");
+ world.setProperty("message", "Hello, World!");
+ session.save();
+
+ // Retrieve content
+ Node node = root.getNode("hello/world");
+ System.out.println(node.getPath());
+ System.out.println(node.getProperty("message").getString());
+
+ // Remove content
+ root.getNode("hello").remove();
+ session.save();
+ } finally {
+ session.logout();
+ }
+ }
+
+}
diff --git a/examples/jackrabbit-firsthops/src/main/java/org/apache/jackrabbit/firsthops/ThirdHop.java b/examples/jackrabbit-firsthops/src/main/java/org/apache/jackrabbit/firsthops/ThirdHop.java
new file mode 100644
index 00000000000..79b20f95929
--- /dev/null
+++ b/examples/jackrabbit-firsthops/src/main/java/org/apache/jackrabbit/firsthops/ThirdHop.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.jackrabbit.firsthops;
+
+import javax.jcr.*;
+import java.io.FileInputStream;
+
+import org.apache.jackrabbit.commons.JcrUtils;
+
+/**
+ * Third Jackrabbit example application. Imports an example XML file and outputs
+ * the contents of the entire workspace.
+ */
+public class ThirdHop {
+
+ /**
+ * The main entry point of the example application.
+ *
+ * @param args
+ * command line arguments (ignored)
+ * @throws Exception
+ * if an error occurs
+ */
+ public static void main(String[] args) throws Exception {
+ Repository repository = JcrUtils.getRepository();
+ Session session = repository.login(new SimpleCredentials("admin",
+ "admin".toCharArray()));
+
+ FileInputStream xml = new FileInputStream("src/main/resources/test.xml");
+ try {
+ Node root = session.getRootNode();
+
+ // Import the XML file unless already imported
+ if (!root.hasNode("importxml")) {
+ System.out.print("Importing xml... ");
+ // Create an unstructured node under which to import the XML
+ Node node = root.addNode("importxml", "nt:unstructured");
+ // Import the file "test.xml" under the created node
+ session.importXML(node.getPath(), xml,
+ ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW);
+
+ session.save();
+ System.out.println("done.");
+ }
+
+ dump(root);
+ } finally {
+ session.logout();
+ }
+ }
+
+ /** Recursively outputs the contents of the given node. */
+ private static void dump(Node node) throws RepositoryException {
+ // First output the node path
+ System.out.println(node.getPath());
+ // Skip the virtual (and large!) jcr:system subtree
+ if (node.getName().equals("jcr:system")) {
+ return;
+ }
+
+ // Then output the properties
+ PropertyIterator properties = node.getProperties();
+ while (properties.hasNext()) {
+ Property property = properties.nextProperty();
+ if (property.getDefinition().isMultiple()) {
+ // A multi-valued property, print all values
+ Value[] values = property.getValues();
+ for (int i = 0; i < values.length; i++) {
+ System.out.println(property.getPath() + " = "
+ + values[i].getString());
+ }
+ } else {
+ // A single-valued property
+ System.out.println(property.getPath() + " = "
+ + property.getString());
+ }
+ }
+
+ // Finally output all the child nodes recursively
+ NodeIterator nodes = node.getNodes();
+ while (nodes.hasNext()) {
+ dump(nodes.nextNode());
+ }
+ }
+
+}
diff --git a/examples/jackrabbit-firsthops/src/main/resources/log4j.properties b/examples/jackrabbit-firsthops/src/main/resources/log4j.properties
new file mode 100644
index 00000000000..c8e9cb77d23
--- /dev/null
+++ b/examples/jackrabbit-firsthops/src/main/resources/log4j.properties
@@ -0,0 +1,20 @@
+# 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.
+
+log4j.rootLogger=ERROR, Console
+
+log4j.appender.Console=org.apache.log4j.ConsoleAppender
+log4j.appender.Console.layout=org.apache.log4j.PatternLayout
+log4j.appender.Console.layout.ConversionPattern=%d %p %c - %m%n
diff --git a/examples/jackrabbit-firsthops/src/main/resources/test.xml b/examples/jackrabbit-firsthops/src/main/resources/test.xml
new file mode 100644
index 00000000000..fdc026199ee
--- /dev/null
+++ b/examples/jackrabbit-firsthops/src/main/resources/test.xml
@@ -0,0 +1,68 @@
+
+
+
+ Three Namespaces
+
+
+ An Ellipse and a Rectangle
+
+
+
+
+ The equation for ellipses
+
+
+
+ 1
+
+
+
+
+
+
+ x
+ 2
+
+
+
+ a
+ 2
+
+
+
+
+
+
+ y
+ 2
+
+
+
+ b
+ 2
+
+
+
+
+
+
+ Last Modified January 10, 2002
+
+
diff --git a/jackrabbit-api/README.txt b/jackrabbit-api/README.txt
new file mode 100644
index 00000000000..c5b53a35cf9
--- /dev/null
+++ b/jackrabbit-api/README.txt
@@ -0,0 +1,8 @@
+=========================
+Welcome to Jackrabbit API
+=========================
+
+This is the API component of the Apache Jackrabbit project.
+This component contains the interface extensions that Apache
+Jackrabbit supports in addition to the standard JCR API. You can
+use these interfaces to access Jackrabbit-specific functionality.
diff --git a/jackrabbit-api/pom.xml b/jackrabbit-api/pom.xml
new file mode 100644
index 00000000000..25d19f5fa75
--- /dev/null
+++ b/jackrabbit-api/pom.xml
@@ -0,0 +1,105 @@
+
+
+
+
+
+ 4.0.0
+
+
+
+
+
+ org.apache.jackrabbit
+ jackrabbit-parent
+ 2.13.5-SNAPSHOT
+ ../jackrabbit-parent/pom.xml
+
+ jackrabbit-api
+ Apache Jackrabbit API
+ Jackrabbit-specific extensions to the JCR API
+ bundle
+
+
+
+
+ org.apache.felix
+ maven-bundle-plugin
+ true
+
+
+ org.apache.rat
+ apache-rat-plugin
+
+
+ .checkstyle
+
+
+
+
+
+
+
+
+ javax.jcr
+ jcr
+
+
+ biz.aQute
+ bndlib
+ provided
+
+
+
+
+ com.google.code.findbugs
+ jsr305
+ provided
+
+
+
+
+
+ clirr
+
+
+
+ org.codehaus.mojo
+ clirr-maven-plugin
+
+
+ verify
+
+ check
+
+
+
+
+ ${project.groupId}
+ ${project.artifactId}
+ ${clirr.baseline.version}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jackrabbit-api/src/main/appended-resources/META-INF/NOTICE b/jackrabbit-api/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 00000000000..45e7de5ff36
--- /dev/null
+++ b/jackrabbit-api/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,2 @@
+Based on source code originally developed by
+Day Software (http://www.day.com/).
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitNode.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitNode.java
new file mode 100644
index 00000000000..0895f9cc667
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitNode.java
@@ -0,0 +1,50 @@
+/*
+ * 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.jackrabbit.api;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.lock.LockException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.version.VersionException;
+
+/**
+ * The Jackrabbit Node interface. This interface contains the
+ * Jackrabbit-specific extensions to the JCR {@link javax.jcr.Node} interface.
+ */
+public interface JackrabbitNode {
+
+ /**
+ *
+ * @param newName
+ * @throws javax.jcr.RepositoryException
+ */
+ void rename(String newName) throws RepositoryException;
+
+ /**
+ *
+ * @param mixinNames
+ * @throws NoSuchNodeTypeException
+ * @throws VersionException
+ * @throws ConstraintViolationException
+ * @throws LockException
+ * @throws RepositoryException
+ */
+ void setMixins(String[] mixinNames)
+ throws NoSuchNodeTypeException, VersionException,
+ ConstraintViolationException, LockException, RepositoryException;
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitNodeTypeManager.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitNodeTypeManager.java
new file mode 100644
index 00000000000..9a14a3ba880
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitNodeTypeManager.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.jackrabbit.api;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeManager;
+
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * The Jackrabbit node type manager interface. This interface contains the
+ * Jackrabbit-specific extensions to the JCR {@link NodeTypeManager} interface.
+ *
+ * Currently Jackrabbit provides a mechanism to register new node types, but
+ * it is not possible to modify or remove existing node types.
+ *
+ * @deprecated Use standard JCR 2.0 API methods defined by
+ * {@link NodeTypeManager} instead.
+ */
+public interface JackrabbitNodeTypeManager extends NodeTypeManager {
+
+ /**
+ * The standard XML content type to be used with XML-formatted
+ * node type streams.
+ */
+ String TEXT_XML = "text/xml";
+
+ /**
+ * The experimental content type for the compact node type definition
+ * files.
+ */
+ String TEXT_X_JCR_CND = "text/x-jcr-cnd";
+
+ /**
+ * Registers node types from the given node type XML stream.
+ *
+ * @param in node type XML stream
+ * @return registered node types
+ * @throws SAXException if the XML stream could not be read or parsed
+ * @throws RepositoryException if the node types are invalid or another
+ * repository error occurs
+ */
+ NodeType[] registerNodeTypes(InputSource in)
+ throws SAXException, RepositoryException;
+
+ /**
+ * Registers node types from the given input stream of the given type.
+ *
+ * @param in node type stream
+ * @param contentType type of the input stream
+ * @return registered node types
+ * @throws IOException if the input stream could not be read or parsed
+ * @throws RepositoryException if the node types are invalid or another
+ * repository error occurs
+ */
+ NodeType[] registerNodeTypes(InputStream in, String contentType)
+ throws IOException, RepositoryException;
+
+ /**
+ * Checks if a node type with the given name is registered.
+ *
+ * @param name node type name
+ * @return true if the named node type is registered
+ * false otherwise
+ * @throws RepositoryException if an error occurs
+ */
+ boolean hasNodeType(String name) throws RepositoryException;
+
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitRepository.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitRepository.java
new file mode 100644
index 00000000000..9a84715789b
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitRepository.java
@@ -0,0 +1,92 @@
+/*
+ * 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.jackrabbit.api;
+
+import java.util.Map;
+
+import javax.jcr.Credentials;
+import javax.jcr.LoginException;
+import javax.jcr.NoSuchWorkspaceException;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+/**
+ * The Jackrabbit repository interface. This interface contains the
+ * Jackrabbit-specific extensions to the JCR {@link Repository} interface.
+ */
+public interface JackrabbitRepository extends Repository {
+
+ /**
+ * Key to a boolean descriptor. Returns true if
+ * and only if user management is supported.
+ */
+ public static final String OPTION_USER_MANAGEMENT_SUPPORTED = "option.user.management.supported";
+
+ /**
+ * Key to a boolean descriptor. Returns true if
+ * and only if principal management is supported.
+ */
+ public static final String OPTION_PRINCIPAL_MANAGEMENT_SUPPORTED = "option.principal.management.supported";
+
+ /**
+ * Key to a boolean descriptor. Returns true if
+ * and only if privilege management is supported.
+ */
+ public static final String OPTION_PRIVILEGE_MANAGEMENT_SUPPORTED = "option.privilege.management.supported";
+
+ /**
+ * Equivalent to {@code login(credentials, workspaceName)} except that the returned
+ * Session instance contains the given extra session attributes in addition to any
+ * included in the given Credentials instance. Attribute names from the credentials
+ * and the attribute map must not overlap. In case of an overlap implementation
+ * may throw an RepositoryException.
+ *
+ * The attributes are implementation-specific and may affect the behavior of the returned
+ * session. Unlike credentials attributes, these separately passed session attributes
+ * are guaranteed not to affect the authentication of the client.
+ *
+ * An implementation that does not support a particular session attribute is expected
+ * to ignore it and not make it available through the returned session. A client that
+ * depends on specific behavior defined by a particular attribute can check whether
+ * the returned session contains that attribute to verify whether the underlying
+ * repository implementation supports that feature.
+ *
+ * @param credentials the credentials of the user
+ * @param workspaceName the name of a workspace
+ * @param attributes implementation-specific session attributes
+ * @return a valid session for the user to access the repository
+ * @throws LoginException if authentication or authorization for the specified workspace fails
+ * @throws NoSuchWorkspaceException if the specified workspace is not recognized
+ * @throws RepositoryException if another error occurs
+ */
+ Session login(Credentials credentials, String workspaceName, Map attributes)
+ throws LoginException, NoSuchWorkspaceException, RepositoryException;
+
+ /**
+ * Shuts down the repository. A Jackrabbit repository instance contains
+ * a acquired resources and cached data that needs to be released and
+ * persisted when the repository is no longer used. This method handles
+ * all these shutdown tasks and must therefore be called by the
+ * client application once the repository instance is no longer used.
+ *
+ * Possible errors are logged rather than thrown as exceptions as there
+ * is little that a client application could do in such a case.
+ */
+ void shutdown();
+
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitRepositoryFactory.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitRepositoryFactory.java
new file mode 100644
index 00000000000..c96e5534dc9
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitRepositoryFactory.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.jackrabbit.api;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.RepositoryFactory;
+import org.apache.jackrabbit.api.management.RepositoryManager;
+
+/**
+ * Classes that implement this interface additionally provide management features.
+ */
+public interface JackrabbitRepositoryFactory extends RepositoryFactory {
+
+ /**
+ * Get the repository management component. Only the factory that created
+ * the given repository may retrieve the manager.
+ *
+ * @param repository the repository to manage
+ * @return the manager
+ */
+ RepositoryManager getRepositoryManager(JackrabbitRepository repository) throws RepositoryException;
+
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitSession.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitSession.java
new file mode 100644
index 00000000000..decf59c8ea1
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitSession.java
@@ -0,0 +1,254 @@
+/*
+ * 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.jackrabbit.api;
+
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+
+import javax.annotation.Nonnull;
+import javax.jcr.Item;
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.Session;
+import javax.jcr.AccessDeniedException;
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+
+/**
+ * Jackrabbit specific extension of the JCR {@link javax.jcr.Session} interface.
+ */
+public interface JackrabbitSession extends Session {
+
+ /**
+ * A constant representing the {@code add_property} action string, used to
+ * determine if this {@code Session} has permission to add a new property.
+ *
+ * @see #hasPermission(String, String...)
+ */
+ String ACTION_ADD_PROPERTY = "add_property";
+
+ /**
+ * A constant representing the {@code modify_property} action string, used to
+ * determine if this {@code Session} has permission to modify a property.
+ *
+ * @see #hasPermission(String, String...)
+ */
+ String ACTION_MODIFY_PROPERTY = "modify_property";
+
+ /**
+ * A constant representing the {@code remove_property} action string, used to
+ * determine if this {@code Session} has permission to remove a property.
+ *
+ * @see #hasPermission(String, String...)
+ */
+ String ACTION_REMOVE_PROPERTY = "remove_property";
+
+ /**
+ * A constant representing the {@code remove_node} action string, used to
+ * determine if this {@code Session} has permission to remove a node.
+ *
+ * @see #hasPermission(String, String...)
+ */
+ String ACTION_REMOVE_NODE = "remove_node";
+
+ /**
+ * A constant representing the {@code node_type_management} action string,
+ * used to determine if this {@code Session} has permission to write
+ * node type information of a node.
+ *
+ * @see #hasPermission(String, String...)
+ */
+ String ACTION_NODE_TYPE_MANAGEMENT = "node_type_management";
+
+ /**
+ * A constant representing the {@code versioning} action string,
+ * used to determine if this {@code Session} has permission to perform
+ * version operations on a node.
+ *
+ * @see #hasPermission(String, String...)
+ */
+ String ACTION_VERSIONING = "versioning";
+
+ /**
+ * A constant representing the {@code locking} action string,
+ * used to determine if this {@code Session} has permission to lock or
+ * unlock a node.
+ *
+ * @see #hasPermission(String, String...)
+ */
+ String ACTION_LOCKING = "locking";
+
+ /**
+ * A constant representing the {@code read_access_control} action string,
+ * used to determine if this {@code Session} has permission to read
+ * access control content at the given path.
+ *
+ * @see #hasPermission(String, String...)
+ */
+ String ACTION_READ_ACCESS_CONTROL = "read_access_control";
+
+ /**
+ * A constant representing the {@code modify_access_control} action string,
+ * used to determine if this {@code Session} has permission to modify
+ * access control content at the given path.
+ *
+ * @see #hasPermission(String, String...)
+ */
+ String ACTION_MODIFY_ACCESS_CONTROL = "modify_access_control";
+
+ /**
+ * A constant representing the {@code user_management} action string,
+ * used to determine if this {@code Session} has permission to perform
+ * user management operations at the given path.
+ *
+ * @see #hasPermission(String, String...)
+ */
+ String ACTION_USER_MANAGEMENT = "user_management";
+
+ /**
+ * Returns {@code true} if this {@code Session} has permission to
+ * perform the specified actions at the specified {@code absPath} and
+ * {@code false} otherwise.
+ *
+ * The {@code actions} parameter is a list of action strings. Apart
+ * from the actions defined on {@link Session}, this variant also allows
+ * to specify the following additional actions to provide better permission
+ * discovery:
+ *
+ *
{@link
+ * #ACTION_ADD_PROPERTY {@code add_property}: If {@code hasPermission(path,
+ * "add_property")} returns {@code true}, then this {@code Session} has
+ * permission to add a new property at {@code path}.
+ *
{@link #ACTION_MODIFY_PROPERTY {@code modify_property}}: If
+ * {@code hasPermission(path, "modify_property")} returns
+ * {@code true}, then this {@code Session} has permission to change
+ * a property at {@code path}.
+ *
{@link
+ * #ACTION_REMOVE_PROPERTY {@code remove_property}}: If {@code hasPermission(path,
+ * "remove_property")} returns {@code true}, then this {@code Session} has
+ * permission to remove a property at {@code path}.
+ *
{@link #ACTION_REMOVE_NODE {@code remove_node}}: If
+ * {@code hasPermission(path, "remove_node")} returns {@code true}, then
+ * this {@code Session} has permission to remove a node at {@code path}.
+ *
{@link #ACTION_NODE_TYPE_MANAGEMENT {@code node_type_management}}: If
+ * {@code hasPermission(path, "node_type_management")} returns {@code true}, then
+ * this {@code Session} has permission to explicitly set or change the node type
+ * information associated with a node at {@code path}.
+ *
{@link #ACTION_VERSIONING {@code versioning}}: If
+ * {@code hasPermission(path, "versioning")} returns {@code true}, then
+ * this {@code Session} has permission to perform version related operations
+ * on a node at {@code path}.
+ *
{@link #ACTION_LOCKING {@code locking}}: If
+ * {@code hasPermission(path, "locking")} returns {@code true}, then
+ * this {@code Session} has permission to lock and unlock a node at {@code path}.
+ *
{@link #ACTION_READ_ACCESS_CONTROL {@code read_access_control}}: If
+ * {@code hasPermission(path, "read_access_control")} returns {@code true}, then
+ * this {@code Session} has permission to read access control content stored
+ * at an item at {@code path}.
+ *
{@link #ACTION_MODIFY_ACCESS_CONTROL {@code modify_access_control}}: If
+ * {@code hasPermission(path, "modify_access_control")} returns {@code true}, then
+ * this {@code Session} has permission to modify access control content
+ * at an item at {@code path}.
+ *
{@link #ACTION_USER_MANAGEMENT {@code user_management}}: If
+ * {@code hasPermission(path, "user_management")} returns {@code true}, then
+ * this {@code Session} has permission to perform user management operations
+ * at an item at {@code path}.
+ *
+ *
+ * When more than one action is specified, this method will only return
+ * {@code true} if this {@code Session} has permission to perform all
+ * of the listed actions at the specified path.
+ *
+ * The information returned through this method will only reflect the permission
+ * status (both JCR defined and implementation-specific) and not
+ * other restrictions that may exist, such as node type or other
+ * implementation enforced constraints. For example, even though
+ * {@code hasPermission} may indicate that a particular {@code Session} may
+ * add a property at {@code /A/B/C}, the node type of the node at {@code /A/B}
+ * may prevent the addition of a property called {@code C}.
+ *
+ * @param absPath an absolute path.
+ * @param actions one or serveral actions.
+ * @return {@code true} if this {@code Session} has permission to
+ * perform the specified actions at the specified
+ * {@code absPath}.
+ * @throws RepositoryException if an error occurs.
+ * @see {@link Session#hasPermission(String, String)}
+ */
+ public boolean hasPermission(@Nonnull String absPath, @Nonnull String... actions) throws RepositoryException;
+
+ /**
+ * Returns the PrincipalManager for the current Session.
+ *
+ * @return the PrincipalManager associated with this Session.
+ * @throws AccessDeniedException If the session lacks privileges to access
+ * the principal manager or principals in general.
+ * @throws UnsupportedRepositoryOperationException If principal management
+ * is not supported.
+ * @throws RepositoryException If another error occurs.
+ * @see PrincipalManager
+ */
+ PrincipalManager getPrincipalManager() throws AccessDeniedException, UnsupportedRepositoryOperationException, RepositoryException;
+
+ /**
+ * Returns the UserManager for the current Session.
+ *
+ * @return the UserManager associated with this Session.
+ * @throws javax.jcr.AccessDeniedException If this session is not allowed to
+ * to access user data.
+ * @throws UnsupportedRepositoryOperationException If user management is
+ * not supported.
+ * @throws javax.jcr.RepositoryException If another error occurs.
+ * @see UserManager
+ */
+ UserManager getUserManager() throws AccessDeniedException, UnsupportedRepositoryOperationException, RepositoryException;
+
+ /**
+ * Returns the node at the specified absolute path in the workspace. If no
+ * such node exists, then it returns the property at the specified path.
+ * If no such property exists, then it return {@code null}.
+ *
+ * @param absPath An absolute path.
+ * @return the specified {@code Item} or {@code null}.
+ * @throws RepositoryException if another error occurs.
+ * @since 2.11.1
+ */
+ Item getItemOrNull(final String absPath) throws RepositoryException;
+
+ /**
+ * Returns the property at the specified absolute path in the workspace or
+ * {@code null} if no such node exists.
+ *
+ * @param absPath An absolute path.
+ * @return the specified {@code Property} or {@code null}.
+ * @throws RepositoryException if another error occurs.
+ * @since 2.11.1
+ */
+ Property getPropertyOrNull(final String absPath) throws RepositoryException;
+
+ /**
+ * Returns the node at the specified absolute path in the workspace or
+ * {@code null} if no such node exists.
+ *
+ * @param absPath An absolute path.
+ * @return the specified {@code Node} or {@code null}.
+ * @throws RepositoryException If another error occurs.
+ * @since 2.11.1
+ */
+ Node getNodeOrNull(final String absPath) throws RepositoryException;
+
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitValue.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitValue.java
new file mode 100644
index 00000000000..f458edec81f
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitValue.java
@@ -0,0 +1,56 @@
+/*
+ * 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.jackrabbit.api;
+
+import javax.jcr.Value;
+
+/**
+ * Values returned by Jackrabbit may implement this interface. The interface
+ * defines optional features. An application should check if the returned value
+ * is of this type before casting as in:
+ *
+ */
+public interface JackrabbitValue extends Value {
+
+ /**
+ * Get a unique identifier of the content of this value. Usually this is a
+ * message digest of the content (a cryptographically secure one-way hash).
+ * This allows to avoid processing large binary values multiple times.
+ *
+ * This method returns null if the identifier is unknown. The identifier may
+ * not always be available, for example if the value has not yet been saved
+ * or processed. Once an identifier is available, it will never change
+ * because values are immutable.
+ *
+ * If two values have the same identifier, the content of the value is
+ * guaranteed to be the same. However it is not guaranteed that two values
+ * with the same content will return the same identifier.
+ *
+ * The identifier is opaque, meaning it can have any format and size, however
+ * it is at normally about 50 characters and at most 255 characters long.
+ * The string only contains Unicode code points from 32 to 127 (including).
+ *
+ * @return the unique identifier or null
+ */
+ String getContentIdentity();
+
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitWorkspace.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitWorkspace.java
new file mode 100644
index 00000000000..fae4eb3911a
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitWorkspace.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.jackrabbit.api;
+
+import org.apache.jackrabbit.api.security.authorization.PrivilegeManager;
+import org.xml.sax.InputSource;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.RepositoryException;
+import javax.jcr.Workspace;
+
+/**
+ * The Jackrabbit workspace interface. This interface contains the
+ * Jackrabbit-specific extensions to the JCR {@link Workspace} interface.
+ */
+public interface JackrabbitWorkspace extends Workspace {
+
+ /**
+ * Creates a workspace with the given name.
+ *
+ * @param workspaceName name of the new workspace
+ * @throws AccessDeniedException if the current session is not allowed to
+ * create the workspace
+ * @throws RepositoryException if a workspace with the given name
+ * already exists or if another error occurs
+ * @see #getAccessibleWorkspaceNames()
+ */
+ void createWorkspace(String workspaceName)
+ throws AccessDeniedException, RepositoryException;
+
+ /**
+ * Creates a workspace with the given name and a workspace configuration
+ * template.
+ *
+ * @param workspaceName name of the new workspace
+ * @param workspaceTemplate the configuration template of the new workspace
+ * @throws AccessDeniedException if the current session is not allowed to
+ * create the workspace
+ * @throws RepositoryException if a workspace with the given name
+ * already exists or if another error occurs
+ * @see #getAccessibleWorkspaceNames()
+ */
+ void createWorkspace(String workspaceName, InputSource workspaceTemplate)
+ throws AccessDeniedException, RepositoryException;
+
+ /**
+ * Returns the privilege manager.
+ *
+ * @return the privilege manager.
+ * @throws RepositoryException If an error occurs.
+ */
+ PrivilegeManager getPrivilegeManager() throws RepositoryException;
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/ReferenceBinary.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/ReferenceBinary.java
new file mode 100644
index 00000000000..b4378e2d343
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/ReferenceBinary.java
@@ -0,0 +1,39 @@
+/*
+ * 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.jackrabbit.api;
+
+import javax.jcr.Binary;
+
+/**
+ * Referenceable binary. In addition to the normal JCR {@link Binary}
+ * functionality, implementations of this class contain a secure
+ * reference to the storage location of the binary stream. This
+ * reference can be used to efficiently copy binaries across servers as
+ * long as both the source and target servers use the same underlying
+ * storage for binaries.
+ */
+public interface ReferenceBinary extends Binary {
+
+ /**
+ * Returns a secure reference to this binary, or {@code null} if such
+ * a reference is not available.
+ *
+ * @return binary reference, or {@code null}
+ */
+ String getReference();
+
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/ReferenceBinaryException.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/ReferenceBinaryException.java
new file mode 100644
index 00000000000..4ae0f3b2f9c
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/ReferenceBinaryException.java
@@ -0,0 +1,27 @@
+/*
+ * 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.jackrabbit.api;
+
+import javax.jcr.RepositoryException;
+
+public class ReferenceBinaryException extends RepositoryException {
+
+ public ReferenceBinaryException(String message) {
+ super(message);
+ }
+
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/XASession.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/XASession.java
new file mode 100644
index 00000000000..efd0b3e7b73
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/XASession.java
@@ -0,0 +1,48 @@
+/*
+ * 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.jackrabbit.api;
+
+import javax.jcr.Session;
+import javax.transaction.xa.XAResource;
+
+/**
+ * The XASession interface extends the capability of {@link Session} by adding
+ * access to a JCR repository's support for the Java Transaction API (JTA).
+ *
+ * This support takes the form of a {@link javax.transaction.xa.XAResource}
+ * object. The functionality of this object closely resembles that defined by
+ * the standard X/Open XA Resource interface.
+ *
+ * This interface is used by the transaction manager; an application does not
+ * use it directly.
+ *
+ * @since 1.4
+ * @deprecated An XA-enabled session should directly implement the
+ * {@link javax.transaction.xa.XAResource} interface
+ */
+public interface XASession extends Session {
+
+ /**
+ * Retrieves an {@link XAResource} object that the transaction manager
+ * will use to manage this XASession object's participation in
+ * a distributed transaction.
+ *
+ * @return the {@link XAResource} object.
+ */
+ XAResource getXAResource();
+
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jmx/EventListenerMBean.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jmx/EventListenerMBean.java
new file mode 100644
index 00000000000..cee8df6dafc
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jmx/EventListenerMBean.java
@@ -0,0 +1,123 @@
+/*
+ * 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.jackrabbit.api.jmx;
+
+import javax.management.openmbean.CompositeData;
+
+/**
+ * MBean interface for exposing information about a registered observation
+ * listener.
+ *
+ * @see JCR-3608
+ */
+public interface EventListenerMBean {
+
+ /** Class name of the event listener */
+ String getClassName();
+
+ /** toString of the event listener */
+ String getToString();
+
+ /** Stack trace of where the listener was registered */
+ String getInitStackTrace();
+
+ /** Event types of the listener registration */
+ int getEventTypes();
+
+ /** Absolute path of the listener registration */
+ String getAbsPath();
+
+ /** Whether the listener registration is deep */
+ boolean isDeep();
+
+ /** UUIDs of the listener registration */
+ String[] getUuid();
+
+ /** Node types of the listener registration */
+ String[] getNodeTypeName();
+
+ /** Whether the listener registration is non-local */
+ boolean isNoLocal();
+
+ /** Number of {@code onEvent()} calls made on the listener */
+ long getEventDeliveries();
+
+ /** Average number of {@code onEvent()} calls per hour */
+ long getEventDeliveriesPerHour();
+
+ /** Average time (in microseconds) taken per {@code onEvent()} call */
+ long getMicrosecondsPerEventDelivery();
+
+ /** Number of individual events delivered to the listener */
+ long getEventsDelivered();
+
+ /** Average number of individual events delivered per hour */
+ long getEventsDeliveredPerHour();
+
+ /** Average time (in microseconds) taken per event delivered */
+ long getMicrosecondsPerEventDelivered();
+
+ /** Ratio of time spent in event processing */
+ double getRatioOfTimeSpentProcessingEvents();
+
+ /** Ratio of time spent in event listener vs. the overall event processing */
+ double getEventConsumerTimeRatio();
+
+ /** Is user information accessed without checking if an event is external? */
+ boolean isUserInfoAccessedWithoutExternalsCheck();
+
+ /** Is user information accessed from an external event? */
+ boolean isUserInfoAccessedFromExternalEvent();
+
+ /** Is date information accessed without checking if an event is external? */
+ boolean isDateAccessedWithoutExternalsCheck();
+
+ /** Is date information accessed from an external event? */
+ boolean isDateAccessedFromExternalEvent();
+
+ /**
+ * The time difference between the current system time and the head (oldest)
+ * element in the queue in milliseconds. This method returns zero if the
+ * queue is empty.
+ */
+ long getQueueBacklogMillis();
+
+ /**
+ * {@link org.apache.jackrabbit.api.stats.TimeSeries time series} of the number of
+ * items related to generating observation events that are currently queued by the
+ * system. The exact nature of these items is implementation specific and might not
+ * be in a one to one relation with the number of pending JCR events.
+ * @return time series of the queue length
+ */
+ CompositeData getQueueLength();
+
+ /**
+ * @return time series of the number of JCR events
+ */
+ CompositeData getEventCount();
+
+ /**
+ * @return time series of the time it took an event listener to process JCR events.
+ */
+ CompositeData getEventConsumerTime();
+
+ /**
+ * @return time series of the time it took the system to produce JCR events.
+ */
+ CompositeData getEventProducerTime();
+
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jmx/ManagedRepositoryMBean.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jmx/ManagedRepositoryMBean.java
new file mode 100644
index 00000000000..751667af16e
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jmx/ManagedRepositoryMBean.java
@@ -0,0 +1,68 @@
+/*
+ * 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.jackrabbit.api.jmx;
+
+import java.util.Map;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * Interface for managing a JCR repository as a JMX MBean.
+ *
+ * @since Apache Jackrabbit 2.3
+ */
+public interface ManagedRepositoryMBean {
+
+ /**
+ * Returns the name of this repository implementation.
+ *
+ * @see javax.jcr.Repository#REP_NAME_DESC
+ * @return name of this repository implementation
+ */
+ String getName();
+
+ /**
+ * Returns the version of this repository implementation.
+ *
+ * @see javax.jcr.Repository#REP_VERSION_DESC
+ * @return version of this repository implementation
+ */
+ String getVersion();
+
+ /**
+ * Returns all the repository descriptors.
+ *
+ * @return repository descriptors
+ */
+ Map getDescriptors();
+
+ /**
+ * Returns the names of all the workspaces in this repository.
+ *
+ * @return workspace names
+ */
+ String[] getWorkspaceNames();
+
+ /**
+ * Creates a new workspace with the given name.
+ *
+ * @param name workspace name
+ * @throws RepositoryException if the workspace could not be created
+ */
+ void createWorkspace(String name) throws RepositoryException;
+
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jmx/QueryStatManagerMBean.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jmx/QueryStatManagerMBean.java
new file mode 100644
index 00000000000..8cbd23d25d0
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jmx/QueryStatManagerMBean.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.jackrabbit.api.jmx;
+
+import javax.management.openmbean.TabularData;
+
+import org.apache.jackrabbit.api.stats.QueryStat;
+
+/**
+ * JMX Bindings for {@link QueryStat}.
+ *
+ */
+public interface QueryStatManagerMBean {
+
+ String NAME = "org.apache.jackrabbit:type=QueryStats";
+
+ /**
+ * @return a sorted array containing the top
+ * {@link #getSlowQueriesQueueSize()} slowest queries
+ */
+ TabularData getSlowQueries();
+
+ /**
+ * @return a sorted array containing the
+ * {@link #getPopularQueriesQueueSize()} most popular queries
+ */
+ TabularData getPopularQueries();
+
+ /**
+ * @return size of the Slow queue
+ */
+ int getSlowQueriesQueueSize();
+
+ /**
+ * Change the size of the Slow queue
+ *
+ * @param size
+ * the new size
+ */
+ void setSlowQueriesQueueSize(int size);
+
+ /**
+ * clears the Slow queue
+ */
+ void clearSlowQueriesQueue();
+
+ /**
+ * @return size of the Popular queue
+ */
+ int getPopularQueriesQueueSize();
+
+ /**
+ * Change the size of the Popular queue
+ *
+ * @param size
+ * the new size
+ */
+ void setPopularQueriesQueueSize(int size);
+
+ /**
+ * clears the Popular queue
+ */
+ void clearPopularQueriesQueue();
+
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jmx/package-info.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jmx/package-info.java
new file mode 100644
index 00000000000..7069a3b6418
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jmx/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/**
+ * JMX management interfaces for JCR.
+ */
+@aQute.bnd.annotation.Version("2.3.0")
+package org.apache.jackrabbit.api.jmx;
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/management/DataStoreGarbageCollector.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/management/DataStoreGarbageCollector.java
new file mode 100644
index 00000000000..3b5061dca9a
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/management/DataStoreGarbageCollector.java
@@ -0,0 +1,106 @@
+/*
+ * 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.jackrabbit.api.management;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * Garbage collector for DataStore. This implementation iterates through all
+ * nodes and reads the binary properties. To detect nodes that are moved while
+ * the scan runs, event listeners are started. Like the well known garbage
+ * collection in Java, the items that are still in use are marked. Currently
+ * this is achieved by updating the modified date of the entries. Newly added
+ * entries are detected because the modified date is changed when they are
+ * added.
+ *
+ * Example code to run the data store garbage collection:
+ *
+ */
+public interface DataStoreGarbageCollector {
+
+ /**
+ * Set the delay between scanning items.
+ * The main scan loop sleeps this many milliseconds after
+ * scanning a node. The default is 0, meaning the scan should run at full speed.
+ *
+ * @param millis the number of milliseconds to sleep
+ */
+ void setSleepBetweenNodes(long millis);
+
+ /**
+ * Get the delay between scanning items.
+ *
+ * @return the number of milliseconds to sleep
+ */
+ long getSleepBetweenNodes();
+
+ /**
+ * Set the event listener. If set, the event listener will be called
+ * for each item that is scanned. This mechanism can be used
+ * to display the progress.
+ *
+ * @param callback if set, this is called while scanning
+ */
+ void setMarkEventListener(MarkEventListener callback);
+
+ /**
+ * Enable or disable using the IterablePersistenceManager interface
+ * to scan the items. This is important for clients that need
+ * the complete Node implementation in the ScanEventListener
+ * callback.
+ *
+ * @param allow true if using the IterablePersistenceManager interface is allowed
+ */
+ void setPersistenceManagerScan(boolean allow);
+
+ /**
+ * Check if using the IterablePersistenceManager interface is allowed.
+ *
+ * @return true if using IterablePersistenceManager is possible.
+ */
+ boolean isPersistenceManagerScan();
+
+ /**
+ * Scan the repository. The garbage collector will iterate over all nodes in the repository
+ * and update the last modified date. If all persistence managers implement the
+ * IterablePersistenceManager interface, this mechanism is used; if not, the garbage
+ * collector scans the repository using the JCR API starting from the root node.
+ *
+ * @throws RepositoryException
+ */
+ void mark() throws RepositoryException;
+
+ /**
+ * Delete all unused items in the data store.
+ *
+ * @return the number of deleted items
+ * @throws RepositoryException
+ */
+ int sweep() throws RepositoryException;
+
+ /**
+ * Cleanup resources used internally by this instance.
+ */
+ void close();
+
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/management/MarkEventListener.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/management/MarkEventListener.java
new file mode 100644
index 00000000000..8dd6bf0980d
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/management/MarkEventListener.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.jackrabbit.api.management;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+/**
+ * The listener interface for receiving garbage collection scan events.
+ */
+public interface MarkEventListener {
+
+ /**
+ * This method is called before a node is scanned.
+ */
+ void beforeScanning(Node n) throws RepositoryException;
+
+}
\ No newline at end of file
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/management/RepositoryManager.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/management/RepositoryManager.java
new file mode 100644
index 00000000000..2db260c4a9a
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/management/RepositoryManager.java
@@ -0,0 +1,50 @@
+/*
+ * 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.jackrabbit.api.management;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * The repository manager provides life-cycle management features for
+ * repositories.
+ *
+ * Not all implementations are required to implement all features,
+ * for example some implementations may not support starting a repository after
+ * is has been stopped.
+ */
+public interface RepositoryManager {
+
+ /**
+ * Shuts down the repository. A Jackrabbit repository instance contains
+ * a acquired resources and cached data that needs to be released and
+ * persisted when the repository is no longer used. This method handles
+ * all these shutdown tasks and should therefore be called by the
+ * client application once the repository instance is no longer used.
+ *
+ * Possible errors are logged rather than thrown as exceptions as there
+ * is little that a client application could do in such a case.
+ */
+ void stop();
+
+ /**
+ * Create a data store garbage collector for this repository.
+ *
+ * @return the data store garbage collector if the data store is enabled, null otherwise
+ */
+ DataStoreGarbageCollector createDataStoreGarbageCollector() throws RepositoryException;
+
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/management/package-info.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/management/package-info.java
new file mode 100644
index 00000000000..081df6b6be8
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/management/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/**
+ * Interfaces for managing a Jackrabbit repository.
+ */
+@aQute.bnd.annotation.Version("2.3.1")
+package org.apache.jackrabbit.api.management;
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/observation/JackrabbitEvent.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/observation/JackrabbitEvent.java
new file mode 100644
index 00000000000..a7e7a05b448
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/observation/JackrabbitEvent.java
@@ -0,0 +1,35 @@
+/*
+ * 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.jackrabbit.api.observation;
+
+import javax.jcr.observation.Event;
+
+/**
+ * This is an extension of the event interface which provides
+ * a method to detect whether the changes happened on locally
+ * or remotely in a clustered environment.
+ */
+public interface JackrabbitEvent extends Event {
+
+ /**
+ * Return a flag indicating whether this is an externally generated event.
+ *
+ * @return true if this is an external event;
+ * false otherwise
+ */
+ boolean isExternal();
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/observation/JackrabbitEventFilter.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/observation/JackrabbitEventFilter.java
new file mode 100644
index 00000000000..be63fbebcb4
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/observation/JackrabbitEventFilter.java
@@ -0,0 +1,309 @@
+/*
+ * 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.jackrabbit.api.observation;
+
+import static java.util.Arrays.copyOf;
+
+/**
+ * A storage object for event filter configuration.
+ *
+ * The parameters of the filter can then be set by chaining the set methods,
+ * since each method returns the same EventFilter with the indicated parameter set.
+ *
+ * Once the filter is configured, it and an {@link javax.jcr.observation.EventListener} object are
+ * passed to
+ * {@link org.apache.jackrabbit.api.observation.JackrabbitObservationManager#addEventListener(javax.jcr.observation.EventListener, JackrabbitEventFilter)}.
+ *
+ * The filter restricts which events are sent to the EventListener according to the
+ * following parameters. Note that the term associated parent node of an event means the
+ * parent node of the item at (or formerly at) the path returned by
+ * {@link javax.jcr.observation.Event#getPath}.
+ *
+ *
+ * eventTypes:
+ * A bitwise OR of the event types to be listened to. See
+ * {@link javax.jcr.observation.Event} for details.
+ *
+ *
+ * absPath, absPaths, excludedPaths,
+ * isDeep: Only events whose associated parent node is at one
+ * of the paths in absPath or absPaths (or within
+ * its subgraph, if isDeep is true) will be received
+ * except if the associated parent node is at one of the paths in
+ * excludedPaths or its subgraph.
+ * It is permissible to register a listener for a path where no node currently
+ * exists.
+ *
+ *
+ * uuid:
+ * Only events whose associated parent node has one of
+ * the identifiers in this list will be received. If his parameter is
+ * null then no identifier-related restriction is placed on
+ * events received. Note that specifying an empty array instead of
+ * null would result in no nodes being listened to. The term
+ * "UUID" is used for compatibility with JCR 1.0.
+ *
+ *
+ * nodeTypeName:
+ * Only events whose associated parent node has
+ * one of the node types (or a subtype of one of the node types) in this
+ * list will be received. If his parameter is null then no node
+ * type-related restriction is placed on events received. Note that
+ * specifying an empty array instead of null would result in no
+ * nodes types being listened to.
+ *
+ *
+ * noLocal: if true, then events
+ * generated by the session through which the listener was registered are
+ * ignored. Otherwise, they are not ignored.
+ *
+ *
+ * noExternal: if true, then events
+ * from external cluster nodes are ignored. Otherwise, they are not ignored.
+ *
+ *
+ * noInternal: if true, then events
+ * from this cluster node are ignored. Otherwise, they are not ignored.
+ *
+ *
+ * The restrictions are "ANDed" together. In other words, for a particular node to be "listened to" it
+ * must meet all the restrictions.
+ *
+ */
+public class JackrabbitEventFilter { // TODO extends EventFilter once JCR 2.1 is out
+ private int eventTypes;
+ private String absPath;
+ private boolean isDeep;
+ private String[] identifiers;
+ private String[] nodeTypeNames;
+ private boolean noLocal;
+ private String[] absPaths = new String[]{};
+ private String[] excludedPaths = new String[]{};
+ private boolean noExternal;
+ private boolean noInternal;
+
+ /**
+ * Sets the eventTypes parameter of the filter.
+ * If left unset, this parameter defaults to 0.
+ *
+ * @param eventTypes an int.
+ * @return This EventFilter object with the eventTypes parameter set.
+ */
+ public JackrabbitEventFilter setEventTypes(int eventTypes) {
+ this.eventTypes = eventTypes;
+ return this;
+ }
+
+ /**
+ * Returns the eventTypes parameter of the filter.
+ *
+ * @return an int.
+ */
+ public int getEventTypes() {
+ return eventTypes;
+ }
+
+ /**
+ * Sets the absPath parameter of the filter.
+ * If left unset, this parameter defaults to null.
+ *
+ * @param absPath an absolute path String.
+ * @return This EventFilter object with the absPath parameter set.
+ */
+ public JackrabbitEventFilter setAbsPath(String absPath) {
+ this.absPath = absPath;
+ return this;
+ }
+
+ /**
+ * Returns the absPath parameter of the filter.
+ *
+ * @return a String.
+ */
+ public String getAbsPath() {
+ return absPath;
+ }
+
+ /**
+ * Sets the isDeep parameter of the filter.
+ * If left unset, this parameter defaults to false.
+ *
+ * @param isDeep a boolean.
+ * @return This EventFilter object with the isDeep parameter set.
+ */
+ public JackrabbitEventFilter setIsDeep(boolean isDeep) {
+ this.isDeep = isDeep;
+ return this;
+ }
+
+ /**
+ * Returns the isDeep parameter of the filter.
+ *
+ * @return a boolean.
+ */
+ public boolean getIsDeep() {
+ return isDeep;
+ }
+
+ /**
+ * Sets the identifiers parameter of the filter.
+ * If left unset, this parameter defaults to null.
+ *
+ * @param identifiers a String array.
+ * @return This EventFilter object with the identifiers parameter set.
+ */
+ public JackrabbitEventFilter setIdentifiers(String[] identifiers) {
+ this.identifiers = copyOf(identifiers, identifiers.length);
+ return null;
+ }
+
+ /**
+ * Returns the uuids parameter of the filter.
+ *
+ * @return a String array.
+ */
+ public String[] getIdentifiers() {
+ return identifiers == null ? null : copyOf(identifiers, identifiers.length);
+ }
+
+ /**
+ * Sets the nodeTypeNames parameter of the filter.
+ * If left unset, this parameter defaults to null.
+ *
+ * @param nodeTypeNames a String array.
+ * @return This EventFilter object with the nodeTypes parameter set.
+ */
+ public JackrabbitEventFilter setNodeTypes(String[] nodeTypeNames) {
+ this.nodeTypeNames = copyOf(nodeTypeNames, nodeTypeNames.length);
+ return this;
+ }
+
+ /**
+ * Returns the nodeTypeName parameter of the filter.
+ *
+ * @return a String array.
+ */
+ public String[] getNodeTypes() {
+ return nodeTypeNames == null ? null : copyOf(nodeTypeNames, nodeTypeNames.length);
+ }
+
+ /**
+ * Sets the noLocal parameter of the filter.
+ * If left unset, this parameter defaults to false.
+ *
+ * @param noLocal a boolean.
+ * @return This EventFilter object with the noLocal parameter set.
+ */
+ public JackrabbitEventFilter setNoLocal(boolean noLocal) {
+ this.noLocal = noLocal;
+ return this;
+ }
+
+ /**
+ * Returns the noLocal parameter of the filter.
+ *
+ * @return a boolean.
+ */
+ public boolean getNoLocal() {
+ return noLocal;
+ }
+
+ /**
+ * Sets the absPaths parameter of the filter.
+ * If left unset, this parameter defaults to an empty array.
+ *
+ * @param absPaths an absolute path String array.
+ * @return This EventFilter object with the absPaths parameter set.
+ */
+ public JackrabbitEventFilter setAdditionalPaths(String... absPaths) {
+ this.absPaths = copyOf(absPaths, absPaths.length);
+ return this;
+ }
+
+ /**
+ * Returns the absPaths parameter of the filter.
+ *
+ * @return a String array.
+ */
+ public String[] getAdditionalPaths() {
+ return copyOf(absPaths, absPaths.length);
+ }
+
+ /**
+ * Sets the excludedPaths parameter of the filter.
+ * If left unset, this parameter defaults to an empty array.
+ *
+ * @param excludedPaths an absolute path String array.
+ * @return This EventFilter object with the excludedPaths parameter set.
+ */
+ public JackrabbitEventFilter setExcludedPaths(String... excludedPaths) {
+ this.excludedPaths = copyOf(excludedPaths, excludedPaths.length);
+ return this;
+ }
+
+ /**
+ * Returns the excludedPaths parameter of the filter.
+ *
+ * @return a String array.
+ */
+ public String[] getExcludedPaths() {
+ return copyOf(excludedPaths, excludedPaths.length);
+ }
+
+ /**
+ * Sets the noExternal parameter of the filter.
+ * If left unset, this parameter defaults to false.
+ *
+ * @param noExternal a boolean.
+ * @return This EventFilter object with the noExternal parameter set.
+ */
+ public JackrabbitEventFilter setNoExternal(boolean noExternal) {
+ this.noExternal = noExternal;
+ return this;
+ }
+
+ /**
+ * Returns the noExternal parameter of the filter.
+ *
+ * @return a boolean.
+ */
+ public boolean getNoExternal() {
+ return noExternal;
+ }
+
+ /**
+ * Sets the noInternal parameter of the filter.
+ * If left unset, this parameter defaults to false.
+ *
+ * @param noInternal a boolean.
+ * @return This EventFilter object with the noExternal parameter set.
+ */
+ public JackrabbitEventFilter setNoInternal(boolean noInternal) {
+ this.noInternal = noInternal;
+ return this;
+ }
+
+ /**
+ * Returns the noInternal parameter of the filter.
+ *
+ * @return a boolean.
+ */
+ public boolean getNoInternal() {
+ return noInternal;
+ }
+
+}
\ No newline at end of file
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/observation/JackrabbitObservationManager.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/observation/JackrabbitObservationManager.java
new file mode 100644
index 00000000000..122ad5aa8e9
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/observation/JackrabbitObservationManager.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.jackrabbit.api.observation;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.observation.EventListener;
+import javax.jcr.observation.ObservationManager;
+
+/**
+ * Jackrabbit specific extensions to {@link javax.jcr.observation.ObservationManager}.
+ */
+public interface JackrabbitObservationManager extends ObservationManager {
+
+ /**
+ * Adds an event listener that listens for the events specified
+ * by the passed {@link JackrabbitEventFilter}.
+ *
+ * In addition to the EventFilter, the set of events reported
+ * will be further filtered by the access rights of the
+ * current Session.
+ *
+ * See {@link JackrabbitEventFilter} for a description of the filtering parameters available.
+ *
+ * The filter of an already-registered EventListener can be
+ * changed at runtime by re-registering the same EventListener
+ * object (i.e. the same actual Java object) with a new filter.
+ * The implementation must ensure that no events are lost during the changeover.
+ *
+ * In addition to the filters placed on a listener above, the scope of
+ * observation support, in terms of which parts of a workspace are observable, may also
+ * be subject to implementation-specific restrictions. For example, in some
+ * repositories observation of changes in the jcr:system
+ * subgraph may not be supported.
+ *
+ * @param listener an {@link EventListener} object.
+ * @param filter an {@link JackrabbitEventFilter} object.
+ * @throws RepositoryException If an error occurs.
+ */
+ void addEventListener(EventListener listener, JackrabbitEventFilter filter)
+ throws RepositoryException;
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/observation/package-info.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/observation/package-info.java
new file mode 100644
index 00000000000..e719d247599
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/observation/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/**
+ * Jackrabbit extensions for JCR observation.
+ */
+@aQute.bnd.annotation.Version("2.3.1")
+package org.apache.jackrabbit.api.observation;
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/package-info.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/package-info.java
new file mode 100644
index 00000000000..e69ad96350d
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/**
+ * Jackrabbit extensions for JCR core interfaces
+ */
+@aQute.bnd.annotation.Version("2.4")
+package org.apache.jackrabbit.api;
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/query/JackrabbitQueryResult.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/query/JackrabbitQueryResult.java
new file mode 100644
index 00000000000..101c4e95456
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/query/JackrabbitQueryResult.java
@@ -0,0 +1,38 @@
+/*
+ * 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.jackrabbit.api.query;
+
+import javax.jcr.query.QueryResult;
+
+/**
+ * The Jackrabbit query result interface. This interface contains the
+ * Jackrabbit-specific extensions to the JCR {@link QueryResult} interface.
+ *
+ * @since Jackrabbit 2.6
+ */
+public interface JackrabbitQueryResult extends QueryResult {
+
+ /**
+ * Returns the total number of hits. This is the number of results you
+ * would get without any limit or offset settings. This method may return
+ * -1 if the total size is unknown.
+ *
+ * @return the total number of hits, or -1
+ */
+ int getTotalSize();
+
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/JackrabbitAccessControlEntry.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/JackrabbitAccessControlEntry.java
new file mode 100644
index 00000000000..21d971cf3c1
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/JackrabbitAccessControlEntry.java
@@ -0,0 +1,78 @@
+/*
+ * 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.jackrabbit.api.security;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+import javax.jcr.security.AccessControlEntry;
+
+/**
+ * JackrabbitAccessControlEntry is a Jackrabbit specific extension
+ * of the AccessControlEntry interface. It represents an single
+ * entry of a {@link JackrabbitAccessControlList}.
+ */
+public interface JackrabbitAccessControlEntry extends AccessControlEntry {
+
+ /**
+ * @return true if this entry adds Privileges for the principal;
+ * false otherwise.
+ */
+ boolean isAllow();
+
+ /**
+ * Return the names of the restrictions present with this access control entry.
+ *
+ * @return the names of the restrictions
+ * @throws RepositoryException if an error occurs.
+ */
+ String[] getRestrictionNames() throws RepositoryException;
+
+ /**
+ * Return the value of the restriction with the specified name or
+ * null if no such restriction exists. In case the restriction
+ * with the specified name contains multiple value this method will call
+ * {@code ValueFormatException}.
+ *
+ * @param restrictionName The of the restriction as obtained through
+ * {@link #getRestrictionNames()}.
+ * @return value of the restriction with the specified name or
+ * null if no such restriction exists.
+ * @throws ValueFormatException If the restriction with the specified name
+ * contains multiple values.
+ * @throws RepositoryException if an error occurs.
+ * @see {@link #getRestrictions(String)}
+ */
+ Value getRestriction(String restrictionName) throws ValueFormatException, RepositoryException;
+
+ /**
+ * Return the values of the restriction with the specified name or
+ * null if no such restriction exists. For restrictions that
+ * contain just a single value this method is expected to return an array
+ * with a single element even if the underlying implementation stored the
+ * restriction in single-value JCR property.
+ *
+ * @param restrictionName The of the restriction as obtained through
+ * {@link #getRestrictionNames()}.
+ * @return the values of the restriction with the specified name as an array
+ * or null if no such restriction exists. The array may contain
+ * zero, one or multiple values.
+ * @throws RepositoryException if an error occurs.
+ * @see {@link #getRestriction(String)}
+ */
+ Value[] getRestrictions(String restrictionName) throws RepositoryException;
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/JackrabbitAccessControlList.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/JackrabbitAccessControlList.java
new file mode 100644
index 00000000000..9d08a405b38
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/JackrabbitAccessControlList.java
@@ -0,0 +1,172 @@
+/*
+ * 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.jackrabbit.api.security;
+
+import java.security.Principal;
+import java.util.Map;
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.Value;
+import javax.jcr.security.AccessControlEntry;
+import javax.jcr.security.AccessControlException;
+import javax.jcr.security.AccessControlList;
+import javax.jcr.security.AccessControlPolicy;
+import javax.jcr.security.Privilege;
+
+/**
+ * JackrabbitAccessControlList is an extension of the AccessControlList.
+ * Similar to the latter any modifications made will not take effect, until it is
+ * {@link javax.jcr.security.AccessControlManager#setPolicy(String, AccessControlPolicy)
+ * written back} and {@link javax.jcr.Session#save() saved}.
+ */
+public interface JackrabbitAccessControlList extends JackrabbitAccessControlPolicy, AccessControlList {
+
+ /**
+ * Returns the names of the supported restrictions or an empty array
+ * if no restrictions are respected.
+ *
+ * @return the names of the supported restrictions or an empty array.
+ * @see #addEntry(Principal, Privilege[], boolean, Map)
+ * @throws RepositoryException If an error occurs.
+ */
+ String[] getRestrictionNames() throws RepositoryException;
+
+ /**
+ * Return the expected {@link javax.jcr.PropertyType property type} of the
+ * restriction with the specified restrictionName.
+ *
+ * @param restrictionName Any of the restriction names retrieved from
+ * {@link #getRestrictionNames()}.
+ * @return expected {@link javax.jcr.PropertyType property type}.
+ * @throws RepositoryException If an error occurs.
+ */
+ int getRestrictionType(String restrictionName) throws RepositoryException;
+
+ /**
+ * Returns true if this policy does not yet define any
+ * entries.
+ *
+ * @return If no entries are present.
+ */
+ boolean isEmpty();
+
+ /**
+ * Returns the number of entries or 0 if the policy {@link #isEmpty() is empty}.
+ *
+ * @return The number of entries present or 0 if the policy {@link #isEmpty() is empty}.
+ */
+ int size();
+
+ /**
+ * Same as {@link #addEntry(Principal, Privilege[], boolean, Map)} using
+ * some implementation specific restrictions.
+ *
+ * @param principal the principal to add the entry for
+ * @param privileges the privileges to add
+ * @param isAllow if true if this is a positive (allow) entry
+ * @return true if this policy has changed by incorporating the given entry;
+ * false otherwise.
+ * @throws AccessControlException If any of the given parameter is invalid
+ * or cannot be handled by the implementation.
+ * @throws RepositoryException If another error occurs.
+ * @see AccessControlList#addAccessControlEntry(Principal, Privilege[])
+ */
+ boolean addEntry(Principal principal, Privilege[] privileges, boolean isAllow)
+ throws AccessControlException, RepositoryException;
+
+ /**
+ * Adds an access control entry to this policy consisting of the specified
+ * principal, the specified privileges, the
+ * isAllow flag and an optional map containing additional
+ * restrictions.
+ *
+ * This method returns true if this policy was modified,
+ * false otherwise.
+ *
+ * An AccessControlException is thrown if any of the specified
+ * parameters is invalid or if some other access control related exception occurs.
+ *
+ * @param principal the principal to add the entry for
+ * @param privileges the privileges to add
+ * @param isAllow if true if this is a positive (allow) entry
+ * @param restrictions A map of additional restrictions used to narrow the
+ * effect of the entry to be created. The map must map JCR names to a single
+ * {@link javax.jcr.Value} object.
+ * @return true if this policy has changed by incorporating the given entry;
+ * false otherwise.
+ * @throws AccessControlException If any of the given parameter is invalid
+ * or cannot be handled by the implementation.
+ * @throws RepositoryException If another error occurs.
+ * @see AccessControlList#addAccessControlEntry(Principal, Privilege[])
+ */
+ boolean addEntry(Principal principal, Privilege[] privileges,
+ boolean isAllow, Map restrictions)
+ throws AccessControlException, RepositoryException;
+
+ /**
+ * Adds an access control entry to this policy consisting of the specified
+ * principal, the specified privileges, the
+ * isAllow flag and an optional map containing additional
+ * restrictions.
+ *
+ * This method returns true if this policy was modified,
+ * false otherwise.
+ *
+ * An AccessControlException is thrown if any of the specified
+ * parameters is invalid or if some other access control related exception occurs.
+ *
+ * @param principal the principal to add the entry for
+ * @param privileges the privileges to add
+ * @param isAllow if true if this is a positive (allow) entry
+ * @param restrictions A map of additional restrictions used to narrow the
+ * effect of the entry to be created. The map must map JCR names to a single
+ * {@link javax.jcr.Value} object.
+ * @param restrictions A map of additional multivalued restrictions used to narrow the
+ * effect of the entry to be created. The map must map JCR names to a
+ * {@link javax.jcr.Value} array.
+ * @return true if this policy has changed by incorporating the given entry;
+ * false otherwise.
+ * @throws AccessControlException If any of the given parameter is invalid
+ * or cannot be handled by the implementation.
+ * @throws RepositoryException If another error occurs.
+ * @see AccessControlList#addAccessControlEntry(Principal, Privilege[])
+ * @since 2.8
+ */
+ boolean addEntry(Principal principal, Privilege[] privileges,
+ boolean isAllow, Map restrictions,
+ Map mvRestrictions)
+ throws AccessControlException, RepositoryException;
+
+ /**
+ * If the AccessControlList implementation supports
+ * reordering of entries the specified srcEntry is inserted
+ * at the position of the specified destEntry.
+ * If destEntry is null the entry is moved to the
+ * end of the list.
+ * If srcEntry and destEntry are the same no
+ * changes are made.
+ *
+ * @param srcEntry The access control entry to be moved within the list.
+ * @param destEntry The entry before which the srcEntry will be moved.
+ * @throws AccessControlException If any of the given entries is invalid or
+ * cannot be handled by the implementation.
+ * @throws UnsupportedRepositoryOperationException If ordering is not supported.
+ * @throws RepositoryException If another error occurs.
+ */
+ void orderBefore(AccessControlEntry srcEntry, AccessControlEntry destEntry)
+ throws AccessControlException, UnsupportedRepositoryOperationException, RepositoryException;
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/JackrabbitAccessControlManager.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/JackrabbitAccessControlManager.java
new file mode 100644
index 00000000000..4dd221f33e1
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/JackrabbitAccessControlManager.java
@@ -0,0 +1,164 @@
+/*
+ * 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.jackrabbit.api.security;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.security.AccessControlException;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.AccessControlPolicy;
+import javax.jcr.security.Privilege;
+import java.security.Principal;
+import java.util.Set;
+
+/**
+ * JackrabbitAccessControlManager provides extensions to the
+ * AccessControlManager interface.
+ */
+public interface JackrabbitAccessControlManager extends AccessControlManager {
+
+ /**
+ * Returns the applicable policies for the specified principal
+ * or an empty array if no additional policies can be applied.
+ *
+ * @param principal A principal known to the editing session.
+ * @return array of policies for the specified principal. Note
+ * that the policy object returned must reveal the path of the node where
+ * they can be applied later on using {@link AccessControlManager#setPolicy(String, javax.jcr.security.AccessControlPolicy)}.
+ * @throws AccessDeniedException if the session lacks
+ * MODIFY_ACCESS_CONTROL privilege.
+ * @throws AccessControlException if the specified principal does not exist
+ * or if another access control related exception occurs.
+ * @throws UnsupportedRepositoryOperationException if editing access control
+ * policies by principal is not supported.
+ * @throws RepositoryException if another error occurs.
+ * @see JackrabbitAccessControlPolicy#getPath()
+ */
+ JackrabbitAccessControlPolicy[] getApplicablePolicies(Principal principal) throws AccessDeniedException, AccessControlException, UnsupportedRepositoryOperationException, RepositoryException;
+
+ /**
+ * Returns the AccessControlPolicy objects that have been set
+ * for the given principal or an empty array if no policy has
+ * been set. This method reflects the binding state, including transient
+ * policy modifications.
+ *
+ * @param principal A valid principal.
+ * @return The policies defined for the given principal or an empty array.
+ * @throws AccessDeniedException if the session lacks
+ * READ_ACCESS_CONTROL privilege.
+ * @throws AccessControlException if the specified principal does not exist
+ * or if another access control related exception occurs.
+ * @throws UnsupportedRepositoryOperationException if editing access control
+ * policies by principal is not supported.
+ * @throws RepositoryException If another error occurs.
+ */
+ JackrabbitAccessControlPolicy[] getPolicies(Principal principal) throws AccessDeniedException, AccessControlException, UnsupportedRepositoryOperationException, RepositoryException;
+
+ /**
+ * Returns the AccessControlPolicy objects that are in effect
+ * for the given Principals. This may be policies set through
+ * this API or some implementation specific (default) policies.
+ *
+ * @param principals A set of valid principals.
+ * @return The policies defined for the given principal or an empty array.
+ * @throws AccessDeniedException if the session lacks
+ * READ_ACCESS_CONTROL privilege.
+ * @throws AccessControlException if the specified principal does not exist
+ * or if another access control related exception occurs.
+ * @throws UnsupportedRepositoryOperationException if editing access control
+ * policies by principal is not supported.
+ * @throws RepositoryException If another error occurs.
+ */
+ AccessControlPolicy[] getEffectivePolicies(Set principals) throws AccessDeniedException, AccessControlException, UnsupportedRepositoryOperationException, RepositoryException;
+
+ /**
+ * Returns whether the given set of Principals has the specified
+ * privileges for absolute path absPath, which must be an
+ * existing node.
+ *
+ * Testing an aggregate privilege is equivalent to testing each non
+ * aggregate privilege among the set returned by calling
+ * Privilege.getAggregatePrivileges() for that privilege.
+ *
+ * The results reported by the this method reflect the net effect of
+ * the currently applied control mechanisms. It does not reflect unsaved
+ * access control policies or unsaved access control entries. Changes to
+ * access control status caused by these mechanisms only take effect on
+ * Session.save() and are only then reflected in the results of
+ * the privilege test methods.
+ *
+ * Since this method allows to view the privileges of principals other
+ * than included in the editing session, this method must throw
+ * AccessDeniedException if the session lacks
+ * READ_ACCESS_CONTROL privilege for the absPath
+ * node.
+ *
+ * @param absPath an absolute path.
+ * @param principals a set of Principals for which is the
+ * given privileges are tested.
+ * @param privileges an array of Privileges.
+ * @return true if the session has the specified privileges;
+ * false otherwise.
+ * @throws javax.jcr.PathNotFoundException if no node at absPath exists
+ * or the session does not have sufficient access to retrieve a node at that location.
+ * @throws AccessDeniedException if the session lacks
+ * READ_ACCESS_CONTROL privilege for the absPath node.
+ * @throws RepositoryException if another error occurs.
+ */
+ public boolean hasPrivileges(String absPath, Set principals, Privilege[] privileges)
+ throws PathNotFoundException, AccessDeniedException, RepositoryException;
+
+ /**
+ * Returns the privileges the given set of Principals has for
+ * absolute path absPath, which must be an existing node.
+ *
+ * The returned privileges are those for which {@link #hasPrivileges} would
+ * return true.
+ *
+ * The results reported by the this method reflect the net effect of
+ * the currently applied control mechanisms. It does not reflect unsaved
+ * access control policies or unsaved access control entries. Changes to
+ * access control status caused by these mechanisms only take effect on
+ * Session.save() and are only then reflected in the results of
+ * the privilege test methods.
+ *
+ * Since this method allows to view the privileges of principals other
+ * than included in the editing session, this method must throw
+ * AccessDeniedException if the session lacks
+ * READ_ACCESS_CONTROL privilege for the absPath
+ * node.
+ *
+ * Note that this method does not resolve any group membership, as this is
+ * the job of the user manager. nor does it augment the set with the
+ * "everyone" principal.
+ *
+ * @param absPath an absolute path.
+ * @param principals a set of Principals for which is the
+ * privileges are retrieved.
+ * @return an array of Privileges.
+ * @throws PathNotFoundException if no node at absPath exists
+ * or the session does not have sufficient access to retrieve a node at that
+ * location.
+ * @throws AccessDeniedException if the session lacks READ_ACCESS_CONTROL
+ * privilege for the absPath node.
+ * @throws RepositoryException if another error occurs.
+ */
+ public Privilege[] getPrivileges(String absPath, Set principals)
+ throws PathNotFoundException, AccessDeniedException, RepositoryException;
+}
\ No newline at end of file
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/JackrabbitAccessControlPolicy.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/JackrabbitAccessControlPolicy.java
new file mode 100644
index 00000000000..dda3af17634
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/JackrabbitAccessControlPolicy.java
@@ -0,0 +1,34 @@
+/*
+ * 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.jackrabbit.api.security;
+
+import javax.jcr.security.AccessControlPolicy;
+
+/**
+ * JackrabbitAccessControlPolicy is an extension of the
+ * AccessControlPolicy that exposes the path of the Node to
+ * which it can be applied using {@link javax.jcr.security.AccessControlManager#setPolicy(String, javax.jcr.security.AccessControlPolicy)}.
+ */
+public interface JackrabbitAccessControlPolicy extends AccessControlPolicy {
+
+ /**
+ * Returns the path of the node this policy has been created for.
+ *
+ * @return the path of the node this policy has been created for.
+ */
+ String getPath();
+}
\ No newline at end of file
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/authentication/token/TokenCredentials.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/authentication/token/TokenCredentials.java
new file mode 100644
index 00000000000..0c360bd7529
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/authentication/token/TokenCredentials.java
@@ -0,0 +1,117 @@
+/*
+ * 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.jackrabbit.api.security.authentication.token;
+
+import javax.jcr.Credentials;
+import java.util.HashMap;
+
+/**
+ * TokenCredentials implements the Credentials
+ * interface and represents single token credentials. Similar to
+ * {@link javax.jcr.SimpleCredentials} this credentials implementation allows
+ * to set additional attributes.
+ */
+public final class TokenCredentials implements Credentials {
+
+ private final String token;
+ private final HashMap attributes = new HashMap();
+
+ /**
+ * Create a new instance.
+ *
+ * @param token A token string used to create this credentials instance.
+ * @throws IllegalArgumentException If the specified token is null
+ * or empty string.
+ */
+ public TokenCredentials(String token) throws IllegalArgumentException {
+ if (token == null || token.length() == 0) {
+ throw new IllegalArgumentException("Invalid token '" + token + "'");
+ }
+ this.token = token;
+ }
+
+ /**
+ * Returns the token this credentials are built from.
+ *
+ * @return the token.
+ */
+ public String getToken() {
+ return token;
+ }
+
+ /**
+ * Stores an attribute in this credentials instance.
+ *
+ * @param name a String specifying the name of the attribute
+ * @param value the Object to be stored
+ */
+ public void setAttribute(String name, String value) {
+ // name cannot be null
+ if (name == null) {
+ throw new IllegalArgumentException("name cannot be null");
+ }
+
+ // null value is the same as removeAttribute()
+ if (value == null) {
+ removeAttribute(name);
+ return;
+ }
+
+ synchronized (attributes) {
+ attributes.put(name, value);
+ }
+ }
+
+ /**
+ * Returns the value of the named attribute as an Object, or
+ * null if no attribute of the given name exists.
+ *
+ * @param name a String specifying the name of the attribute
+ * @return an Object containing the value of the attribute, or
+ * null if the attribute does not exist
+ */
+ public String getAttribute(String name) {
+ synchronized (attributes) {
+ return (attributes.get(name));
+ }
+ }
+
+ /**
+ * Removes an attribute from this credentials instance.
+ *
+ * @param name a String specifying the name of the attribute to
+ * remove
+ */
+ public void removeAttribute(String name) {
+ synchronized (attributes) {
+ attributes.remove(name);
+ }
+ }
+
+ /**
+ * Returns the names of the attributes available to this credentials
+ * instance. This method returns an empty array if the credentials instance
+ * has no attributes available to it.
+ *
+ * @return a string array containing the names of the stored attributes
+ */
+ public String[] getAttributeNames() {
+ synchronized (attributes) {
+ return attributes.keySet().toArray(new String[attributes.keySet().size()]);
+ }
+ }
+}
\ No newline at end of file
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/authentication/token/package-info.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/authentication/token/package-info.java
new file mode 100644
index 00000000000..df4760dc6e4
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/authentication/token/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/**
+ * Token credentials.
+ */
+@aQute.bnd.annotation.Version("2.3")
+@aQute.bnd.annotation.Export(optional = "provide:=true")
+package org.apache.jackrabbit.api.security.authentication.token;
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/authorization/PrincipalSetPolicy.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/authorization/PrincipalSetPolicy.java
new file mode 100644
index 00000000000..d42b183dc50
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/authorization/PrincipalSetPolicy.java
@@ -0,0 +1,76 @@
+/*
+ * 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.jackrabbit.api.security.authorization;
+
+import java.security.Principal;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import javax.jcr.security.AccessControlException;
+import javax.jcr.security.AccessControlPolicy;
+
+/**
+ * Extension of the JCR {@link javax.jcr.security.AccessControlPolicy AccessControlPolicy}
+ * intended to grant a set of {@code Principal}s the ability to perform certain
+ * actions. The scope of this policy (and thus the affected items) is an
+ * implementation detail; it may e.g. take effect on the tree defined by the
+ * {@link javax.jcr.Node}, where a given {@code PrincipalSetPolicy} is being
+ * applied.
+ *
+ *
The very details on what actions are granted by a given {@code PrincipalSetPolicy}
+ * remains an implementation detail. Similarly a given permission model is
+ * in charge of defining the interactions and effects different
+ * {@link AccessControlPolicy policies} will have if used together in the same
+ * repository.
+ */
+public interface PrincipalSetPolicy extends AccessControlPolicy {
+
+ /**
+ * Returns the set of {@code Principal}s that are allowed to perform
+ * implementation specific actions on the items affected by this policy.
+ *
+ * @return The set of {@code Principal}s that are allowed to perform
+ * implementation specific actions on the those items where this policy
+ * takes effect.
+ */
+ @Nonnull
+ Set getPrincipals();
+
+ /**
+ * Add {@code Principal}s that are allowed to perform some implementation
+ * specific actions on those items where this policy takes effect.
+ *
+ * @param principals The {@code Principal}s that are granted access.
+ * @return {@code true} if this policy was modified; {@code false} otherwise.
+ * @throws javax.jcr.security.AccessControlException If any of the specified
+ * principals is considered invalid or if another access control specific
+ * error occurs.
+ */
+ boolean addPrincipals(@Nonnull Principal... principals) throws AccessControlException;
+
+ /**
+ * Remove the specified {@code Principal}s for the set of allowed principals
+ * thus revoking their ability to perform the implementation specific actions
+ * on items where this policy takes effect.
+ *
+ * @param principals The {@code Principal}s for which access should be revoked.
+ * @return {@code true} if this policy was modified; {@code false} otherwise.
+ * @throws javax.jcr.security.AccessControlException If any of the specified
+ * principals is considered invalid or if another access control specific
+ * error occurs.
+ */
+ boolean removePrincipals(@Nonnull Principal... principals) throws AccessControlException;
+}
\ No newline at end of file
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/authorization/PrivilegeManager.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/authorization/PrivilegeManager.java
new file mode 100644
index 00000000000..e80df049151
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/authorization/PrivilegeManager.java
@@ -0,0 +1,75 @@
+/*
+ * 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.jackrabbit.api.security.authorization;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.NamespaceException;
+import javax.jcr.RepositoryException;
+import javax.jcr.security.AccessControlException;
+import javax.jcr.security.Privilege;
+
+/**
+ * PrivilegeManager is a jackrabbit specific extensions to
+ * JCR access control management that allows to retrieve privileges known
+ * by this JCR implementation and to register new custom privileges according
+ * to implementation specific rules.
+ *
+ * @see javax.jcr.security.AccessControlManager#privilegeFromName(String)
+ */
+public interface PrivilegeManager {
+
+ /**
+ * Returns all registered privileges.
+ *
+ * @return all registered privileges.
+ * @throws RepositoryException If an error occurs.
+ */
+ Privilege[] getRegisteredPrivileges() throws RepositoryException;
+
+ /**
+ * Returns the privilege with the specified privilegeName.
+ *
+ * @param privilegeName Name of the principal.
+ * @return the privilege with the specified privilegeName.
+ * @throws javax.jcr.security.AccessControlException If no privilege with the given name exists.
+ * @throws javax.jcr.RepositoryException If another error occurs.
+ */
+ Privilege getPrivilege(String privilegeName) throws AccessControlException, RepositoryException;
+
+ /**
+ * Creates and registers a new custom privilege with the specified
+ * characteristics and returns the new privilege.
+ * If the registration succeeds, the changes are immediately effective;
+ * there is no need to call save.
+ *
+ * @param privilegeName The name of the new custom privilege.
+ * @param isAbstract Boolean flag indicating if the privilege is abstract.
+ * @param declaredAggregateNames An array of privilege names referring to
+ * registered privileges being aggregated by this new custom privilege.
+ * In case of a non aggregate privilege an empty array should be passed.
+ * @return the new privilege.
+ * @throws AccessDeniedException If the session this manager has been created
+ * for is not allowed to register new privileges.
+ * @throws NamespaceException If any of the specified JCR names is illegal.
+ * @throws RepositoryException If the privilege could not be registered due
+ * to any implementation specific constraint violations or if persisting the
+ * custom privilege fails.
+ */
+ Privilege registerPrivilege(String privilegeName, boolean isAbstract,
+ String[] declaredAggregateNames)
+ throws AccessDeniedException, NamespaceException, RepositoryException;
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/authorization/package-info.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/authorization/package-info.java
new file mode 100644
index 00000000000..7bf2cf3460e
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/authorization/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/**
+ * Jackrabbit extensions for authorization.
+ */
+@aQute.bnd.annotation.Version("2.3")
+package org.apache.jackrabbit.api.security.authorization;
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/package-info.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/package-info.java
new file mode 100644
index 00000000000..b44ae45c1b7
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/**
+ * Jackrabbit extensions for access control.
+ */
+@aQute.bnd.annotation.Version("2.3")
+package org.apache.jackrabbit.api.security;
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/principal/ItemBasedPrincipal.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/principal/ItemBasedPrincipal.java
new file mode 100644
index 00000000000..c7b57fc2617
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/principal/ItemBasedPrincipal.java
@@ -0,0 +1,39 @@
+/*
+ * 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.jackrabbit.api.security.principal;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * ItemBasedPrincipal is a Principal having a
+ * corresponding item within the JCR repository. In addition to the methods
+ * inherited from the {@link java.security.Principal} interface it therefore
+ * provides a {@link #getPath()} method.
+ */
+public interface ItemBasedPrincipal extends JackrabbitPrincipal {
+
+ /**
+ * Returns the JCR path of the item that corresponds to this
+ * Principal.
+ *
+ * @return the path of the {@link javax.jcr.Item} that corresponds to this
+ * Principal.
+ * @throws RepositoryException If an error occurs while retrieving the
+ * Item path.
+ */
+ String getPath() throws RepositoryException;
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/principal/JackrabbitPrincipal.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/principal/JackrabbitPrincipal.java
new file mode 100644
index 00000000000..77ae1302cdf
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/principal/JackrabbitPrincipal.java
@@ -0,0 +1,27 @@
+/*
+ * 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.jackrabbit.api.security.principal;
+
+import java.security.Principal;
+
+/**
+ * JackrabbitPrincipal marks the principal to be the result of
+ * authentication against the repository.
+ */
+public interface JackrabbitPrincipal extends Principal {
+
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/principal/PrincipalIterator.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/principal/PrincipalIterator.java
new file mode 100644
index 00000000000..5a843177f72
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/principal/PrincipalIterator.java
@@ -0,0 +1,34 @@
+/*
+ * 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.jackrabbit.api.security.principal;
+
+import javax.jcr.RangeIterator;
+import java.security.Principal;
+
+/**
+ * A {@link RangeIterator} iterating over Principals.
+ */
+public interface PrincipalIterator extends RangeIterator {
+
+ /**
+ * Returns the next principal.
+ *
+ * @return the next principal
+ */
+ Principal nextPrincipal();
+
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/principal/PrincipalManager.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/principal/PrincipalManager.java
new file mode 100644
index 00000000000..cfad491cb0a
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/principal/PrincipalManager.java
@@ -0,0 +1,156 @@
+/*
+ * 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.jackrabbit.api.security.principal;
+
+import java.security.Principal;
+import java.security.acl.Group;
+
+/**
+ * This interface defines the principal manager which is the clients view on
+ * all principals known to the repository. Each principal manager is bound to
+ * a session and is restricted by the respective access control. The principal
+ * manager in addition provides basic search facilities.
+ *
+ * A {@link Principal} is an object used to connect
+ * to any kind of security mechanism. Example for this are the
+ * {@link javax.security.auth.spi.LoginModule login modules} that use principals
+ * to process the login procedure.
+ * A principal can be a member of a {@link Group}. A
+ * group is a principal itself and can therefore be a member of a group again.
+ *
+ * Please note the following security considerations that need to be respected
+ * when implementing the PrincipalManager: All principals returned by this
+ * manager as well as {@link Group#members()} must respect access restrictions
+ * that may be present for the Session this manager has been built
+ * for. The same applies for {@link #getGroupMembership(Principal)}.
+ */
+public interface PrincipalManager {
+
+ /**
+ * Filter flag indicating that only Principals that do NOT
+ * represent a {@link java.security.acl.Group group} should be searched
+ * and returned.
+ */
+ int SEARCH_TYPE_NOT_GROUP = 1;
+
+ /**
+ * Filter flag indicating that only Principals that represent
+ * a {@link java.security.acl.Group group} of Principals should be searched
+ * and returned.
+ */
+ int SEARCH_TYPE_GROUP = 2;
+
+ /**
+ * Filter flag indicating that all Principals should be search
+ * irrespective whether they represent a group of Principals or not.
+ */
+ int SEARCH_TYPE_ALL = 3;
+
+ /**
+ * Checks if the principal with the given name is known to this manager
+ * (in respect to the sessions access rights). If this method returns
+ * true then the following expression evaluates to true
+ * as well: PrincipalManager.getPrincipal(name).getName().equals(name)
+ *
+ * @param principalName the name of the principal to check
+ * @return return true if the principal with this name is known
+ * to this manager; false otherwise.
+ */
+ boolean hasPrincipal(String principalName);
+
+ /**
+ * Returns the principal with the given name if is known to this manager
+ * (with respect to the sessions access rights).
+ * Please note that due to security reasons Group principals will only
+ * reveal those members that are visible to the Session this
+ * PrincipalManager has been built for.
+ *
+ * @param principalName the name of the principal to retrieve
+ * @return return the requested principal or null if a
+ * principal with the given name does not exist or is not accessible
+ * for the editing session.
+ */
+ Principal getPrincipal(String principalName);
+
+ /**
+ * Gets the principals matching a simple filter expression applied against
+ * the {@link Principal#getName() principal name}.
+ * TODO: define the filter expression.
+ * An implementation may limit the number of principals returned.
+ * If there are no matching principals, an empty iterator is returned.
+ *
+ * @param simpleFilter
+ * @return a PrincipalIterator over the Principals
+ * matching the given filter.
+ */
+ PrincipalIterator findPrincipals(String simpleFilter);
+
+ /**
+ * Gets the principals matching a simple filter expression applied against
+ * the {@link Principal#getName() principal name} AND the specified search
+ * type.
+ * TODO: define the filter expression.
+ * An implementation may limit the number of principals returned.
+ * If there are no matching principals, an empty iterator is returned.
+ *
+ * @param simpleFilter
+ * @param searchType Any of the following constants:
+ *
+ *
{@link PrincipalManager#SEARCH_TYPE_ALL}
+ *
{@link PrincipalManager#SEARCH_TYPE_GROUP}
+ *
{@link PrincipalManager#SEARCH_TYPE_NOT_GROUP}
+ *
+ * @return a PrincipalIterator over the Principals
+ * matching the given filter and search type.
+ */
+ PrincipalIterator findPrincipals(String simpleFilter, int searchType);
+
+ /**
+ * Returns all Principals matching the specified search type.
+ *
+ * @param searchType Any of the following constants:
+ *
+ *
{@link PrincipalManager#SEARCH_TYPE_ALL}
+ *
{@link PrincipalManager#SEARCH_TYPE_GROUP}
+ *
{@link PrincipalManager#SEARCH_TYPE_NOT_GROUP}
+ *
+ * @return a PrincipalIterator over all the Principals
+ * matching the given search type.
+ */
+ PrincipalIterator getPrincipals(int searchType);
+
+ /**
+ * Returns an iterator over all group principals for which the given
+ * principal is either direct or indirect member of.
+ *
+ * Example:
+ * If Principal P is member of Group A, and Group A is member of
+ * Group B, this method will return Principal A and Principal B.
+ *
+ * @param principal the principal to return it's membership from.
+ * @return an iterator returning all groups the given principal is member of.
+ */
+ PrincipalIterator getGroupMembership(Principal principal);
+
+ /**
+ * Returns the Principal which is implicitly applied to
+ * every subject.
+ *
+ * @return the 'everyone' principal
+ */
+ Principal getEveryone();
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/principal/package-info.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/principal/package-info.java
new file mode 100644
index 00000000000..ad20430e303
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/principal/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/**
+ * Jackrabbit extensions for JAAS principals.
+ */
+@aQute.bnd.annotation.Version("2.3")
+package org.apache.jackrabbit.api.security.principal;
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Authorizable.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Authorizable.java
new file mode 100644
index 00000000000..6502ccf09ab
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Authorizable.java
@@ -0,0 +1,200 @@
+/*
+ * 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.jackrabbit.api.security.user;
+
+import java.security.Principal;
+import java.util.Iterator;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.Value;
+
+/**
+ * The Authorizable is the common base interface for {@link User} and
+ * {@link Group}. It provides access to the Principals associated
+ * with an Authorizable (see below) and allow to access and
+ * modify additional properties such as e.g. full name, e-mail or address.
+ *
+ *
+ * Please note the difference between Authorizable and
+ * {@link java.security.Principal Principal}:
+ * An Authorizable is repository object that is neither associated
+ * with nor depending from a particular Session and thus independent
+ * of the login mechanisms creating Sessions.
+ *
+ * On the other hand Principals are representations of user
+ * identities. In other words: each Principal within the set
+ * associated with the Session's Subject upon login represents an identity for
+ * that user. An the set of Principals may differ between different
+ * login mechanisms.
+ *
+ * Consequently an one-to-many relationship exists between Authorizable
+ * and Principal (see also {@link #getPrincipal()}.
+ *
+ *
+ * The interfaces derived from Authorizable are defined as follows:
+ *
+ *
{@link User}: defined to be an Authorizable that can be authenticated
+ * (by using Credentials) and impersonated.
+ *
{@link Group}: defined to be a collection of other
+ * Authorizables.
+ *
+ *
+ * @see User
+ * @see Group
+ */
+public interface Authorizable {
+
+ /**
+ * Return the implementation specific identifier for this
+ * Authorizable. It could e.g. be a UserID or simply the
+ * principal name.
+ *
+ * @return Name of this Authorizable.
+ * @throws RepositoryException if an error occurs.
+ */
+ String getID() throws RepositoryException;
+
+ /**
+ * @return if the current Authorizable is a {@link Group}
+ */
+ boolean isGroup();
+
+ /**
+ * @return a representation as Principal.
+ * @throws RepositoryException If an error occurs.
+ */
+ Principal getPrincipal() throws RepositoryException;
+
+ /**
+ * @return all {@link Group}s, this Authorizable is declared member of.
+ * @throws RepositoryException If an error occurs.
+ */
+ Iterator declaredMemberOf() throws RepositoryException;
+
+ /**
+ * @return all {@link Group}s, this Authorizable is member of included
+ * indirect group membership.
+ * @throws RepositoryException If an error occurs.
+ */
+ Iterator memberOf() throws RepositoryException;
+
+ /**
+ * Removes this Authorizable, if the session has sufficient
+ * permissions. Note, that removing an Authorizable even
+ * if it listed as member of a Group or if still has members (this is
+ * a Group itself).
+ *
+ * @throws RepositoryException If an error occurred and the
+ * Authorizable could not be removed.
+ */
+ void remove() throws RepositoryException;
+
+ /**
+ * Returns the names of properties present with this
+ * Authorizable not taking possible relative paths into consideration.
+ * Same as {@link #getPropertyNames(String)} where the specified string
+ * is ".".
+ *
+ * @return names of properties.
+ * @throws RepositoryException If an error occurs.
+ * @see #getProperty(String) where the specified relative path is simply an
+ * name.
+ * @see #hasProperty(String)
+ */
+ Iterator getPropertyNames() throws RepositoryException;
+
+ /**
+ * Returns the names of properties present with this
+ * Authorizable at the specified relative path.
+ *
+ * @param relPath A relative path.
+ * @return names of properties.
+ * @throws RepositoryException If an error occurs.
+ * @see #getProperty(String)
+ * @see #hasProperty(String)
+ */
+ Iterator getPropertyNames(String relPath) throws RepositoryException;
+
+ /**
+ * Tests if a the property with specified name exists.
+ *
+ * @param relPath The relative path to the property to be tested.
+ * @return true if a property with the given name exists.
+ * @throws RepositoryException If an error occurs.
+ * @see #getProperty(String)
+ */
+ boolean hasProperty(String relPath) throws RepositoryException;
+
+ /**
+ * Set an arbitrary property to this Authorizable.
+ *
+ * @param relPath The relative path of the property to be added or modified.
+ * @param value The desired value.
+ * @throws RepositoryException If the specified property could not be set.
+ */
+ void setProperty(String relPath, Value value) throws RepositoryException;
+
+ /**
+ * Set an arbitrary property to this Authorizable.
+ *
+ * @param relPath The relative path of the property to be added or modified.
+ * @param value The desired property values.
+ * @throws RepositoryException If the specified property could not be set.
+ */
+ void setProperty(String relPath, Value[] value) throws RepositoryException;
+
+ /**
+ * Returns the values for the properties with the specified name or
+ * null.
+ *
+ * @param relPath Relative path of the property to be retrieved.
+ * @return value of the property with the given name or null
+ * if no such property exists.
+ * @throws RepositoryException If an error occurs.
+ */
+ Value[] getProperty(String relPath) throws RepositoryException;
+
+ /**
+ * Removes the property with the given name.
+ *
+ * @param relPath Relative path (or name) of the property to be removed.
+ * @return true If the property at the specified relPath was successfully
+ * removed; false if no such property was present.
+ * @throws RepositoryException If an error occurs.
+ */
+ boolean removeProperty(String relPath) throws RepositoryException;
+
+ /**
+ * Returns a JCR path if this authorizable instance is associated with an
+ * item that can be accessed by the editing Session.
+ * Throws UnsupportedRepositoryOperationException if this
+ * method is not supported or if there is no item associated with this
+ * authorizable that is accessible by the editing Session.
+ * Throws RepositoryException if another error occurs while
+ * retrieving the path.
+ *
+ * @return the path of the {@link javax.jcr.Item} that corresponds to this
+ * Authorizable.
+ * @throws UnsupportedRepositoryOperationException If this method is not
+ * supported or if there exists no accessible item associated with this
+ * Authorizable instance.
+ * @throws RepositoryException If an error occurs while retrieving the
+ * Item path.
+ */
+ String getPath() throws UnsupportedRepositoryOperationException, RepositoryException;
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/AuthorizableExistsException.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/AuthorizableExistsException.java
new file mode 100644
index 00000000000..0832fccfd10
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/AuthorizableExistsException.java
@@ -0,0 +1,35 @@
+/*
+ * 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.jackrabbit.api.security.user;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * AuthorizableExistsException
+ */
+public class AuthorizableExistsException extends RepositoryException {
+
+ /**
+ * Serial version UID.
+ */
+ private static final long serialVersionUID = 7875416346848889564L;
+
+ public AuthorizableExistsException(String msg) {
+ super(msg);
+ }
+
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/AuthorizableTypeException.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/AuthorizableTypeException.java
new file mode 100644
index 00000000000..a70c707aa6f
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/AuthorizableTypeException.java
@@ -0,0 +1,29 @@
+/*
+ * 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.jackrabbit.api.security.user;
+
+import javax.jcr.RepositoryException;
+
+/**
+ * The {@code AuthorizableTypeException} signals an {@link Authorizable} type mismatch.
+ */
+public class AuthorizableTypeException extends RepositoryException {
+
+ public AuthorizableTypeException(String msg) {
+ super(msg);
+ }
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Group.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Group.java
new file mode 100644
index 00000000000..03c7b326cb5
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Group.java
@@ -0,0 +1,116 @@
+/*
+ * 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.jackrabbit.api.security.user;
+
+import javax.annotation.Nonnull;
+import javax.jcr.RepositoryException;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * A Group is a collection of {@link #getMembers() Authorizable}s.
+ */
+public interface Group extends Authorizable {
+
+ /**
+ * @return Iterator of Authorizables which are declared
+ * members of this Group.
+ * @throws RepositoryException If an error occurs.
+ */
+ Iterator getDeclaredMembers() throws RepositoryException;
+
+ /**
+ * @return Iterator of Authorizables which are members of
+ * this Group. This includes both declared members and all authorizables
+ * that are indirect group members.
+ * @throws RepositoryException If an error occurs.
+ */
+ Iterator getMembers() throws RepositoryException;
+
+ /**
+ * Test whether an {@link Authorizable} is a declared member of this group.
+ * @param authorizable The Authorizable to test.
+ * @return true if the Authorizable to test is a direct member
+ * @throws RepositoryException If an error occurs.
+ */
+ boolean isDeclaredMember(Authorizable authorizable) throws RepositoryException;
+
+ /**
+ * @param authorizable The Authorizable to test.
+ * @return true if the Authorizable to test is a direct or indirect member
+ * of this Group.
+ * @throws RepositoryException If an error occurs.
+ */
+ boolean isMember(Authorizable authorizable) throws RepositoryException;
+
+ /**
+ * Add a member to this Group.
+ *
+ * @param authorizable The Authorizable to be added as
+ * member to this group.
+ * @return true if the Authorizable has successfully been added
+ * to this Group, false otherwise (e.g. unknown implementation
+ * or if it already is a member or if the passed authorizable is this
+ * group itself or for some implementation specific constraint).
+ * @throws RepositoryException If an error occurs.
+ */
+ boolean addMember(Authorizable authorizable) throws RepositoryException;
+
+ /**
+ * Add one or more member(s) to this Group. Note, that an implementation may
+ * define circumstances under which this method allows to add non-existing
+ * {@code Authorizable}s as new members. Also an implementation may choose to
+ * (partially) postpone validation/verification util {@link Session#save()}.
+ *
+ * @param memberIds The {@code Id}s of the authorizables to be added as
+ * members to this group.
+ * @return a set of those {@code memberIds} that could not be added or an
+ * empty set of all ids have been successfully processed. The former may include
+ * those cases where a given id cannot be resolved to an existing authorizable,
+ * one that is already member or if adding the member would create a
+ * cyclic group membership.
+ * @throws RepositoryException If one of the specified memberIds is invalid or
+ * if some other error occurs.
+ */
+ Set addMembers(@Nonnull String... memberIds) throws RepositoryException;
+
+ /**
+ * Remove a member from this Group.
+ *
+ * @param authorizable The Authorizable to be removed from
+ * the list of group members.
+ * @return true if the Authorizable was successfully removed. False otherwise.
+ * @throws RepositoryException If an error occurs.
+ */
+ boolean removeMember(Authorizable authorizable) throws RepositoryException;
+
+ /**
+ * Remove one or several members from this Group. Note, that an implementation
+ * may define circumstances under which this method allows to remove members
+ * that (no longer) exist. An implementation may choose to (partially)
+ * postpone validation/verification util {@link Session#save()}.
+ *
+ * @param memberIds The {@code Id}s of the authorizables to be removed
+ * from the members of this group.
+ * @return a set of those {@code memberIds} that could not be removed or an
+ * empty set if all ids have been successfully processed. The former may include
+ * those cases where a given id cannot be resolved to an existing authorizable.
+ * @throws RepositoryException If one of the specified memberIds is invalid
+ * or if some other error occurs.
+ */
+ Set removeMembers(@Nonnull String... memberIds) throws RepositoryException;
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Impersonation.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Impersonation.java
new file mode 100644
index 00000000000..e03a223ce4f
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Impersonation.java
@@ -0,0 +1,72 @@
+/*
+ * 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.jackrabbit.api.security.user;
+
+import org.apache.jackrabbit.api.security.principal.PrincipalIterator;
+
+import javax.jcr.RepositoryException;
+import javax.security.auth.Subject;
+import java.security.Principal;
+
+/**
+ * The Impersonation maintains Principals that are allowed to
+ * impersonate. Principals can be added or removed using
+ * {@link #grantImpersonation(Principal)} and
+ * {@link #revokeImpersonation(Principal)}, respectively.
+ *
+ * @see User#getImpersonation()
+ */
+public interface Impersonation {
+
+ /**
+ * @return An iterator over the Principals that are allowed
+ * to impersonate the User this Impersonation
+ * object has been created for.
+ * @throws RepositoryException If an error occurs.
+ */
+ PrincipalIterator getImpersonators() throws RepositoryException;
+
+ /**
+ * @param principal The principal that should be allowed to impersonate
+ * the User this Impersonation has been built for.
+ * @return true if the specified Principal has not been allowed
+ * to impersonate before and if impersonation has been successfully
+ * granted to it, false otherwise.
+ * @throws RepositoryException If an error occurs.
+ */
+ boolean grantImpersonation(Principal principal) throws RepositoryException;
+
+ /**
+ * @param principal The principal that should no longer be allowed to
+ * impersonate.
+ * @return If the granted impersonation has been successfully revoked for
+ * the given principal; false otherwise.
+ * @throws RepositoryException If an error occurs.
+ */
+ boolean revokeImpersonation(Principal principal) throws RepositoryException;
+
+ /**
+ * Test if the given subject (i.e. any of the principals it contains) is
+ * allowed to impersonate.
+ *
+ * @param subject to impersonate.
+ * @return true if this Impersonation allows the specified
+ * Subject to impersonate.
+ * @throws RepositoryException If an error occurs.
+ */
+ boolean allows(Subject subject) throws RepositoryException;
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Query.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Query.java
new file mode 100644
index 00000000000..41732a9a30e
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Query.java
@@ -0,0 +1,50 @@
+/*
+ * 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.jackrabbit.api.security.user;
+
+/**
+ * A query to match {@link Authorizable}s. Pass an instance of this interface to
+ * {@link UserManager#findAuthorizables(Query)}.
+ *
+ * The following query finds all users named 'Bob' which have the word
+ * 'engineer' in its description and returns them in ascending order wrt. to
+ * the name.
+ *
+ *
+ */
+public interface Query {
+
+ /**
+ * Build the query using a {@link QueryBuilder}.
+ * @param builder A query builder for building the query.
+ * @param Opaque type of the query builder.
+ */
+ void build(QueryBuilder builder);
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/QueryBuilder.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/QueryBuilder.java
new file mode 100644
index 00000000000..6a49b882aa5
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/QueryBuilder.java
@@ -0,0 +1,292 @@
+/*
+ * 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.jackrabbit.api.security.user;
+
+import javax.jcr.Value;
+
+public interface QueryBuilder {
+
+ /**
+ * The sort order of the result set of a query.
+ */
+ enum Direction {
+ ASCENDING("ascending"),
+ DESCENDING("descending");
+
+ private final String direction;
+
+ Direction(String direction) {
+ this.direction = direction;
+ }
+
+ public String getDirection() {
+ return direction;
+ }
+ }
+
+ /**
+ * Set the selector for the query. The selector determines whether the query
+ * returns all {@link Authorizable}s or just {@link User}s respectively {@link Group}s.
+ *
+ * @param selector The selector for the query
+ */
+ void setSelector(Class extends Authorizable> selector);
+
+ /**
+ * Set the scope for the query. If set, the query will only return members of a specific group.
+ *
+ * @param groupName Name of the group to restrict the query to.
+ * @param declaredOnly If true only declared members of the groups are returned.
+ * Otherwise indirect memberships are also considered.
+ */
+ void setScope(String groupName, boolean declaredOnly);
+
+ /**
+ * Set the condition for the query. The query only includes {@link Authorizable}s
+ * for which this condition holds.
+ *
+ * @param condition Condition upon which Authorizables are included in the query result
+ */
+ void setCondition(T condition);
+
+ /**
+ * Set the sort order of the {@link Authorizable}s returned by the query.
+ * The format of the propertyName is the same as in XPath:
+ * @propertyName sorts on a property of the current node.
+ * relative/path/@propertyName sorts on a property of a
+ * descendant node.
+ *
+ * @param propertyName The name of the property to sort on
+ * @param direction Direction to sort. Either {@link Direction#ASCENDING} or {@link Direction#DESCENDING}
+ * @param ignoreCase Ignore character case in sort if true. Note: For false
+ * sorting is done lexicographically even for non string properties.
+ */
+ void setSortOrder(String propertyName, Direction direction, boolean ignoreCase);
+
+ /**
+ * Set the sort order of the {@link Authorizable}s returned by the query.
+ * The format of the propertyName is the same as in XPath:
+ * @propertyName sorts on a property of the current node.
+ * relative/path/@propertyName sorts on a property of a
+ * descendant node. Character case is taken into account for the sort order.
+ *
+ * @param propertyName The name of the property to sort on
+ * @param direction Direction to sort. Either {@link Direction#ASCENDING} or {@link Direction#DESCENDING}
+ */
+ void setSortOrder(String propertyName, Direction direction);
+
+ /**
+ * Set limits for the query. The limits consists of a bound and a maximal
+ * number of results. The bound refers to the value of the
+ * {@link #setSortOrder(String, Direction) sort order} property. The
+ * query returns at most maxCount {@link Authorizable}s whose
+ * values of the sort order property follow bound in the sort
+ * direction. This method has no effect if the sort order is not specified.
+ *
+ * @param bound Bound from where to start returning results. null
+ * for no bound
+ * @param maxCount Maximal number of results to return. -1 for no limit.
+ */
+ void setLimit(Value bound, long maxCount);
+
+ /**
+ * Set limits for the query. The limits consists of an offset and a maximal
+ * number of results. offset refers to the offset within the full
+ * result set at which the returned result set should start expressed in terms
+ * of the number of {@link Authorizable}s to skip. maxCount sets the
+ * maximum size of the result set expressed in terms of the number of authorizables
+ * to return.
+ *
+ * @param offset Offset from where to start returning results. 0 for no offset.
+ * @param maxCount Maximal number of results to return. -1 for no limit.
+ */
+ void setLimit(long offset, long maxCount);
+
+ /**
+ * Create a condition which holds if the name of the {@link Authorizable}
+ * matches a pattern.
+ * The percent character "%" represents any string of zero or more characters and the
+ * underscore character "_" represents any single character. Any literal use of these characters
+ * and the backslash character "\" must be escaped with a backslash character.
+ * The pattern is matched against the {@link Authorizable#getID() id} and the
+ * {@link Authorizable#getPrincipal() principal}.
+ *
+ * @param pattern Pattern to match the name of an authorizable.
+ * @return A condition
+ */
+ T nameMatches(String pattern);
+
+ /**
+ * Create a condition which holds if the node of an {@link Authorizable} has a
+ * property at relPath which is not equal to value.
+ * The format of the relPath argument is the same as in XPath:
+ * @attributeName for an attribute on this node and
+ * relative/path/@attributeName for an attribute of a descendant node.
+ *
+ * @param relPath Relative path from the authorizable's node to the property
+ * @param value Value to compare the property at relPath to
+ * @return A condition
+ */
+ T neq(String relPath, Value value);
+
+ /**
+ * Create a condition which holds if the node of an {@link Authorizable} has a
+ * property at relPath which is equal to value.
+ * The format of the relPath argument is the same as in XPath:
+ * @attributeName for an attribute on this node and
+ * relative/path/@attributeName for an attribute of a descendant node.
+ *
+ * @param relPath Relative path from the authorizable's node to the property
+ * @param value Value to compare the property at relPath to
+ * @return A condition
+ */
+ T eq(String relPath, Value value);
+
+ /**
+ * Create a condition which holds if the node of an {@link Authorizable} has a
+ * property at relPath which is smaller than value.
+ * The format of the relPath argument is the same as in XPath:
+ * @attributeName for an attribute on this node and
+ * relative/path/@attributeName for an attribute of a descendant node.
+ *
+ * @param relPath Relative path from the authorizable's node to the property
+ * @param value Value to compare the property at relPath to
+ * @return A condition
+ */
+ T lt(String relPath, Value value);
+
+ /**
+ * Create a condition which holds if the node of an {@link Authorizable} has a
+ * property at relPath which is smaller than or equal to value.
+ * The format of the relPath argument is the same as in XPath:
+ * @attributeName for an attribute on this node and
+ * relative/path/@attributeName for an attribute of a descendant node.
+ *
+ * @param relPath Relative path from the authorizable's node to the property
+ * @param value Value to compare the property at relPath to
+ * @return A condition
+ */
+ T le(String relPath, Value value);
+
+ /**
+ * Create a condition which holds if the node of an {@link Authorizable} has a
+ * property at relPath which is greater than value.
+ * The format of the relPath argument is the same as in XPath:
+ * @attributeName for an attribute on this node and
+ * relative/path/@attributeName for an attribute of a descendant node.
+ *
+ * @param relPath Relative path from the authorizable's node to the property
+ * @param value Value to compare the property at relPath to
+ * @return A condition
+ */
+ T gt(String relPath, Value value);
+
+ /**
+ * Create a condition which holds if the node of an {@link Authorizable} has a
+ * property at relPath which is greater than or equal to value.
+ * The format of the relPath argument is the same as in XPath:
+ * @attributeName for an attribute on this node and
+ * relative/path/@attributeName for an attribute of a descendant node.
+ *
+ * @param relPath Relative path from the authorizable's node to the property
+ * @param value Value to compare the property at relPath to
+ * @return A condition
+ */
+ T ge(String relPath, Value value);
+
+ /**
+ * Create a condition which holds if the node of an {@link Authorizable} has a
+ * property at relPath.
+ * The format of the relPath argument is the same as in XPath:
+ * @attributeName for an attribute on this node and
+ * relative/path/@attributeName for an attribute of a descendant node.
+ *
+ * @param relPath Relative path from the authorizable's node to the property
+ * @return A condition
+ */
+ T exists(String relPath);
+
+ /**
+ * Create a condition which holds if the node of an {@link Authorizable} has a
+ * property at relPath which matches the pattern in pattern.
+ * The percent character "%" represents any string of zero or more characters and the
+ * underscore character "_" represents any single character. Any literal use of these characters
+ * and the backslash character "\" must be escaped with a backslash character.
+ * The format of the relPath argument is the same as in XPath:
+ * @attributeName for an attribute on this node and
+ * relative/path/@attributeName for an attribute of a descendant node.
+ *
+ * @param relPath Relative path from the authorizable's node to the property
+ * @param pattern Pattern to match the property at relPath against
+ * @return A condition
+ */
+ T like(String relPath, String pattern);
+
+ /**
+ * Create a full text search condition. The condition holds if the node of an
+ * {@link Authorizable} has a property at relPath for which
+ * searchExpr yields results.
+ * The format of the relPath argument is the same as in XPath:
+ * . searches all properties of the current node, @attributeName
+ * searches the attributeName property of the current node, relative/path/.
+ * searches all properties of the descendant node at relative/path and
+ * relative/path/@attributeName searches the attributeName property
+ * of the descendant node at relative/path.
+ * The syntax of searchExpr is
[-]value { [OR] [-]value }
.
+ *
+ * @param relPath Relative path from the authorizable's node to the property
+ * @param searchExpr A full text search expression
+ * @return A condition
+ */
+ T contains(String relPath, String searchExpr);
+
+ /**
+ * Create a condition which holds for {@link Authorizable}s which can impersonate as
+ * name.
+ *
+ * @param name Name of an authorizable
+ * @return A condition
+ */
+ T impersonates(String name);
+
+ /**
+ * Return a condition which holds if condition does not hold.
+ *
+ * @param condition Condition to negate
+ * @return A condition
+ */
+ T not(T condition);
+
+ /**
+ * Return a condition which holds if both sub conditions hold.
+ *
+ * @param condition1 first sub condition
+ * @param condition2 second sub condition
+ * @return A condition
+ */
+ T and(T condition1, T condition2);
+
+ /**
+ * Return a condition which holds if any of the two sub conditions hold.
+ *
+ * @param condition1 first sub condition
+ * @param condition2 second sub condition
+ * @return A condition
+ */
+ T or(T condition1, T condition2);
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/User.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/User.java
new file mode 100644
index 00000000000..e02e3db9a4a
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/User.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.jackrabbit.api.security.user;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Credentials;
+
+/**
+ * User is a special {@link Authorizable} that can be authenticated and
+ * impersonated.
+ *
+ * @see #getCredentials()
+ * @see #getImpersonation()
+ */
+public interface User extends Authorizable {
+
+ /**
+ * @return true if the current user represents the administrator.
+ */
+ boolean isAdmin();
+
+ /**
+ * @return true if the current user represents a system user.
+ */
+ boolean isSystemUser();
+
+ /**
+ * Returns the internal Credentials representation for this
+ * user. This method is expected to be used for validation during the
+ * login process. However, the return value should neither be usable nor
+ * used for {@link javax.jcr.Repository#login}.
+ *
+ * @return Credentials for this user.
+ * @throws javax.jcr.RepositoryException If an error occurs.
+ */
+ Credentials getCredentials() throws RepositoryException;
+
+ /**
+ * @return Impersonation for this User.
+ * @throws javax.jcr.RepositoryException If an error occurs.
+ */
+ Impersonation getImpersonation() throws RepositoryException;
+
+ /**
+ * Change the password of this user.
+ *
+ * @param password The new password.
+ * @throws RepositoryException If an error occurs.
+ */
+ void changePassword(String password) throws RepositoryException;
+
+ /**
+ * Change the password of this user.
+ *
+ * @param password The new password.
+ * @param oldPassword The old password.
+ * @throws RepositoryException If the old password doesn't match or if
+ * an error occurs.
+ */
+ void changePassword(String password, String oldPassword) throws RepositoryException;
+
+ /**
+ * Disable this user thus preventing future login if the reason
+ * is a non-null String.
+ * Note however, that this user will still be accessible by
+ * {@link UserManager#getAuthorizable}.
+ *
+ * @param reason String describing the reason for disable this user or
+ * null if the user account should be enabled again.
+ * @throws RepositoryException If an error occurs.
+ */
+ void disable(String reason) throws RepositoryException;
+
+ /**
+ * Returns true if this user is disabled, false
+ * otherwise.
+ *
+ * @return true if this user is disabled, false
+ * otherwise.
+ * @throws RepositoryException If an error occurs.
+ */
+ boolean isDisabled() throws RepositoryException;
+
+ /**
+ * Returns the String specified upon disabling this user or null
+ * if {@link #isDisabled()} returns false.
+ *
+ * @return The reason specified upon disabling this user or null
+ * if this user is not disabled.
+ * @throws RepositoryException If an error occurs.
+ */
+ String getDisabledReason() throws RepositoryException;
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/UserManager.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/UserManager.java
new file mode 100644
index 00000000000..cac890907ab
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/UserManager.java
@@ -0,0 +1,357 @@
+/*
+ * 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.jackrabbit.api.security.user;
+
+import java.security.Principal;
+import java.util.Iterator;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
+
+import aQute.bnd.annotation.ProviderType;
+
+/**
+ * The UserManager provides access to and means to maintain
+ * {@link Authorizable authorizable objects} i.e. {@link User users} and
+ * {@link Group groups}. The UserManager is bound to a particular
+ * Session.
+ *
+ * Note that all create calls will modify the session associated
+ * with the {@linkplain UserManager} (whether this is the current session or not
+ * depends on the repository configuration). If the user manager is not
+ * in "autosave" mode (see {@link UserManager#isAutoSave()}), problems like
+ * overlapping creation of intermediate nodes may only surface upon a subsequent
+ * {@link Session#save()} operation; callers should be prepared to repeat them
+ * in case this happens.
+ */
+@ProviderType
+public interface UserManager {
+
+ /**
+ * Filter flag indicating that only Users should be searched
+ * and returned.
+ */
+ int SEARCH_TYPE_USER = 1;
+
+ /**
+ * Filter flag indicating that only Groups should be searched
+ * and returned.
+ */
+ int SEARCH_TYPE_GROUP = 2;
+
+ /**
+ * Filter flag indicating that all Authorizables should be
+ * searched.
+ */
+ int SEARCH_TYPE_AUTHORIZABLE = 3;
+
+ /**
+ * Get the Authorizable by its id.
+ *
+ * @param id The user or group id.
+ * @return Authorizable or null, if not present.
+ * @throws RepositoryException If an error occurs.
+ * @see Authorizable#getID()
+ */
+ Authorizable getAuthorizable(String id) throws RepositoryException;
+
+ /**
+ * Get the Authorizable of a specific type by its id.
+ *
+ * @param id the user or group id.
+ * @param authorizableClass the class of the type of Authorizable required; must not be null.
+ * @param the required Authorizable type.
+ * @return Authorizable or null, if not present.
+ * @throws AuthorizableTypeException If an authorizable exists but is not of the requested type.
+ * @throws RepositoryException If an error occurs
+ */
+ T getAuthorizable(String id, Class authorizableClass) throws AuthorizableTypeException, RepositoryException;
+
+ /**
+ * Get the Authorizable by its Principal.
+ *
+ * @param principal The principal of the authorizable to retrieve.
+ * @return Authorizable or null, if not present.
+ * @throws RepositoryException If an error occurs.
+ */
+ Authorizable getAuthorizable(Principal principal) throws RepositoryException;
+
+ /**
+ * In accordance to {@link org.apache.jackrabbit.api.security.user.Authorizable#getPath()}
+ * this method allows to retrieve an given authorizable by it's path.
+ *
+ * @param path The path to an authorizable.
+ * @return Authorizable or null, if not present.
+ * @throws UnsupportedRepositoryOperationException If this implementation does
+ * support to retrieve authorizables by path.
+ * @throws RepositoryException If another error occurs.
+ * @see org.apache.jackrabbit.api.security.user.Authorizable#getPath()
+ */
+ Authorizable getAuthorizableByPath(String path) throws UnsupportedRepositoryOperationException, RepositoryException;
+
+ /**
+ * Returns all Authorizables that have a
+ * {@link Authorizable#getProperty(String) property} with the given relative
+ * path (or name) that matches the specified value.
+ *
+ * If a relative path with more than one segment is specified only properties
+ * exactly matching that patch will be returned. If, however, a name is
+ * specified all properties that may be retrieved using
+ * {@link Authorizable#getProperty(String)} will be searched for a match.
+ *
+ * @param relPath A relative property path or name.
+ * @param value A string value to match.
+ * @return All Authorizables that have a property with the given
+ * name exactly matching the given value.
+ * @throws RepositoryException If an error occurs.
+ * @see Authorizable#getProperty(String)
+ */
+ Iterator findAuthorizables(String relPath, String value) throws RepositoryException;
+
+ /**
+ * Returns all Authorizables that have a
+ * {@link Authorizable#getProperty(String) property} with the given relative
+ * path (or name) that matches the specified value. In contrast to
+ * {@link #findAuthorizables(String, String)} the type of authorizable is
+ * respected while executing the search.
+ *
+ * If a relative path with more than one segment is specified only properties
+ * exactly matching that path will be returned. If, however, a name is
+ * specified all properties that may be retrieved using
+ * {@link Authorizable#getProperty(String)} will be searched for a match.
+ *
+ * @param relPath A relative property path or name.
+ * @param value A string value to match.
+ * @param searchType Any of the following constants:
+ *
+ *
{@link #SEARCH_TYPE_AUTHORIZABLE}
+ *
{@link #SEARCH_TYPE_GROUP}
+ *
{@link #SEARCH_TYPE_USER}
+ *
+ * @return An iterator of Authorizable.
+ * @throws RepositoryException If an error occurs.
+ */
+ Iterator findAuthorizables(String relPath, String value, int searchType) throws RepositoryException;
+
+ /**
+ * Return {@link Authorizable}s that match a specific {@link Query}.
+ *
+ * @param query A query
+ * @return Iterator of authorizables witch match the query.
+ * @throws RepositoryException If an error occurs.
+ */
+ Iterator findAuthorizables(Query query) throws RepositoryException;
+
+ /**
+ * Creates an User for the given userID / password pair; neither of the
+ * specified parameters can be null.
+ * Same as {@link #createUser(String,String,Principal,String)} where
+ * the specified userID is equal to the principal name and the intermediate
+ * path is null.
+ *
+ * @param userID The ID of the new user.
+ * @param password The initial password of this user.
+ * @return The new User.
+ * @throws AuthorizableExistsException in case the given userID is already
+ * in use or another Authorizable with the same principal name exists.
+ * @throws RepositoryException If another error occurs.
+ */
+ User createUser(String userID, String password) throws AuthorizableExistsException, RepositoryException;
+
+ /**
+ * Creates an User for the given userID / password pair; neither of the
+ * specified parameters can be null.
+ * Same as {@link #createUser(String,String,Principal,String)} where
+ * the specified userID is equal to the principal name and the intermediate
+ * path is null.
+ *
+ * @param userID The ID of the new user.
+ * @param password The initial password of this user.
+ * @param forceHash Always hash the password provided, otherwise
+ * only hash the password if the password appears to be plain-text
+ * @return The new User.
+ * @throws AuthorizableExistsException in case the given userID is already
+ * in use or another Authorizable with the same principal name exists.
+ * @throws RepositoryException If another error occurs.
+ */
+ User createUser(String userID, String password, boolean forceHash) throws AuthorizableExistsException, RepositoryException;
+
+ /**
+ * Creates an User for the given parameters. If the implementation is not
+ * able to deal with the intermediatePath that parameter should
+ * be ignored.
+ * Except for the intermediatePath, neither of the specified
+ * parameters can be null.
+ *
+ * @param userID The ID of the new user.
+ * @param password The initial password of the new user.
+ * @param principal The principal of the new user.
+ * @param intermediatePath An optional intermediate path used to create the
+ * new user. If the intermediate path is null an internal,
+ * implementation specific structure will be used.
+ * @return The new User.
+ * @throws AuthorizableExistsException in case the given userID is already
+ * in use or another Authorizable with the same principal name exists.
+ * @throws RepositoryException If the current Session is
+ * not allowed to create users or some another error occurs.
+ */
+ User createUser(String userID, String password, Principal principal,
+ String intermediatePath) throws AuthorizableExistsException, RepositoryException;
+
+ /**
+ * Creates an User for the given parameters. If the implementation is not
+ * able to deal with the intermediatePath that parameter should
+ * be ignored.
+ * Except for the intermediatePath, neither of the specified
+ * parameters can be null.
+ *
+ * @param userID The ID of the new user.
+ * @param password The initial password of the new user.
+ * @param forceHash Always hash the password provided, otherwise
+ * only hash the password if the password appears to be plain-text
+ * @param principal The principal of the new user.
+ * @param intermediatePath An optional intermediate path used to create the
+ * new user. If the intermediate path is null an internal,
+ * implementation specific structure will be used.
+ * @return The new User.
+ * @throws AuthorizableExistsException in case the given userID is already
+ * in use or another Authorizable with the same principal name exists.
+ * @throws RepositoryException If the current Session is
+ * not allowed to create users or some another error occurs.
+ */
+ User createUser(String userID, String password, boolean forceHash, Principal principal, String intermediatePath)
+ throws AuthorizableExistsException, RepositoryException;
+
+ /**
+ * Create a new system user for the specified {@code userID}. The new authorizable
+ * is required to have the following characteristics:
+ *
+ *
The system user doesn't have a password set and doesn't allow change the password.
+ *
The principal name is generated by the system; it may be the same as {@code userID}.
+ *
A given implementation may choose to keep system users in a dedicated
+ * location and thus may impose restrictions on the {@code intermediatePath}.
+ *
+ *
+ * @param userID A valid userID.
+ * @param intermediatePath An optional intermediate path to create the new
+ * system user. The implemenation may decide to reject intermediate paths
+ * if they violate an implementation specific requirement with respect to
+ * the location where systems users are being held. If the intermediate path
+ * is {@code null} an internal implementation specific structure will be used.
+ * @return The new system user.
+ * @throws AuthorizableExistsException if an Authorizable with this id already exists.
+ * @throws RepositoryException If another error occurs.
+ */
+ User createSystemUser(String userID, String intermediatePath) throws AuthorizableExistsException, RepositoryException;
+
+ /**
+ * Creates a Group for the given groupID, which must not be null.
+ *
+ * Same as {@link #createGroup(String, Principal,String)} where the specified
+ * groupID is the name of the Principal the intermediate path
+ * is null.
+ *
+ * @param groupID The ID of the new group; must not be null.
+ * @return The new Group.
+ * @throws AuthorizableExistsException in case the given groupID is already
+ * in use or another {@link Authorizable} with the same
+ * {@link Authorizable#getID() ID} or principal name already exists.
+ * @throws RepositoryException If another error occurs.
+ */
+ Group createGroup(String groupID) throws AuthorizableExistsException, RepositoryException;
+
+ /**
+ * Creates a new Group that is based on the given principal.
+ * Note that the group's ID is implementation specific. The implementation
+ * may take the principal name as ID hint but must in any case assert that
+ * it is unique among the IDs known to this manager.
+ *
+ * @param principal A non-null Principal
+ * @return The new Group.
+ * @throws AuthorizableExistsException in case the given principal is
+ * already in use with another Authorizable.
+ * @throws RepositoryException If another error occurs.
+ */
+ Group createGroup(Principal principal) throws AuthorizableExistsException, RepositoryException;
+
+ /**
+ * Same as {@link #createGroup(String, Principal, String)} where the
+ * name of the specified principal is used to create the group's ID.
+ *
+ * @param principal The principal associated with the new group.
+ * @param intermediatePath An optional intermediate path used to create the
+ * new group. If the intermediate path is null an internal,
+ * implementation specific structure will be used.
+ * @return The new Group.
+ * @throws AuthorizableExistsException in case the given principal is
+ * already in use with another Authorizable.
+ * @throws RepositoryException If another error occurs.
+ */
+ Group createGroup(Principal principal, String intermediatePath) throws AuthorizableExistsException, RepositoryException;
+
+ /**
+ * Creates a new Group that is based on the given id, principal
+ * and the specified intermediatePath hint. If the implementation
+ * is not able to deal with the intermediatePath this parameter
+ * should be ignored.
+ *
+ * @param groupID The ID of the new group.
+ * @param principal The principal of the new group.
+ * @param intermediatePath An optional intermediate path used to create the
+ * new group. If the intermediate path is null an internal,
+ * implementation specific structure will be used.
+ * @return The new Group.
+ * @throws AuthorizableExistsException in case the given principal is already
+ * in use with another Authorizable.
+ * @throws RepositoryException If another error occurs.
+ */
+ Group createGroup(String groupID, Principal principal, String intermediatePath) throws AuthorizableExistsException, RepositoryException;
+
+ /**
+ * If any write operations executed through the User API are automatically
+ * persisted this method returns true. In this case there are
+ * no pending transient changes left and there is no need to explicitly call
+ * {@link javax.jcr.Session#save()}. If this method returns false
+ * any changes must be completed by an extra save call on the
+ * Session associated with this UserManager.
+ *
+ * @return true if changes are automatically persisted;
+ * false if changes made through this API (including method
+ * calls on {@link Authorizable} and subclasses are only transient and
+ * must be persisted using {@link javax.jcr.Session#save()}.
+ * @see #autoSave(boolean)
+ */
+ boolean isAutoSave();
+
+ /**
+ * Changes the auto save behavior of this UserManager.
+ *
+ * Note, that this shouldn't be allowed in cases where the associated session
+ * is different from the original session accessing the user manager.
+ *
+ * @param enable If true changes made through this API will
+ * be automatically saved; otherwise an explicit call to
+ * {@link javax.jcr.Session#save()} is required in order to persist changes.
+ * @throws UnsupportedRepositoryOperationException If the implementation
+ * does not allow to change the auto save behavior.
+ * @throws RepositoryException If some other error occurs.
+ */
+ void autoSave(boolean enable) throws UnsupportedRepositoryOperationException, RepositoryException;
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/package-info.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/package-info.java
new file mode 100644
index 00000000000..21316bfddf6
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/**
+ * Jackrabbit extensions for user management.
+ */
+@aQute.bnd.annotation.Version("2.4.0")
+package org.apache.jackrabbit.api.security.user;
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/stats/QueryStat.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/stats/QueryStat.java
new file mode 100644
index 00000000000..13786db55ba
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/stats/QueryStat.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.jackrabbit.api.stats;
+
+/**
+ * Statistics on query operations
+ *
+ */
+public interface QueryStat {
+
+ /**
+ * @return a sorted array containing the top
+ * {@link #getSlowQueriesQueueSize()} slowest queries
+ */
+ QueryStatDto[] getSlowQueries();
+
+ /**
+ * @return size of the Slow queue
+ */
+ int getSlowQueriesQueueSize();
+
+ /**
+ * Change the size of the Slow queue
+ *
+ * @param size
+ * the new size
+ */
+ void setSlowQueriesQueueSize(int size);
+
+ /**
+ * clears the Slow queue
+ */
+ void clearSlowQueriesQueue();
+
+ /**
+ * @return a sorted array containing the
+ * {@link #getPopularQueriesQueueSize()} most popular queries
+ */
+ QueryStatDto[] getPopularQueries();
+
+ /**
+ * @return size of the Popular queue
+ */
+ int getPopularQueriesQueueSize();
+
+ /**
+ * Change the size of the Popular queue
+ *
+ * @param size
+ * the new size
+ */
+ void setPopularQueriesQueueSize(int size);
+
+ /**
+ * clears the Popular queue
+ */
+ void clearPopularQueriesQueue();
+
+ /** -- GENERAL OPS -- **/
+
+ /**
+ * If this service is currently registering stats
+ *
+ * @return true if the service is enabled
+ */
+ boolean isEnabled();
+
+ /**
+ * Enables/Disables the service
+ *
+ * @param enabled
+ */
+ void setEnabled(boolean enabled);
+
+ /**
+ * clears all data
+ */
+ void reset();
+
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/stats/QueryStatDto.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/stats/QueryStatDto.java
new file mode 100644
index 00000000000..4f66fcada87
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/stats/QueryStatDto.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.jackrabbit.api.stats;
+
+import java.io.Serializable;
+
+/**
+ * Object that holds statistical info about a query.
+ *
+ */
+public interface QueryStatDto extends Serializable {
+
+ long getDuration();
+
+ String getLanguage();
+
+ String getStatement();
+
+ String getCreationTime();
+
+ int getOccurrenceCount();
+
+ long getPosition();
+
+ void setPosition(long position);
+
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/stats/RepositoryStatistics.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/stats/RepositoryStatistics.java
new file mode 100644
index 00000000000..4d206262d91
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/stats/RepositoryStatistics.java
@@ -0,0 +1,147 @@
+/*
+ * 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.jackrabbit.api.stats;
+
+
+/**
+ * Statistics on core repository operations
+ *
+ */
+public interface RepositoryStatistics {
+
+ /**
+ * The values of this enum determine the type of the time
+ * series returned by {@link #getTimeSeries(Type)}
+ * and link {@link #getTimeSeries(String, boolean)}.
+ */
+ enum Type {
+ BUNDLE_READ_COUNTER(true),
+ BUNDLE_WRITE_COUNTER(true),
+ BUNDLE_WRITE_DURATION(true),
+ BUNDLE_WRITE_AVERAGE(false),
+ BUNDLE_CACHE_ACCESS_COUNTER(true),
+ BUNDLE_CACHE_SIZE_COUNTER(false),
+ BUNDLE_CACHE_MISS_COUNTER(true),
+ BUNDLE_CACHE_MISS_DURATION(true),
+ BUNDLE_CACHE_MISS_AVERAGE(false),
+ BUNDLE_COUNTER(true),
+ BUNDLE_WS_SIZE_COUNTER(true),
+
+ /**
+ * Number of read accesses through any session.
+ */
+ SESSION_READ_COUNTER(true),
+
+ /**
+ * Total time spent reading from sessions in nano seconds.
+ */
+ SESSION_READ_DURATION(true),
+
+ /**
+ * Average time spent reading from sessions in nano seconds.
+ * This is the sum of all read durations divided by the number
+ * of reads in the respective time period.
+ */
+ SESSION_READ_AVERAGE(false),
+
+ /**
+ * Number of write accesses through any session.
+ */
+ SESSION_WRITE_COUNTER(true),
+
+ /**
+ * Total time spent writing to sessions in nano seconds.
+ */
+ SESSION_WRITE_DURATION(true),
+
+ /**
+ * Average time spent writing to sessions in nano seconds.
+ * This is the sum of all write durations divided by the number
+ * of writes in the respective time period.
+ */
+ SESSION_WRITE_AVERAGE(false),
+
+ /**
+ * Number of calls sessions that have been logged in.
+ */
+ SESSION_LOGIN_COUNTER(true),
+
+ /**
+ * Number of currently logged in sessions.
+ */
+ SESSION_COUNT(false),
+
+ /**
+ * Number of queries executed.
+ */
+ QUERY_COUNT(true),
+
+ /**
+ * Total time spent evaluating queries in milli seconds.
+ */
+ QUERY_DURATION(true),
+
+ /**
+ * Average time spent evaluating queries in milli seconds.
+ * This is the sum of all query durations divided by the number
+ * of queries in the respective time period.
+ */
+ QUERY_AVERAGE(true),
+
+ /**
+ * Total number of observation {@code Event} instances delivered
+ * to all observation listeners.
+ */
+ OBSERVATION_EVENT_COUNTER(true),
+
+ /**
+ * Total time spent processing observation events by all observation
+ * listeners in nano seconds.
+ */
+ OBSERVATION_EVENT_DURATION(true),
+
+ /**
+ * Average time spent processing observation events by all observation
+ * listeners in nano seconds.
+ * This is the sum of all observation durations divided by the number
+ * of observation events in the respective time period.
+ */
+ OBSERVATION_EVENT_AVERAGE(true);
+
+ private final boolean resetValueEachSecond;
+
+ Type(final boolean resetValueEachSecond) {
+ this.resetValueEachSecond = resetValueEachSecond;
+ }
+
+ public static Type getType(String type) {
+ Type realType = null;
+ try {
+ realType = valueOf(type);
+ } catch (IllegalArgumentException ignore) {}
+ return realType;
+ }
+
+ public boolean isResetValueEachSecond() {
+ return resetValueEachSecond;
+ }
+ }
+
+ TimeSeries getTimeSeries(Type type);
+
+ TimeSeries getTimeSeries(String type, boolean resetValueEachSecond);
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/stats/TimeSeries.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/stats/TimeSeries.java
new file mode 100755
index 00000000000..6c21a32265b
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/stats/TimeSeries.java
@@ -0,0 +1,64 @@
+/*
+ * 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.jackrabbit.api.stats;
+
+/**
+ * Interface for a time series of the measured values per
+ * second, minute, hour and day. The type of the value is arbitrary; it
+ * could be cache hits or misses, disk reads or writes, created sessions,
+ * completed transactions, or pretty much anything of interest.
+ *
+ * @since Apache Jackrabbit 2.3.2
+ */
+public interface TimeSeries {
+
+ /**
+ * Returns the measured value per second over the last minute.
+ *
+ * @return measured value per second, in chronological order
+ */
+ long[] getValuePerSecond();
+
+ /**
+ * Returns the measured value per minute over the last hour.
+ *
+ * @return measured value per minute, in chronological order
+ */
+ long[] getValuePerMinute();
+
+ /**
+ * Returns the measured value per hour over the last week.
+ *
+ * @return measured value per hour, in chronological order
+ */
+ long[] getValuePerHour();
+
+ /**
+ * Returns the measured value per week over the last three years.
+ *
+ * @return measured value per week, in chronological order
+ */
+ long[] getValuePerWeek();
+
+ /**
+ * The value used to encode missing values i.e. for a period where no value was recorded.
+ *
+ * @return default value
+ */
+ long getMissingValue();
+
+}
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/stats/package-info.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/stats/package-info.java
new file mode 100644
index 00000000000..c1e99922c9e
--- /dev/null
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/stats/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/**
+ * Jackrabbit repository statistics
+ */
+@aQute.bnd.annotation.Version("1.2.0")
+package org.apache.jackrabbit.api.stats;
diff --git a/jackrabbit-api/src/main/javadoc/org/apache/jackrabbit/api/package.html b/jackrabbit-api/src/main/javadoc/org/apache/jackrabbit/api/package.html
new file mode 100644
index 00000000000..135c2bfaea9
--- /dev/null
+++ b/jackrabbit-api/src/main/javadoc/org/apache/jackrabbit/api/package.html
@@ -0,0 +1,19 @@
+
+
+Contains set of interfaces that form the Jackrabbit-specific extensions to the JCR API
+
diff --git a/jackrabbit-aws-ext/README.txt b/jackrabbit-aws-ext/README.txt
new file mode 100644
index 00000000000..864329c95e7
--- /dev/null
+++ b/jackrabbit-aws-ext/README.txt
@@ -0,0 +1,28 @@
+====================================================
+Welcome to Jackrabbit Amazon WebServices Extension
+====================================================
+
+This is the Amazon Webservices Extension component of the Apache Jackrabbit project.
+This component contains S3 Datastore which stores binaries on Amazon S3 (http://aws.amazon.com/s3).
+
+====================================================
+Build Instructions
+====================================================
+To build the latest SNAPSHOT versions of all the components
+included here, run the following command with Maven 3:
+
+ mvn clean install
+
+To run testcases which stores in S3 bucket, please pass aws config file via system property. For e.g.
+
+ mvn clean install -DargLine="-Dconfig=/opt/cq/aws.properties"
+
+Sample aws properties located at src/test/resources/aws.properties
+
+====================================================
+Configuration Instructions
+====================================================
+It require to configure aws.properties to configure S3 Datastore.
+
+
+
diff --git a/jackrabbit-aws-ext/pom.xml b/jackrabbit-aws-ext/pom.xml
new file mode 100644
index 00000000000..0aa602226f7
--- /dev/null
+++ b/jackrabbit-aws-ext/pom.xml
@@ -0,0 +1,109 @@
+
+
+
+
+
+ 4.0.0
+
+
+
+
+
+ org.apache.jackrabbit
+ jackrabbit-parent
+ 2.13.5-SNAPSHOT
+ ../jackrabbit-parent/pom.xml
+
+ jackrabbit-aws-ext
+ Jackrabbit AWS Extension
+ Jackrabbit extenstion to Amazon Webservices
+ bundle
+
+
+
+
+
+
+ javax.jcr
+ jcr
+
+
+ org.apache.jackrabbit
+ jackrabbit-jcr-commons
+ ${project.version}
+
+
+ com.amazonaws
+ aws-java-sdk-s3
+ 1.10.27
+
+
+ org.apache.jackrabbit
+ jackrabbit-data
+ ${project.version}
+
+
+ org.apache.jackrabbit
+ jackrabbit-data
+ ${project.version}
+ test-jar
+
+
+ org.slf4j
+ slf4j-api
+
+
+
+ junit
+ junit
+ test
+
+
+ org.slf4j
+ slf4j-log4j12
+ 1.7.5
+ test
+
+
+
+
+
+ maven-surefire-plugin
+
+
+ **/aws/**/TestAll.java
+
+
+
+
+ org.apache.felix
+ maven-bundle-plugin
+ true
+
+
+ org.apache.jackrabbit.aws.ext.ds
+ sun.io
+
+
+
+
+ org.apache.rat
+ apache-rat-plugin
+
+
+ .checkstyle
+
+
+
+
+
+
diff --git a/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/S3Constants.java b/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/S3Constants.java
new file mode 100644
index 00000000000..29da427a06d
--- /dev/null
+++ b/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/S3Constants.java
@@ -0,0 +1,117 @@
+/*
+ * 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.jackrabbit.aws.ext;
+
+/**
+ * Defined Amazon S3 constants.
+ */
+public final class S3Constants {
+
+ /**
+ * Amazon aws access key.
+ */
+ public static final String ACCESS_KEY = "accessKey";
+
+ /**
+ * Amazon aws secret key.
+ */
+ public static final String SECRET_KEY = "secretKey";
+
+ /**
+ * Amazon S3 Http connection timeout.
+ */
+ public static final String S3_CONN_TIMEOUT = "connectionTimeout";
+
+ /**
+ * Amazon S3 socket timeout.
+ */
+ public static final String S3_SOCK_TIMEOUT = "socketTimeout";
+
+ /**
+ * Amazon S3 maximum connections to be used.
+ */
+ public static final String S3_MAX_CONNS = "maxConnections";
+
+ /**
+ * Amazon S3 maximum retries.
+ */
+ public static final String S3_MAX_ERR_RETRY = "maxErrorRetry";
+
+ /**
+ * Amazon aws S3 bucket.
+ */
+ public static final String S3_BUCKET = "s3Bucket";
+
+ /**
+ * Amazon aws S3 region.
+ */
+ public static final String S3_REGION = "s3Region";
+
+ /**
+ * Amazon aws S3 region.
+ */
+ public static final String S3_END_POINT = "s3EndPoint";
+
+ /**
+ * Constant for S3 Connector Protocol
+ */
+ public static final String S3_CONN_PROTOCOL = "s3ConnProtocol";
+
+ /**
+ * Constant to rename keys
+ */
+ public static final String S3_RENAME_KEYS = "s3RenameKeys";
+
+ /**
+ * Constant to rename keys
+ */
+ public static final String S3_WRITE_THREADS = "writeThreads";
+
+ /**
+ * Constant to enable encryption in S3.
+ */
+ public static final String S3_ENCRYPTION = "s3Encryption";
+
+ /**
+ * Constant for no encryption. it is default.
+ */
+ public static final String S3_ENCRYPTION_NONE = "NONE";
+
+ /**
+ * Constant to set SSE_S3 encryption.
+ */
+ public static final String S3_ENCRYPTION_SSE_S3 = "SSE_S3";
+
+ /**
+ * Constant to set proxy host.
+ */
+ public static final String PROXY_HOST = "proxyHost";
+
+ /**
+ * Constant to set proxy port.
+ */
+ public static final String PROXY_PORT = "proxyPort";
+
+ /**
+ * private constructor so that class cannot initialized from outside.
+ */
+ private S3Constants() {
+
+ }
+
+}
diff --git a/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/S3RequestDecorator.java b/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/S3RequestDecorator.java
new file mode 100644
index 00000000000..2fcc2444ffe
--- /dev/null
+++ b/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/S3RequestDecorator.java
@@ -0,0 +1,87 @@
+/*
+ * 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.jackrabbit.aws.ext;
+
+import java.util.Properties;
+
+import com.amazonaws.services.s3.model.CopyObjectRequest;
+import com.amazonaws.services.s3.model.ObjectMetadata;
+import com.amazonaws.services.s3.model.PutObjectRequest;
+
+/**
+ * This class to sets encrption mode in S3 request.
+ *
+ */
+public class S3RequestDecorator {
+ DataEncryption dataEncryption = DataEncryption.NONE;
+
+ public S3RequestDecorator(Properties props) {
+ if (props.getProperty(S3Constants.S3_ENCRYPTION) != null) {
+ this.dataEncryption = dataEncryption.valueOf(props.getProperty(S3Constants.S3_ENCRYPTION));
+ }
+ }
+
+ /**
+ * Set encryption in {@link PutObjectRequest}
+ */
+ public PutObjectRequest decorate(PutObjectRequest request) {
+ switch (getDataEncryption()) {
+ case SSE_S3:
+ ObjectMetadata metadata = request.getMetadata() == null
+ ? new ObjectMetadata()
+ : request.getMetadata();
+ metadata.setSSEAlgorithm(ObjectMetadata.AES_256_SERVER_SIDE_ENCRYPTION);
+ request.setMetadata(metadata);
+ break;
+ case NONE:
+ break;
+ }
+ return request;
+ }
+
+ /**
+ * Set encryption in {@link CopyObjectRequest}
+ */
+ public CopyObjectRequest decorate(CopyObjectRequest request) {
+ switch (getDataEncryption()) {
+ case SSE_S3:
+ ObjectMetadata metadata = request.getNewObjectMetadata() == null
+ ? new ObjectMetadata()
+ : request.getNewObjectMetadata();
+ metadata.setSSEAlgorithm(ObjectMetadata.AES_256_SERVER_SIDE_ENCRYPTION);
+ request.setNewObjectMetadata(metadata);
+ break;
+ case NONE:
+ break;
+ }
+ return request;
+ }
+
+ private DataEncryption getDataEncryption() {
+ return this.dataEncryption;
+ }
+
+ /**
+ * Enum to indicate S3 encryption mode
+ *
+ */
+ private enum DataEncryption {
+ SSE_S3, NONE;
+ }
+
+}
diff --git a/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/Utils.java b/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/Utils.java
new file mode 100644
index 00000000000..00d66f21498
--- /dev/null
+++ b/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/Utils.java
@@ -0,0 +1,227 @@
+/*
+ * 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.jackrabbit.aws.ext;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.amazonaws.AmazonClientException;
+import com.amazonaws.ClientConfiguration;
+import com.amazonaws.Protocol;
+import com.amazonaws.auth.AWSCredentials;
+import com.amazonaws.auth.BasicAWSCredentials;
+import com.amazonaws.regions.Regions;
+import com.amazonaws.services.s3.AmazonS3;
+import com.amazonaws.services.s3.AmazonS3Client;
+import com.amazonaws.services.s3.model.ObjectListing;
+import com.amazonaws.services.s3.model.Region;
+import com.amazonaws.services.s3.model.S3ObjectSummary;
+import com.amazonaws.util.StringUtils;
+
+/**
+ * Amazon S3 utilities.
+ */
+public final class Utils {
+
+ private static final Logger LOG = LoggerFactory.getLogger(Utils.class);
+
+ public static final String DEFAULT_CONFIG_FILE = "aws.properties";
+
+ private static final String DELETE_CONFIG_SUFFIX = ";burn";
+
+ /**
+ * The default value AWS bucket region.
+ */
+ public static final String DEFAULT_AWS_BUCKET_REGION = "us-standard";
+
+ /**
+ * constants to define endpoint to various AWS region
+ */
+ public static final String AWSDOTCOM = "amazonaws.com";
+
+ public static final String S3 = "s3";
+
+ public static final String DOT = ".";
+
+ public static final String DASH = "-";
+
+ /**
+ * private constructor so that class cannot initialized from outside.
+ */
+ private Utils() {
+
+ }
+
+ /**
+ * Create AmazonS3Client from properties.
+ *
+ * @param prop properties to configure @link {@link AmazonS3Client}
+ * @return {@link AmazonS3Client}
+ */
+ public static AmazonS3Client openService(final Properties prop) {
+ String accessKey = prop.getProperty(S3Constants.ACCESS_KEY);
+ String secretKey = prop.getProperty(S3Constants.SECRET_KEY);
+ AmazonS3Client s3service = null;
+ if (StringUtils.isNullOrEmpty(accessKey)
+ || StringUtils.isNullOrEmpty(secretKey)) {
+ LOG.info("Configuring Amazon Client from environment");
+ s3service = new AmazonS3Client(getClientConfiguration(prop));
+ } else {
+ LOG.info("Configuring Amazon Client from property file.");
+ AWSCredentials credentials = new BasicAWSCredentials(accessKey,
+ secretKey);
+ s3service = new AmazonS3Client(credentials,
+ getClientConfiguration(prop));
+ }
+ String region = prop.getProperty(S3Constants.S3_REGION);
+ String endpoint = null;
+ String propEndPoint = prop.getProperty(S3Constants.S3_END_POINT);
+ if ((propEndPoint != null) & !"".equals(propEndPoint)) {
+ endpoint = propEndPoint;
+ } else {
+ if (StringUtils.isNullOrEmpty(region)) {
+ com.amazonaws.regions.Region s3Region = Regions.getCurrentRegion();
+ if (s3Region != null) {
+ region = s3Region.getName();
+ } else {
+ throw new AmazonClientException(
+ "parameter ["
+ + S3Constants.S3_REGION
+ + "] not configured and cannot be derived from environment");
+ }
+ }
+ if (DEFAULT_AWS_BUCKET_REGION.equals(region)) {
+ endpoint = S3 + DOT + AWSDOTCOM;
+ } else if (Region.EU_Ireland.toString().equals(region)) {
+ endpoint = "s3-eu-west-1" + DOT + AWSDOTCOM;
+ } else {
+ endpoint = S3 + DASH + region + DOT + AWSDOTCOM;
+ }
+ }
+ /*
+ * setting endpoint to remove latency of redirection. If endpoint is
+ * not set, invocation first goes us standard region, which
+ * redirects it to correct location.
+ */
+ s3service.setEndpoint(endpoint);
+ LOG.info("S3 service endpoint [{}] ", endpoint);
+ return s3service;
+ }
+
+ /**
+ * Delete S3 bucket. This method first deletes all objects from bucket and
+ * then delete empty bucket.
+ *
+ * @param bucketName the bucket name.
+ */
+ public static void deleteBucket(final String bucketName) throws IOException {
+ Properties prop = readConfig(DEFAULT_CONFIG_FILE);
+ AmazonS3 s3service = openService(prop);
+ ObjectListing prevObjectListing = s3service.listObjects(bucketName);
+ while (true) {
+ for (S3ObjectSummary s3ObjSumm : prevObjectListing.getObjectSummaries()) {
+ s3service.deleteObject(bucketName, s3ObjSumm.getKey());
+ }
+ if (!prevObjectListing.isTruncated()) {
+ break;
+ }
+ prevObjectListing = s3service.listNextBatchOfObjects(prevObjectListing);
+ }
+ s3service.deleteBucket(bucketName);
+ }
+
+ /**
+ * Read a configuration properties file. If the file name ends with ";burn",
+ * the file is deleted after reading.
+ *
+ * @param fileName the properties file name
+ * @return the properties
+ * @throws IOException if the file doesn't exist
+ */
+ public static Properties readConfig(String fileName) throws IOException {
+ boolean delete = false;
+ if (fileName.endsWith(DELETE_CONFIG_SUFFIX)) {
+ delete = true;
+ fileName = fileName.substring(0, fileName.length()
+ - DELETE_CONFIG_SUFFIX.length());
+ }
+ if (!new File(fileName).exists()) {
+ throw new IOException("Config file not found: " + fileName);
+ }
+ Properties prop = new Properties();
+ InputStream in = null;
+ try {
+ in = new FileInputStream(fileName);
+ prop.load(in);
+ } finally {
+ if (in != null) {
+ in.close();
+ }
+ if (delete) {
+ deleteIfPossible(new File(fileName));
+ }
+ }
+ return prop;
+ }
+
+ private static void deleteIfPossible(final File file) {
+ boolean deleted = file.delete();
+ if (!deleted) {
+ LOG.warn("Could not delete " + file.getAbsolutePath());
+ }
+ }
+
+ private static ClientConfiguration getClientConfiguration(Properties prop) {
+ int connectionTimeOut = Integer.parseInt(prop.getProperty(S3Constants.S3_CONN_TIMEOUT));
+ int socketTimeOut = Integer.parseInt(prop.getProperty(S3Constants.S3_SOCK_TIMEOUT));
+ int maxConnections = Integer.parseInt(prop.getProperty(S3Constants.S3_MAX_CONNS));
+ int maxErrorRetry = Integer.parseInt(prop.getProperty(S3Constants.S3_MAX_ERR_RETRY));
+
+ String protocol = prop.getProperty(S3Constants.S3_CONN_PROTOCOL);
+ String proxyHost = prop.getProperty(S3Constants.PROXY_HOST);
+ String proxyPort = prop.getProperty(S3Constants.PROXY_PORT);
+
+ ClientConfiguration cc = new ClientConfiguration();
+
+ if (protocol != null && protocol.equalsIgnoreCase("http")) {
+ cc.setProtocol(Protocol.HTTP);
+ }
+
+ if (proxyHost != null && !proxyHost.isEmpty()) {
+ cc.setProxyHost(proxyHost);
+ }
+
+ if (proxyPort != null && !proxyPort.isEmpty()) {
+ cc.setProxyPort(Integer.parseInt(proxyPort));
+ }
+
+ cc.setConnectionTimeout(connectionTimeOut);
+ cc.setSocketTimeout(socketTimeOut);
+ cc.setMaxConnections(maxConnections);
+ cc.setMaxErrorRetry(maxErrorRetry);
+
+ return cc;
+ }
+
+}
diff --git a/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/ds/S3Backend.java b/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/ds/S3Backend.java
new file mode 100644
index 00000000000..01e87ddb403
--- /dev/null
+++ b/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/ds/S3Backend.java
@@ -0,0 +1,921 @@
+/*
+ * 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.jackrabbit.aws.ext.ds;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.jackrabbit.aws.ext.S3Constants;
+import org.apache.jackrabbit.aws.ext.S3RequestDecorator;
+import org.apache.jackrabbit.aws.ext.Utils;
+import org.apache.jackrabbit.core.data.AbstractBackend;
+import org.apache.jackrabbit.core.data.AsyncTouchCallback;
+import org.apache.jackrabbit.core.data.AsyncTouchResult;
+import org.apache.jackrabbit.core.data.AsyncUploadCallback;
+import org.apache.jackrabbit.core.data.AsyncUploadResult;
+import org.apache.jackrabbit.core.data.CachingDataStore;
+import org.apache.jackrabbit.core.data.DataIdentifier;
+import org.apache.jackrabbit.core.data.DataStoreException;
+import org.apache.jackrabbit.core.data.util.NamedThreadFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.amazonaws.AmazonClientException;
+import com.amazonaws.AmazonServiceException;
+import com.amazonaws.event.ProgressEvent;
+import com.amazonaws.event.ProgressListener;
+import com.amazonaws.regions.Regions;
+import com.amazonaws.services.s3.AmazonS3Client;
+import com.amazonaws.services.s3.model.CopyObjectRequest;
+import com.amazonaws.services.s3.model.DeleteObjectsRequest;
+import com.amazonaws.services.s3.model.DeleteObjectsResult;
+import com.amazonaws.services.s3.model.ObjectListing;
+import com.amazonaws.services.s3.model.ObjectMetadata;
+import com.amazonaws.services.s3.model.PutObjectRequest;
+import com.amazonaws.services.s3.model.Region;
+import com.amazonaws.services.s3.model.S3Object;
+import com.amazonaws.services.s3.model.S3ObjectSummary;
+import com.amazonaws.services.s3.transfer.Copy;
+import com.amazonaws.services.s3.transfer.TransferManager;
+import com.amazonaws.services.s3.transfer.Upload;
+import com.amazonaws.util.StringUtils;
+
+/**
+ * A data store backend that stores data on Amazon S3.
+ */
+public class S3Backend extends AbstractBackend {
+
+ /**
+ * Logger instance.
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(S3Backend.class);
+
+ private static final String KEY_PREFIX = "dataStore_";
+
+ private AmazonS3Client s3service;
+
+ private String bucket;
+
+ private TransferManager tmx;
+
+ private Properties properties;
+
+ private Date startTime;
+
+ private S3RequestDecorator s3ReqDecorator;
+
+ /**
+ * Initialize S3Backend. It creates AmazonS3Client and TransferManager from
+ * aws.properties. It creates S3 bucket if it doesn't pre-exist in S3.
+ */
+ @Override
+ public void init(CachingDataStore store, String homeDir, String config)
+ throws DataStoreException {
+ super.init(store, homeDir, config);
+ Properties initProps = null;
+ //Check is configuration is already provided. That takes precedence
+ //over config provided via file based config
+ if(this.properties != null){
+ initProps = this.properties;
+ } else {
+ if(config == null){
+ config = Utils.DEFAULT_CONFIG_FILE;
+ }
+ try{
+ initProps = Utils.readConfig(config);
+ }catch(IOException e){
+ throw new DataStoreException("Could not initialize S3 from "
+ + config, e);
+ }
+ this.properties = initProps;
+ }
+ init(store, homeDir, initProps);
+ }
+
+ public void init(CachingDataStore store, String homeDir, Properties prop)
+ throws DataStoreException {
+
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ startTime = new Date();
+ Thread.currentThread().setContextClassLoader(
+ getClass().getClassLoader());
+ LOG.debug("init");
+ setDataStore(store);
+ s3ReqDecorator = new S3RequestDecorator(prop);
+
+ s3service = Utils.openService(prop);
+ if (bucket == null || "".equals(bucket.trim())) {
+ bucket = prop.getProperty(S3Constants.S3_BUCKET);
+ }
+ String region = prop.getProperty(S3Constants.S3_REGION);
+ Region s3Region = null;
+ if (StringUtils.isNullOrEmpty(region)) {
+ com.amazonaws.regions.Region ec2Region = Regions.getCurrentRegion();
+ if (ec2Region != null) {
+ s3Region = Region.fromValue(ec2Region.getName());
+ } else {
+ throw new AmazonClientException(
+ "parameter ["
+ + S3Constants.S3_REGION
+ + "] not configured and cannot be derived from environment");
+ }
+ } else {
+ if (Utils.DEFAULT_AWS_BUCKET_REGION.equals(region)) {
+ s3Region = Region.US_Standard;
+ } else if (Region.EU_Ireland.toString().equals(region)) {
+ s3Region = Region.EU_Ireland;
+ } else {
+ s3Region = Region.fromValue(region);
+ }
+ }
+
+ if (!s3service.doesBucketExist(bucket)) {
+ s3service.createBucket(bucket, s3Region);
+ LOG.info("Created bucket [{}] in [{}] ", bucket, region);
+ } else {
+ LOG.info("Using bucket [{}] in [{}] ", bucket, region);
+ }
+
+ int writeThreads = 10;
+ String writeThreadsStr = prop.getProperty(S3Constants.S3_WRITE_THREADS);
+ if (writeThreadsStr != null) {
+ writeThreads = Integer.parseInt(writeThreadsStr);
+ }
+ LOG.info("Using thread pool of [{}] threads in S3 transfer manager.", writeThreads);
+ tmx = new TransferManager(s3service,
+ (ThreadPoolExecutor) Executors.newFixedThreadPool(writeThreads,
+ new NamedThreadFactory("s3-transfer-manager-worker")));
+
+ int asyncWritePoolSize = 10;
+ String maxConnsStr = prop.getProperty(S3Constants.S3_MAX_CONNS);
+ if (maxConnsStr != null) {
+ asyncWritePoolSize = Integer.parseInt(maxConnsStr)
+ - writeThreads;
+ }
+ setAsyncWritePoolSize(asyncWritePoolSize);
+ String renameKeyProp = prop.getProperty(S3Constants.S3_RENAME_KEYS);
+ boolean renameKeyBool = (renameKeyProp == null || "".equals(renameKeyProp))
+ ? false
+ : Boolean.parseBoolean(renameKeyProp);
+ LOG.info("Rename keys [{}]", renameKeyBool);
+ if (renameKeyBool) {
+ renameKeys();
+ }
+ LOG.debug("S3 Backend initialized in [{}] ms",
+ +(System.currentTimeMillis() - startTime.getTime()));
+ } catch (Exception e) {
+ LOG.debug(" error ", e);
+ throw new DataStoreException("Could not initialize S3 from "
+ + prop, e);
+ } finally {
+ if (contextClassLoader != null) {
+ Thread.currentThread().setContextClassLoader(contextClassLoader);
+ }
+ }
+ }
+
+ /**
+ * It uploads file to Amazon S3. If file size is greater than 5MB, this
+ * method uses parallel concurrent connections to upload.
+ */
+ @Override
+ public void write(DataIdentifier identifier, File file)
+ throws DataStoreException {
+ this.write(identifier, file, false, null);
+
+ }
+
+ @Override
+ public void writeAsync(DataIdentifier identifier, File file,
+ AsyncUploadCallback callback) throws DataStoreException {
+ if (callback == null) {
+ throw new IllegalArgumentException(
+ "callback parameter cannot be null in asyncUpload");
+ }
+ getAsyncWriteExecutor().execute(new AsyncUploadJob(identifier, file,
+ callback));
+ }
+
+ /**
+ * Check if record identified by identifier exists in Amazon S3.
+ */
+ @Override
+ public boolean exists(DataIdentifier identifier) throws DataStoreException {
+ long start = System.currentTimeMillis();
+ String key = getKeyName(identifier);
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ Thread.currentThread().setContextClassLoader(
+ getClass().getClassLoader());
+ ObjectMetadata objectMetaData = s3service.getObjectMetadata(bucket,
+ key);
+ if (objectMetaData != null) {
+ LOG.trace("exists [{}]: [true] took [{}] ms.",
+ identifier, (System.currentTimeMillis() - start) );
+ return true;
+ }
+ return false;
+ } catch (AmazonServiceException e) {
+ if (e.getStatusCode() == 404 || e.getStatusCode() == 403) {
+ LOG.debug("exists [{}]: [false] took [{}] ms.",
+ identifier, (System.currentTimeMillis() - start) );
+ return false;
+ }
+ throw new DataStoreException(
+ "Error occured to getObjectMetadata for key ["
+ + identifier.toString() + "]", e);
+ } finally {
+ if (contextClassLoader != null) {
+ Thread.currentThread().setContextClassLoader(contextClassLoader);
+ }
+ }
+ }
+
+ @Override
+ public boolean exists(DataIdentifier identifier, boolean touch)
+ throws DataStoreException {
+ long start = System.currentTimeMillis();
+ String key = getKeyName(identifier);
+ ObjectMetadata objectMetaData = null;
+ boolean retVal = false;
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ Thread.currentThread().setContextClassLoader(
+ getClass().getClassLoader());
+ objectMetaData = s3service.getObjectMetadata(bucket, key);
+ if (objectMetaData != null) {
+ retVal = true;
+ if (touch) {
+ CopyObjectRequest copReq = new CopyObjectRequest(bucket,
+ key, bucket, key);
+ copReq.setNewObjectMetadata(objectMetaData);
+ Copy copy = tmx.copy(s3ReqDecorator.decorate(copReq));
+ copy.waitForCopyResult();
+ LOG.debug("[{}] touched took [{}] ms. ", identifier,
+ (System.currentTimeMillis() - start));
+ }
+ } else {
+ retVal = false;
+ }
+
+ } catch (AmazonServiceException e) {
+ if (e.getStatusCode() == 404 || e.getStatusCode() == 403) {
+ retVal = false;
+ } else {
+ throw new DataStoreException(
+ "Error occured to find exists for key ["
+ + identifier.toString() + "]", e);
+ }
+ } catch (Exception e) {
+ throw new DataStoreException(
+ "Error occured to find exists for key "
+ + identifier.toString(), e);
+ } finally {
+ if (contextClassLoader != null) {
+ Thread.currentThread().setContextClassLoader(contextClassLoader);
+ }
+ }
+ LOG.debug("exists [{}]: [{}] took [{}] ms.", new Object[] { identifier,
+ retVal, (System.currentTimeMillis() - start) });
+ return retVal;
+ }
+
+ @Override
+ public void touchAsync(final DataIdentifier identifier,
+ final long minModifiedDate, final AsyncTouchCallback callback)
+ throws DataStoreException {
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ if (callback == null) {
+ throw new IllegalArgumentException(
+ "callback parameter cannot be null in touchAsync");
+ }
+ Thread.currentThread().setContextClassLoader(
+ getClass().getClassLoader());
+
+ getAsyncWriteExecutor().execute(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ touch(identifier, minModifiedDate);
+ callback.onSuccess(new AsyncTouchResult(identifier));
+ } catch (DataStoreException e) {
+ AsyncTouchResult result = new AsyncTouchResult(
+ identifier);
+ result.setException(e);
+ callback.onFailure(result);
+ }
+ }
+ });
+ } catch (Exception e) {
+ callback.onAbort(new AsyncTouchResult(identifier));
+ throw new DataStoreException("Cannot touch the record "
+ + identifier.toString(), e);
+ } finally {
+ if (contextClassLoader != null) {
+ Thread.currentThread().setContextClassLoader(contextClassLoader);
+ }
+ }
+
+ }
+
+ @Override
+ public void touch(DataIdentifier identifier, long minModifiedDate)
+ throws DataStoreException {
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ final long start = System.currentTimeMillis();
+ final String key = getKeyName(identifier);
+ if (minModifiedDate > 0
+ && minModifiedDate > getLastModified(identifier)) {
+ CopyObjectRequest copReq = new CopyObjectRequest(bucket, key,
+ bucket, key);
+ copReq.setNewObjectMetadata(new ObjectMetadata());
+ Copy copy = tmx.copy(s3ReqDecorator.decorate(copReq));
+ copy.waitForCompletion();
+ LOG.debug("[{}] touched. time taken [{}] ms ", new Object[] {
+ identifier, (System.currentTimeMillis() - start) });
+ } else {
+ LOG.trace("[{}] touch not required. time taken [{}] ms ",
+ new Object[] { identifier,
+ (System.currentTimeMillis() - start) });
+ }
+
+ } catch (Exception e) {
+ throw new DataStoreException("Error occured in touching key ["
+ + identifier.toString() + "]", e);
+ } finally {
+ if (contextClassLoader != null) {
+ Thread.currentThread().setContextClassLoader(contextClassLoader);
+ }
+ }
+ }
+
+ @Override
+ public InputStream read(DataIdentifier identifier)
+ throws DataStoreException {
+ long start = System.currentTimeMillis();
+ String key = getKeyName(identifier);
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ Thread.currentThread().setContextClassLoader(
+ getClass().getClassLoader());
+ S3Object object = s3service.getObject(bucket, key);
+ InputStream in = object.getObjectContent();
+ LOG.debug("[{}] read took [{}]ms", identifier,
+ (System.currentTimeMillis() - start));
+ return in;
+ } catch (AmazonServiceException e) {
+ throw new DataStoreException("Object not found: " + key, e);
+ } finally {
+ if (contextClassLoader != null) {
+ Thread.currentThread().setContextClassLoader(contextClassLoader);
+ }
+ }
+ }
+
+ @Override
+ public Iterator getAllIdentifiers()
+ throws DataStoreException {
+ long start = System.currentTimeMillis();
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ Thread.currentThread().setContextClassLoader(
+ getClass().getClassLoader());
+ Set ids = new HashSet();
+ ObjectListing prevObjectListing = s3service.listObjects(bucket);
+ while (true) {
+ for (S3ObjectSummary s3ObjSumm : prevObjectListing.getObjectSummaries()) {
+ String id = getIdentifierName(s3ObjSumm.getKey());
+ if (id != null) {
+ ids.add(new DataIdentifier(id));
+ }
+ }
+ if (!prevObjectListing.isTruncated()) break;
+ prevObjectListing = s3service.listNextBatchOfObjects(prevObjectListing);
+ }
+ LOG.debug("getAllIdentifiers returned size [{}] took [{}] ms.",
+ ids.size(), (System.currentTimeMillis() - start));
+ return ids.iterator();
+ } catch (AmazonServiceException e) {
+ throw new DataStoreException("Could not list objects", e);
+ } finally {
+ if (contextClassLoader != null) {
+ Thread.currentThread().setContextClassLoader(contextClassLoader);
+ }
+ }
+ }
+
+ @Override
+ public long getLastModified(DataIdentifier identifier)
+ throws DataStoreException {
+ long start = System.currentTimeMillis();
+ String key = getKeyName(identifier);
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ Thread.currentThread().setContextClassLoader(
+ getClass().getClassLoader());
+ ObjectMetadata object = s3service.getObjectMetadata(bucket, key);
+ long lastModified = object.getLastModified().getTime();
+ LOG.debug(
+ "Identifier [{}]'s lastModified = [{}] took [{}]ms.",
+ new Object[] { identifier, lastModified,
+ (System.currentTimeMillis() - start) });
+ return lastModified;
+ } catch (AmazonServiceException e) {
+ if (e.getStatusCode() == 404 || e.getStatusCode() == 403) {
+ LOG.info(
+ "getLastModified:Identifier [{}] not found. Took [{}] ms.",
+ identifier, (System.currentTimeMillis() - start));
+ }
+ throw new DataStoreException(e);
+ } finally {
+ if (contextClassLoader != null) {
+ Thread.currentThread().setContextClassLoader(contextClassLoader);
+ }
+ }
+ }
+
+ @Override
+ public long getLength(DataIdentifier identifier) throws DataStoreException {
+ long start = System.currentTimeMillis();
+ String key = getKeyName(identifier);
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ Thread.currentThread().setContextClassLoader(
+ getClass().getClassLoader());
+ ObjectMetadata object = s3service.getObjectMetadata(bucket, key);
+ long length = object.getContentLength();
+ LOG.debug("Identifier [{}]'s length = [{}] took [{}]ms.",
+ new Object[] { identifier, length,
+ (System.currentTimeMillis() - start) });
+ return length;
+ } catch (AmazonServiceException e) {
+ throw new DataStoreException("Could not length of dataIdentifier "
+ + identifier, e);
+ } finally {
+ if (contextClassLoader != null) {
+ Thread.currentThread().setContextClassLoader(contextClassLoader);
+ }
+ }
+ }
+
+ @Override
+ public void deleteRecord(DataIdentifier identifier)
+ throws DataStoreException {
+ long start = System.currentTimeMillis();
+ String key = getKeyName(identifier);
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ Thread.currentThread().setContextClassLoader(
+ getClass().getClassLoader());
+ s3service.deleteObject(bucket, key);
+ LOG.debug("Identifier [{}] deleted. It took [{}]ms.", new Object[] {
+ identifier, (System.currentTimeMillis() - start) });
+ } catch (AmazonServiceException e) {
+ throw new DataStoreException(
+ "Could not getLastModified of dataIdentifier " + identifier, e);
+ } finally {
+ if (contextClassLoader != null) {
+ Thread.currentThread().setContextClassLoader(contextClassLoader);
+ }
+ }
+ }
+
+ @Override
+ public Set deleteAllOlderThan(long min)
+ throws DataStoreException {
+ long start = System.currentTimeMillis();
+ // S3 stores lastModified to lower boundary of timestamp in ms.
+ // and hence min is reduced by 1000ms.
+ min = min - 1000;
+ Set deleteIdSet = new HashSet(30);
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ Thread.currentThread().setContextClassLoader(
+ getClass().getClassLoader());
+ ObjectListing prevObjectListing = s3service.listObjects(bucket);
+ while (true) {
+ List deleteList = new ArrayList();
+ for (S3ObjectSummary s3ObjSumm : prevObjectListing.getObjectSummaries()) {
+ DataIdentifier identifier = new DataIdentifier(
+ getIdentifierName(s3ObjSumm.getKey()));
+ long lastModified = s3ObjSumm.getLastModified().getTime();
+ LOG.debug("Identifier [{}]'s lastModified = [{}]", identifier, lastModified);
+ if (lastModified < min
+ && getDataStore().confirmDelete(identifier)
+ // confirm once more that record's lastModified < min
+ // order is important here
+ && s3service.getObjectMetadata(bucket,
+ s3ObjSumm.getKey()).getLastModified().getTime() < min) {
+
+ getDataStore().deleteFromCache(identifier);
+ LOG.debug("add id [{}] to delete lists",
+ s3ObjSumm.getKey());
+ deleteList.add(new DeleteObjectsRequest.KeyVersion(
+ s3ObjSumm.getKey()));
+ deleteIdSet.add(identifier);
+ }
+ }
+ if (deleteList.size() > 0) {
+ DeleteObjectsRequest delObjsReq = new DeleteObjectsRequest(
+ bucket);
+ delObjsReq.setKeys(deleteList);
+ DeleteObjectsResult dobjs = s3service.deleteObjects(delObjsReq);
+ if (dobjs.getDeletedObjects().size() != deleteList.size()) {
+ throw new DataStoreException(
+ "Incomplete delete object request. only "
+ + dobjs.getDeletedObjects().size() + " out of "
+ + deleteList.size() + " are deleted");
+ } else {
+ LOG.debug("[{}] records deleted from datastore",
+ deleteList);
+ }
+ }
+ if (!prevObjectListing.isTruncated()) {
+ break;
+ }
+ prevObjectListing = s3service.listNextBatchOfObjects(prevObjectListing);
+ }
+ } finally {
+ if (contextClassLoader != null) {
+ Thread.currentThread().setContextClassLoader(contextClassLoader);
+ }
+ }
+ LOG.info(
+ "deleteAllOlderThan: min=[{}] exit. Deleted[{}] records. Number of records deleted [{}] took [{}]ms",
+ new Object[] { min, deleteIdSet, deleteIdSet.size(),
+ (System.currentTimeMillis() - start) });
+ return deleteIdSet;
+ }
+
+ @Override
+ public void close() throws DataStoreException {
+ super.close();
+ // backend is closing. abort all mulitpart uploads from start.
+ if(s3service.doesBucketExist(bucket)) {
+ tmx.abortMultipartUploads(bucket, startTime);
+ }
+ tmx.shutdownNow();
+ s3service.shutdown();
+ LOG.info("S3Backend closed.");
+ }
+
+ public String getBucket() {
+ return bucket;
+ }
+
+ public void setBucket(String bucket) {
+ this.bucket = bucket;
+ }
+
+ /**
+ * Properties used to configure the backend. If provided explicitly
+ * before init is invoked then these take precedence
+ *
+ * @param properties to configure S3Backend
+ */
+ public void setProperties(Properties properties) {
+ this.properties = properties;
+ }
+
+ private void write(DataIdentifier identifier, File file,
+ boolean asyncUpload, AsyncUploadCallback callback)
+ throws DataStoreException {
+ String key = getKeyName(identifier);
+ ObjectMetadata objectMetaData = null;
+ long start = System.currentTimeMillis();
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ Thread.currentThread().setContextClassLoader(
+ getClass().getClassLoader());
+ // check if the same record already exists
+ try {
+ objectMetaData = s3service.getObjectMetadata(bucket, key);
+ } catch (AmazonServiceException ase) {
+ if (!(ase.getStatusCode() == 404 || ase.getStatusCode() == 403)) {
+ throw ase;
+ }
+ }
+ if (objectMetaData != null) {
+ long l = objectMetaData.getContentLength();
+ if (l != file.length()) {
+ throw new DataStoreException("Collision: " + key
+ + " new length: " + file.length() + " old length: " + l);
+ }
+ LOG.debug("[{}]'s exists, lastmodified = [{}]", key,
+ objectMetaData.getLastModified().getTime());
+ CopyObjectRequest copReq = new CopyObjectRequest(bucket, key,
+ bucket, key);
+ copReq.setNewObjectMetadata(objectMetaData);
+ Copy copy = tmx.copy(s3ReqDecorator.decorate(copReq));
+ try {
+ copy.waitForCopyResult();
+ LOG.debug("lastModified of [{}] updated successfully.", identifier);
+ if (callback != null) {
+ callback.onSuccess(new AsyncUploadResult(identifier, file));
+ }
+ }catch (Exception e2) {
+ AsyncUploadResult asyncUpRes= new AsyncUploadResult(identifier, file);
+ asyncUpRes.setException(e2);
+ if (callback != null) {
+ callback.onAbort(asyncUpRes);
+ }
+ throw new DataStoreException("Could not upload " + key, e2);
+ }
+ }
+
+ if (objectMetaData == null) {
+ try {
+ // start multipart parallel upload using amazon sdk
+ Upload up = tmx.upload(s3ReqDecorator.decorate(new PutObjectRequest(
+ bucket, key, file)));
+ // wait for upload to finish
+ if (asyncUpload) {
+ up.addProgressListener(new S3UploadProgressListener(up,
+ identifier, file, callback));
+ LOG.debug(
+ "added upload progress listener to identifier [{}]",
+ identifier);
+ } else {
+ up.waitForUploadResult();
+ LOG.debug("synchronous upload to identifier [{}] completed.", identifier);
+ if (callback != null) {
+ callback.onSuccess(new AsyncUploadResult(
+ identifier, file));
+ }
+ }
+ } catch (Exception e2 ) {
+ AsyncUploadResult asyncUpRes= new AsyncUploadResult(identifier, file);
+ asyncUpRes.setException(e2);
+ if (callback != null) {
+ callback.onAbort(asyncUpRes);
+ }
+ throw new DataStoreException("Could not upload " + key, e2);
+ }
+ }
+ } finally {
+ if (contextClassLoader != null) {
+ Thread.currentThread().setContextClassLoader(contextClassLoader);
+ }
+ }
+ LOG.debug(
+ "write of [{}], length=[{}], in async mode [{}], in [{}]ms",
+ new Object[] { identifier, file.length(), asyncUpload,
+ (System.currentTimeMillis() - start) });
+ }
+
+ /**
+ * This method rename object keys in S3 concurrently. The number of
+ * concurrent threads is defined by 'maxConnections' property in
+ * aws.properties. As S3 doesn't have "move" command, this method simulate
+ * move as copy object object to new key and then delete older key.
+ */
+ private void renameKeys() throws DataStoreException {
+ long startTime = System.currentTimeMillis();
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ long count = 0;
+ try {
+ Thread.currentThread().setContextClassLoader(
+ getClass().getClassLoader());
+ ObjectListing prevObjectListing = s3service.listObjects(bucket);
+ List deleteList = new ArrayList();
+ int nThreads = Integer.parseInt(properties.getProperty("maxConnections"));
+ ExecutorService executor = Executors.newFixedThreadPool(nThreads,
+ new NamedThreadFactory("s3-object-rename-worker"));
+ boolean taskAdded = false;
+ while (true) {
+ for (S3ObjectSummary s3ObjSumm : prevObjectListing.getObjectSummaries()) {
+ executor.execute(new KeyRenameThread(s3ObjSumm.getKey()));
+ taskAdded = true;
+ count++;
+ // delete the object if it follows old key name format
+ if( s3ObjSumm.getKey().startsWith(KEY_PREFIX)) {
+ deleteList.add(new DeleteObjectsRequest.KeyVersion(
+ s3ObjSumm.getKey()));
+ }
+ }
+ if (!prevObjectListing.isTruncated()) break;
+ prevObjectListing = s3service.listNextBatchOfObjects(prevObjectListing);
+ }
+ // This will make the executor accept no new threads
+ // and finish all existing threads in the queue
+ executor.shutdown();
+
+ try {
+ // Wait until all threads are finish
+ while (taskAdded
+ && !executor.awaitTermination(10, TimeUnit.SECONDS)) {
+ LOG.info("Rename S3 keys tasks timedout. Waiting again");
+ }
+ } catch (InterruptedException ie) {
+
+ }
+ LOG.info("Renamed [{}] keys, time taken [{}]sec", count,
+ ((System.currentTimeMillis() - startTime) / 1000));
+ // Delete older keys.
+ if (deleteList.size() > 0) {
+ DeleteObjectsRequest delObjsReq = new DeleteObjectsRequest(
+ bucket);
+ int batchSize = 500, startIndex = 0, size = deleteList.size();
+ int endIndex = batchSize < size ? batchSize : size;
+ while (endIndex <= size) {
+ delObjsReq.setKeys(Collections.unmodifiableList(deleteList.subList(
+ startIndex, endIndex)));
+ DeleteObjectsResult dobjs = s3service.deleteObjects(delObjsReq);
+ LOG.info(
+ "Records[{}] deleted in datastore from index [{}] to [{}]",
+ new Object[] { dobjs.getDeletedObjects().size(),
+ startIndex, (endIndex - 1) });
+ if (endIndex == size) {
+ break;
+ } else {
+ startIndex = endIndex;
+ endIndex = (startIndex + batchSize) < size
+ ? (startIndex + batchSize)
+ : size;
+ }
+ }
+ }
+ } finally {
+ if (contextClassLoader != null) {
+ Thread.currentThread().setContextClassLoader(contextClassLoader);
+ }
+ }
+ }
+
+ /**
+ * The method convert old key format to new format. For e.g. this method
+ * converts old key dataStore_004cb70c8f87d78f04da41e7547cb434094089ea to
+ * 004c-b70c8f87d78f04da41e7547cb434094089ea.
+ */
+ private static String convertKey(String oldKey)
+ throws IllegalArgumentException {
+ if (!oldKey.startsWith(KEY_PREFIX)) {
+ return oldKey;
+ }
+ String key = oldKey.substring(KEY_PREFIX.length());
+ return key.substring(0, 4) + Utils.DASH + key.substring(4);
+ }
+
+ /**
+ * Get key from data identifier. Object is stored with key in S3.
+ */
+ private static String getKeyName(DataIdentifier identifier) {
+ String key = identifier.toString();
+ return key.substring(0, 4) + Utils.DASH + key.substring(4);
+ }
+
+ /**
+ * Get data identifier from key.
+ */
+ private static String getIdentifierName(String key) {
+ if (!key.contains(Utils.DASH)) {
+ return null;
+ }
+ return key.substring(0, 4) + key.substring(5);
+ }
+
+
+ /**
+ * The class renames object key in S3 in a thread.
+ */
+ private class KeyRenameThread implements Runnable {
+
+ private String oldKey;
+
+ public void run() {
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ Thread.currentThread().setContextClassLoader(
+ getClass().getClassLoader());
+ String newS3Key = convertKey(oldKey);
+ CopyObjectRequest copReq = new CopyObjectRequest(bucket,
+ oldKey, bucket, newS3Key);
+ Copy copy = tmx.copy(s3ReqDecorator.decorate(copReq));
+ try {
+ copy.waitForCopyResult();
+ LOG.debug("[{}] renamed to [{}] ", oldKey, newS3Key);
+ } catch (InterruptedException ie) {
+ LOG.error(" Exception in renaming [{}] to [{}] ",
+ new Object[] { ie, oldKey, newS3Key });
+ }
+ } finally {
+ if (contextClassLoader != null) {
+ Thread.currentThread().setContextClassLoader(
+ contextClassLoader);
+ }
+ }
+ }
+
+ public KeyRenameThread(String oldKey) {
+ this.oldKey = oldKey;
+ }
+ }
+
+ /**
+ * Listener which receives callback on status of S3 upload.
+ */
+ private class S3UploadProgressListener implements ProgressListener {
+
+ private File file;
+
+ private DataIdentifier identifier;
+
+ private AsyncUploadCallback callback;
+
+ private Upload upload;
+
+ public S3UploadProgressListener(Upload upload, DataIdentifier identifier, File file,
+ AsyncUploadCallback callback) {
+ super();
+ this.identifier = identifier;
+ this.file = file;
+ this.callback = callback;
+ this.upload = upload;
+ }
+
+ public void progressChanged(ProgressEvent progressEvent) {
+ switch (progressEvent.getEventCode()) {
+ case ProgressEvent.COMPLETED_EVENT_CODE:
+ callback.onSuccess(new AsyncUploadResult(identifier, file));
+ break;
+ case ProgressEvent.FAILED_EVENT_CODE:
+ AsyncUploadResult result = new AsyncUploadResult(
+ identifier, file);
+ try {
+ AmazonClientException e = upload.waitForException();
+ if (e != null) {
+ result.setException(e);
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ callback.onFailure(result);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /**
+ * This class implements {@link Runnable} interface to upload {@link File}
+ * to S3 asynchronously.
+ */
+ private class AsyncUploadJob implements Runnable {
+
+ private DataIdentifier identifier;
+
+ private File file;
+
+ private AsyncUploadCallback callback;
+
+ public AsyncUploadJob(DataIdentifier identifier, File file,
+ AsyncUploadCallback callback) {
+ super();
+ this.identifier = identifier;
+ this.file = file;
+ this.callback = callback;
+ }
+
+ public void run() {
+ try {
+ write(identifier, file, true, callback);
+ } catch (DataStoreException e) {
+ LOG.error("Could not upload [" + identifier + "], file[" + file
+ + "]", e);
+ }
+
+ }
+ }
+}
diff --git a/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/ds/S3DataStore.java b/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/ds/S3DataStore.java
new file mode 100644
index 00000000000..8253572b244
--- /dev/null
+++ b/jackrabbit-aws-ext/src/main/java/org/apache/jackrabbit/aws/ext/ds/S3DataStore.java
@@ -0,0 +1,50 @@
+/*
+ * 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.jackrabbit.aws.ext.ds;
+
+import java.util.Properties;
+
+import org.apache.jackrabbit.core.data.Backend;
+import org.apache.jackrabbit.core.data.CachingDataStore;
+
+/**
+ * An Amazon S3 data store.
+ */
+public class S3DataStore extends CachingDataStore {
+ private Properties properties;
+
+ @Override
+ protected Backend createBackend() {
+ S3Backend backend = new S3Backend();
+ if(properties != null){
+ backend.setProperties(properties);
+ }
+ return backend;
+ }
+
+ @Override
+ protected String getMarkerFile() {
+ return "s3.init.done";
+ }
+
+ /**
+ * Properties required to configure the S3Backend
+ */
+ public void setProperties(Properties properties) {
+ this.properties = properties;
+ }
+}
diff --git a/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/TestAll.java b/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/TestAll.java
new file mode 100644
index 00000000000..fb289ad99c5
--- /dev/null
+++ b/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/TestAll.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.jackrabbit.aws.ext;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.apache.jackrabbit.aws.ext.ds.TestS3Ds;
+import org.apache.jackrabbit.aws.ext.ds.TestS3DSAsyncTouch;
+import org.apache.jackrabbit.aws.ext.ds.TestS3DsCacheOff;
+import org.apache.jackrabbit.aws.ext.ds.TestS3DSWithSSES3;
+import org.apache.jackrabbit.aws.ext.ds.TestS3DSWithSmallCache;
+import org.apache.jackrabbit.core.data.TestCaseBase;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test suite that includes all test cases for the this module.
+ */
+public class TestAll extends TestCase {
+
+ private static final Logger LOG = LoggerFactory.getLogger(TestAll.class);
+
+ /**
+ * TestAll suite that executes all tests inside this module. To
+ * run test cases against Amazon S3 pass AWS configuration properties file as
+ * system property -Dconfig=/opt/cq/aws.properties. Sample aws properties
+ * located at src/test/resources/aws.properties.
+ */
+ public static Test suite() {
+ TestSuite suite = new TestSuite("S3 tests");
+ String config = System.getProperty(TestCaseBase.CONFIG);
+ LOG.info("config= " + config);
+ if (config != null && !"".equals(config.trim())) {
+ suite.addTestSuite(TestS3Ds.class);
+ suite.addTestSuite(TestS3DSAsyncTouch.class);
+ suite.addTestSuite(TestS3DSWithSmallCache.class);
+ suite.addTestSuite(TestS3DsCacheOff.class);
+ suite.addTestSuite(TestS3DSWithSSES3.class);
+ }
+ return suite;
+ }
+}
diff --git a/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/S3TestDataStore.java b/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/S3TestDataStore.java
new file mode 100644
index 00000000000..33dbba4d0ec
--- /dev/null
+++ b/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/S3TestDataStore.java
@@ -0,0 +1,47 @@
+/*
+ * 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.jackrabbit.aws.ext.ds;
+
+import java.util.Properties;
+
+import org.apache.jackrabbit.core.data.Backend;
+
+/**
+ * This class intialize {@link S3DataStore} with the give bucket. The other
+ * configuration are taken from configuration file. This class is implemented so
+ * that each test case run in its own bucket. It was required as deletions in
+ * bucket are not immediately reflected in the next test case.
+ */
+public class S3TestDataStore extends S3DataStore {
+
+ Properties props;
+
+ public S3TestDataStore() {
+ super();
+ }
+
+ public S3TestDataStore(Properties props) {
+ super();
+ this.props = props;
+ }
+
+ protected Backend createBackend() {
+ Backend backend = new S3Backend();
+ ((S3Backend) backend).setProperties(props);
+ return backend;
+ }
+}
diff --git a/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3DSAsyncTouch.java b/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3DSAsyncTouch.java
new file mode 100644
index 00000000000..910d4229b4f
--- /dev/null
+++ b/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3DSAsyncTouch.java
@@ -0,0 +1,53 @@
+/*
+ * 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.jackrabbit.aws.ext.ds;
+
+import java.io.IOException;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.data.CachingDataStore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test {@link CachingDataStore} with
+ * {@link CachingDataStore#setTouchAsync(boolean) set to true. It requires to
+ * pass aws config file via system property. For e.g.
+ * -Dconfig=/opt/cq/aws.properties. Sample aws properties located at
+ * src/test/resources/aws.properties
+ */
+public class TestS3DSAsyncTouch extends TestS3Ds {
+
+ protected static final Logger LOG = LoggerFactory.getLogger(TestS3DSAsyncTouch.class);
+
+ public TestS3DSAsyncTouch() throws IOException {
+
+ }
+
+ @Override
+ protected CachingDataStore createDataStore() throws RepositoryException {
+ S3DataStore s3ds = new S3DataStore();
+ s3ds.setProperties(props);
+ s3ds.setTouchAsync(true);
+ s3ds.setSecret("123456");
+ s3ds.init(dataStoreDir);
+ s3ds.updateModifiedDateOnAccess(System.currentTimeMillis() + 50 * 1000);
+ sleep(1000);
+ return s3ds;
+ }
+}
diff --git a/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3DSWithSSES3.java b/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3DSWithSSES3.java
new file mode 100644
index 00000000000..45a29482494
--- /dev/null
+++ b/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3DSWithSSES3.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.jackrabbit.aws.ext.ds;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.aws.ext.S3Constants;
+import org.apache.jackrabbit.core.data.CachingDataStore;
+import org.apache.jackrabbit.core.data.DataRecord;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test S3DataStore operation with SSE_S3 encryption.
+ */
+public class TestS3DSWithSSES3 extends TestS3Ds {
+
+ protected static final Logger LOG = LoggerFactory.getLogger(TestS3DSWithSSES3.class);
+
+ public TestS3DSWithSSES3() throws IOException {
+ }
+
+ @Override
+ protected CachingDataStore createDataStore() throws RepositoryException {
+ props.setProperty(S3Constants.S3_ENCRYPTION,
+ S3Constants.S3_ENCRYPTION_SSE_S3);
+ S3DataStore s3ds = new S3DataStore();
+ s3ds.setProperties(props);
+ s3ds.setSecret("123456");
+ s3ds.init(dataStoreDir);
+ sleep(1000);
+ return s3ds;
+ }
+
+ /**
+ * Test data migration enabling SSE_S3 encryption.
+ */
+ public void testDataMigration() {
+ try {
+ String bucket = props.getProperty(S3Constants.S3_BUCKET);
+ S3DataStore s3ds = new S3DataStore();
+ s3ds.setProperties(props);
+ s3ds.setCacheSize(0);
+ s3ds.init(dataStoreDir);
+ byte[] data = new byte[dataLength];
+ randomGen.nextBytes(data);
+ DataRecord rec = s3ds.addRecord(new ByteArrayInputStream(data));
+ assertEquals(data.length, rec.getLength());
+ assertRecord(data, rec);
+ s3ds.close();
+
+ // turn encryption now.
+ props.setProperty(S3Constants.S3_BUCKET, bucket);
+ props.setProperty(S3Constants.S3_ENCRYPTION,
+ S3Constants.S3_ENCRYPTION_SSE_S3);
+ props.setProperty(S3Constants.S3_RENAME_KEYS, "true");
+ s3ds = new S3DataStore();
+ s3ds.setProperties(props);
+ s3ds.setCacheSize(0);
+ s3ds.init(dataStoreDir);
+
+ rec = s3ds.getRecord(rec.getIdentifier());
+ assertEquals(data.length, rec.getLength());
+ assertRecord(data, rec);
+
+ randomGen.nextBytes(data);
+ rec = s3ds.addRecord(new ByteArrayInputStream(data));
+ s3ds.close();
+
+ } catch (Exception e) {
+ LOG.error("error:", e);
+ fail(e.getMessage());
+ }
+ }
+
+}
diff --git a/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3DSWithSmallCache.java b/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3DSWithSmallCache.java
new file mode 100644
index 00000000000..b63bf67f025
--- /dev/null
+++ b/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3DSWithSmallCache.java
@@ -0,0 +1,53 @@
+/*
+ * 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.jackrabbit.aws.ext.ds;
+
+import java.io.IOException;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.data.CachingDataStore;
+import org.apache.jackrabbit.core.data.LocalCache;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test {@link CachingDataStore} with S3Backend and with very small size (@link
+ * {@link LocalCache}. It requires to pass aws config file via system property.
+ * For e.g. -Dconfig=/opt/cq/aws.properties. Sample aws properties located at
+ * src/test/resources/aws.properties
+ */
+public class TestS3DSWithSmallCache extends TestS3Ds {
+
+ protected static final Logger LOG = LoggerFactory.getLogger(TestS3DSWithSmallCache.class);
+
+ public TestS3DSWithSmallCache() throws IOException {
+ }
+
+ @Override
+ protected CachingDataStore createDataStore() throws RepositoryException {
+ S3DataStore s3ds = new S3DataStore();
+ s3ds.setProperties(props);
+ s3ds.setCacheSize(dataLength * 10);
+ s3ds.setCachePurgeTrigFactor(0.5d);
+ s3ds.setCachePurgeResizeFactor(0.4d);
+ s3ds.setSecret("123456");
+ s3ds.init(dataStoreDir);
+ sleep(1000);
+ return s3ds;
+ }
+}
diff --git a/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3Ds.java b/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3Ds.java
new file mode 100644
index 00000000000..36c256cddda
--- /dev/null
+++ b/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3Ds.java
@@ -0,0 +1,144 @@
+/*
+ * 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.jackrabbit.aws.ext.ds;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Properties;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.aws.ext.S3Constants;
+import org.apache.jackrabbit.aws.ext.Utils;
+import org.apache.jackrabbit.core.data.Backend;
+import org.apache.jackrabbit.core.data.CachingDataStore;
+import org.apache.jackrabbit.core.data.TestCaseBase;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.amazonaws.services.s3.AmazonS3Client;
+import com.amazonaws.services.s3.model.DeleteObjectsRequest;
+import com.amazonaws.services.s3.model.ObjectListing;
+import com.amazonaws.services.s3.model.S3ObjectSummary;
+import com.amazonaws.services.s3.transfer.TransferManager;
+
+/**
+ * Test {@link CachingDataStore} with S3Backend and local cache on. It requires
+ * to pass aws config file via system property. For e.g.
+ * -Dconfig=/opt/cq/aws.properties. Sample aws properties located at
+ * src/test/resources/aws.properties
+ */
+public class TestS3Ds extends TestCaseBase {
+
+ protected static final Logger LOG = LoggerFactory.getLogger(TestS3Ds.class);
+
+ private Date startTime = null;
+
+ protected Properties props;
+
+ protected String config;
+
+ public TestS3Ds() throws IOException {
+ System.setProperty(
+ TestCaseBase.CONFIG,
+ "C:/src/apache/jackrabbit-encryp-changes/jackrabbit/jackrabbit-aws-ext/src/test/resources/aws.properties");
+ config = System.getProperty(CONFIG);
+ props = Utils.readConfig(System.getProperty(CONFIG));
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ startTime = new Date();
+ super.setUp();
+ String bucket = String.valueOf(randomGen.nextInt(9999)) + "-"
+ + String.valueOf(randomGen.nextInt(9999)) + "-test";
+ props.setProperty(S3Constants.S3_BUCKET, bucket);
+ // delete bucket if exists
+ deleteBucket(bucket);
+ }
+
+ @Override
+ protected void tearDown() {
+ try {
+ deleteBucket();
+ super.tearDown();
+ } catch (Exception ignore) {
+
+ }
+ }
+
+ @Override
+ protected CachingDataStore createDataStore() throws RepositoryException {
+ S3DataStore s3ds = new S3DataStore();
+ s3ds.setProperties(props);
+ s3ds.setSecret("123456");
+ s3ds.init(dataStoreDir);
+ sleep(1000);
+ return s3ds;
+ }
+
+ /**
+ * Cleaning of bucket after test run.
+ */
+ /**
+ * Cleaning of bucket after test run.
+ */
+ public void deleteBucket() throws Exception {
+ Backend backend = ((S3DataStore) ds).getBackend();
+ String bucket = ((S3Backend) backend).getBucket();
+ deleteBucket(bucket);
+ }
+
+ public void deleteBucket(String bucket) throws Exception {
+ LOG.info("deleting bucket [" + bucket + "]");
+ Properties props = Utils.readConfig(config);
+ AmazonS3Client s3service = Utils.openService(props);
+ TransferManager tmx = new TransferManager(s3service);
+
+ if (s3service.doesBucketExist(bucket)) {
+ for (int i = 0; i < 4; i++) {
+ tmx.abortMultipartUploads(bucket, startTime);
+ ObjectListing prevObjectListing = s3service.listObjects(bucket);
+ while (prevObjectListing != null) {
+ List deleteList = new ArrayList();
+ for (S3ObjectSummary s3ObjSumm : prevObjectListing.getObjectSummaries()) {
+ deleteList.add(new DeleteObjectsRequest.KeyVersion(
+ s3ObjSumm.getKey()));
+ }
+ if (deleteList.size() > 0) {
+ DeleteObjectsRequest delObjsReq = new DeleteObjectsRequest(
+ bucket);
+ delObjsReq.setKeys(deleteList);
+ s3service.deleteObjects(delObjsReq);
+ }
+ if (!prevObjectListing.isTruncated()) break;
+ prevObjectListing = s3service.listNextBatchOfObjects(prevObjectListing);
+ }
+ }
+ s3service.deleteBucket(bucket);
+ LOG.info("bucket [ " + bucket + "] deleted");
+
+ } else {
+ LOG.info("bucket [" + bucket + "] doesn't exists");
+ }
+ tmx.shutdownNow();
+ s3service.shutdown();
+ }
+
+}
diff --git a/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3DsCacheOff.java b/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3DsCacheOff.java
new file mode 100644
index 00000000000..14896b9da7b
--- /dev/null
+++ b/jackrabbit-aws-ext/src/test/java/org/apache/jackrabbit/aws/ext/ds/TestS3DsCacheOff.java
@@ -0,0 +1,50 @@
+/*
+ * 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.jackrabbit.aws.ext.ds;
+
+import java.io.IOException;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.data.CachingDataStore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test {@link CachingDataStore} with S3Backend and local cache Off. It requires
+ * to pass aws config file via system property. For e.g.
+ * -Dconfig=/opt/cq/aws.properties. Sample aws properties located at
+ * src/test/resources/aws.properties
+ */
+public class TestS3DsCacheOff extends TestS3Ds {
+
+ protected static final Logger LOG = LoggerFactory.getLogger(TestS3DsCacheOff.class);
+
+ public TestS3DsCacheOff() throws IOException {
+ }
+
+ @Override
+ protected CachingDataStore createDataStore() throws RepositoryException {
+ S3DataStore s3ds = new S3DataStore();
+ s3ds.setProperties(props);
+ s3ds.setCacheSize(0);
+ s3ds.setSecret("123456");
+ s3ds.init(dataStoreDir);
+ sleep(1000);
+ return s3ds;
+ }
+}
diff --git a/jackrabbit-aws-ext/src/test/resources/aws.properties b/jackrabbit-aws-ext/src/test/resources/aws.properties
new file mode 100644
index 00000000000..04c752ae027
--- /dev/null
+++ b/jackrabbit-aws-ext/src/test/resources/aws.properties
@@ -0,0 +1,47 @@
+#
+# 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.
+#
+
+# AWS account ID
+accessKey=
+# AWS secret key
+secretKey=
+# AWS bucket name
+s3Bucket=
+# AWS bucket region
+# Mapping of S3 regions to their constants
+# US Standard us-standard
+# US West us-west-2
+# US West (Northern California) us-west-1
+# EU (Ireland) EU
+# Asia Pacific (Singapore) ap-southeast-1
+# Asia Pacific (Sydney) ap-southeast-2
+# Asia Pacific (Tokyo) ap-northeast-1
+# South America (Sao Paulo) sa-east-1
+s3Region=
+# S3 endpoint to be used. This parameter is optional
+# and has a higher precedence over endpoint derived
+# via S3 region.
+s3EndPoint=
+connectionTimeout=120000
+socketTimeout=120000
+maxConnections=20
+maxErrorRetry=10
+# maximum concurrent threads to write to S3.
+writeThreads=10
+# proxy configurations (optional)
+proxyHost=
+proxyPort=
\ No newline at end of file
diff --git a/jackrabbit-aws-ext/src/test/resources/log4j.properties b/jackrabbit-aws-ext/src/test/resources/log4j.properties
new file mode 100644
index 00000000000..ac7c3fc2057
--- /dev/null
+++ b/jackrabbit-aws-ext/src/test/resources/log4j.properties
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+
+# this is the log4j configuration for the JCR API tests
+log4j.rootLogger=INFO, file
+log4j.logger.org.apache.jackrabbit.core.data.CachingDataStore=ERROR
+log4j.logger.org.apache.jackrabbit.aws.ext.ds=INFO
+
+#log4j.logger.org.apache.jackrabbit.test=DEBUG
+
+# 'file' is set to be a FileAppender.
+log4j.appender.file=org.apache.log4j.FileAppender
+log4j.appender.file.File=target/debug.log
+
+# 'file' uses PatternLayout.
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d{dd.MM.yyyy HH:mm:ss} *%-5p* [%t] %c{1}: %m (%F, line %L)\n
diff --git a/jackrabbit-aws-ext/src/test/resources/repository_sample.xml b/jackrabbit-aws-ext/src/test/resources/repository_sample.xml
new file mode 100644
index 00000000000..40a00ea064a
--- /dev/null
+++ b/jackrabbit-aws-ext/src/test/resources/repository_sample.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jackrabbit-bundle/pom.xml b/jackrabbit-bundle/pom.xml
new file mode 100644
index 00000000000..b3e80cb253b
--- /dev/null
+++ b/jackrabbit-bundle/pom.xml
@@ -0,0 +1,135 @@
+
+
+
+
+
+ 4.0.0
+
+
+
+
+
+ org.apache.jackrabbit
+ jackrabbit-parent
+ 2.13.5-SNAPSHOT
+ ../jackrabbit-parent/pom.xml
+
+ jackrabbit-bundle
+ bundle
+ Jackrabbit OSGi bundle
+ OSGi bundle of Apache Jackrabbit
+
+
+
+
+ org.apache.felix
+ maven-bundle-plugin
+ true
+
+
+ *;groupId=!org.osgi|javax.jcr
+ true
+
+ org.apache.jackrabbit.api.*;version=${project.version}
+
+
+
+ org.apache.jackrabbit.test;resolution:=optional,
+
+ javax.servlet;resolution:=optional,
+ javax.servlet.http;resolution:=optional,
+
+ org.apache.xpath;resolution:=optional,
+ org.apache.xpath.objects;resolution:=optional,
+ org.apache.xml.utils;resolution:=optional,
+ org.apache.xalan.serialize;resolution:=optional,
+ org.apache.xalan.templates;resolution:=optional,
+ org.apache.derby.impl.drda;resolution:=optional,
+ *
+
+
+ org.apache.jackrabbit.bundle.Activator
+
+
+
+
+
+
+
+
+
+ org.osgi
+ org.osgi.core
+ 4.0.0
+ provided
+
+
+ org.osgi
+ org.osgi.compendium
+ 4.0.0
+ provided
+
+
+ javax.jcr
+ jcr
+ provided
+
+
+
+ org.apache.jackrabbit
+ jackrabbit-core
+ ${project.version}
+ provided
+
+
+ javax.jcr
+ jcr
+
+
+ org.slf4j
+ slf4j-api
+
+
+ org.slf4j
+ jcl-over-slf4j
+
+
+
+
+ org.apache.jackrabbit
+ jackrabbit-jcr2dav
+ ${project.version}
+ provided
+
+
+ javax.jcr
+ jcr
+
+
+ org.slf4j
+ slf4j-api
+
+
+ org.slf4j
+ jcl-over-slf4j
+
+
+
+
+
+
diff --git a/jackrabbit-bundle/src/main/java/org/apache/jackrabbit/bundle/Activator.java b/jackrabbit-bundle/src/main/java/org/apache/jackrabbit/bundle/Activator.java
new file mode 100644
index 00000000000..f9f358aba3b
--- /dev/null
+++ b/jackrabbit-bundle/src/main/java/org/apache/jackrabbit/bundle/Activator.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.jackrabbit.bundle;
+
+import java.io.File;
+import java.util.Hashtable;
+
+import javax.jcr.Repository;
+
+import org.apache.jackrabbit.core.RepositoryImpl;
+import org.apache.jackrabbit.core.config.RepositoryConfig;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class Activator implements BundleActivator {
+
+ private volatile RepositoryImpl repository;
+
+ private volatile ServiceRegistration registration;
+
+ public void start(BundleContext context) throws Exception {
+ repository = RepositoryImpl.create(
+ RepositoryConfig.install(new File("jackrabbit")));
+
+ Hashtable properties = new Hashtable();
+ for (String key : repository.getDescriptorKeys()) {
+ String descriptor = repository.getDescriptor(key);
+ if (descriptor != null) {
+ properties.put(key, descriptor);
+ }
+ }
+ registration = context.registerService(
+ Repository.class.getName(), repository, properties);
+ }
+
+ public void stop(BundleContext context) throws Exception {
+ registration.unregister();
+
+ repository.shutdown();
+ }
+
+}
diff --git a/jackrabbit-bundle/src/main/resources/OSGI-INF/jackrabbit-repository-factory.xml b/jackrabbit-bundle/src/main/resources/OSGI-INF/jackrabbit-repository-factory.xml
new file mode 100644
index 00000000000..8c9efb48a58
--- /dev/null
+++ b/jackrabbit-bundle/src/main/resources/OSGI-INF/jackrabbit-repository-factory.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
diff --git a/jackrabbit-core/HEADER.txt b/jackrabbit-core/HEADER.txt
new file mode 100644
index 00000000000..ae6f28c4a1c
--- /dev/null
+++ b/jackrabbit-core/HEADER.txt
@@ -0,0 +1,16 @@
+/*
+ * 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.
+ */
diff --git a/jackrabbit-core/README.txt b/jackrabbit-core/README.txt
new file mode 100644
index 00000000000..21c486f43e5
--- /dev/null
+++ b/jackrabbit-core/README.txt
@@ -0,0 +1,7 @@
+==========================
+Welcome to Jackrabbit Core
+==========================
+
+This is the Core component of the Apache Jackrabbit project.
+This component contains the core of the fully JSR-170 compliant
+Apache Jackrabbit content repository implementation.
diff --git a/jackrabbit-core/checkstyle-suppressions.xml b/jackrabbit-core/checkstyle-suppressions.xml
new file mode 100644
index 00000000000..c0f0ab1833f
--- /dev/null
+++ b/jackrabbit-core/checkstyle-suppressions.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jackrabbit-core/checkstyle.xml b/jackrabbit-core/checkstyle.xml
new file mode 100644
index 00000000000..df1aedb4a14
--- /dev/null
+++ b/jackrabbit-core/checkstyle.xml
@@ -0,0 +1,175 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jackrabbit-core/jdepend.properties b/jackrabbit-core/jdepend.properties
new file mode 100644
index 00000000000..b7e12a58b41
--- /dev/null
+++ b/jackrabbit-core/jdepend.properties
@@ -0,0 +1,20 @@
+# 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.
+ignore.java=java.*,javax.*,org.w3c.*,org.xml.*
+ignore.sun=sun.*,com.sun.*
+ignore.jackrabbit=org.apache.jackrabbit.util
+ignore.slf4j=org.slf4j
+ignore.commons=org.apache.commons
+ignore.concurrent=EDU.*
diff --git a/jackrabbit-core/pom.xml b/jackrabbit-core/pom.xml
new file mode 100644
index 00000000000..9db8c8e1e90
--- /dev/null
+++ b/jackrabbit-core/pom.xml
@@ -0,0 +1,582 @@
+
+
+
+
+
+ 4.0.0
+
+
+
+
+
+ org.apache.jackrabbit
+ jackrabbit-parent
+ 2.13.5-SNAPSHOT
+ ../jackrabbit-parent/pom.xml
+
+ jackrabbit-core
+ Jackrabbit Core
+ Jackrabbit content repository implementation
+
+
+ false
+
+
+
+
+
+ maven-antrun-plugin
+
+
+ process-test-resources
+ process-test-resources
+
+
+
+
+
+
+
+
+
+
+
+ run
+
+
+
+
+
+ ant
+ ant-optional
+ 1.5.3-1
+
+
+
+
+ maven-surefire-plugin
+
+
+ **/*TestAll.java
+
+ -Xmx512m
+
+
+ java.awt.headless
+ true
+
+
+ derby.system.durability
+ test
+
+
+ derby.storage.fileSyncTransactionLog
+ true
+
+
+ derby.stream.error.file
+ target/derby.log
+
+
+ org.apache.jackrabbit.repository.home
+ target/repository-factory-test
+
+
+ known.issues
+
+org.apache.jackrabbit.core.ConcurrentImportTest
+org.apache.jackrabbit.core.xml.DocumentViewTest#testMultiValue
+org.apache.jackrabbit.core.NodeImplTest#testReferentialIntegrityCorruptionGetPath
+org.apache.jackrabbit.core.integration.ConcurrentQueryTest#testConcurrentQueryWithDeletes
+org.apache.jackrabbit.test.api.ShareableNodeTest#testGetName
+org.apache.jackrabbit.test.api.ShareableNodeTest#testGetNode
+org.apache.jackrabbit.test.api.ShareableNodeTest#testGetNodes
+org.apache.jackrabbit.test.api.ShareableNodeTest#testGetNodesByPattern
+org.apache.jackrabbit.test.api.ShareableNodeTest#testMoveShareableNode
+org.apache.jackrabbit.test.api.ShareableNodeTest#testTransientMoveShareableNode
+org.apache.jackrabbit.test.api.lock.OpenScopedLockTest#testLockExpiration
+org.apache.jackrabbit.test.api.lock.SessionScopedLockTest#testLockExpiration
+org.apache.jackrabbit.test.api.observation.NodeReorderTest#testNodeReorderMove
+org.apache.jackrabbit.core.data.ConcurrentGcTest#testDatabases
+org.apache.jackrabbit.core.data.GarbageCollectorTest#testCloseSessionWhileRunningGc
+org.apache.jackrabbit.core.ReplacePropertyWhileOthersReadTest
+org.apache.jackrabbit.core.security.user.MembershipCachePerfTest
+org.apache.jackrabbit.test.api.query.qom.NodeLocalNameTest#testStringLiteralInvalidName
+org.apache.jackrabbit.test.api.query.qom.NodeLocalNameTest#testPathLiteral
+org.apache.jackrabbit.test.api.query.qom.NodeLocalNameTest#testURILiteral
+
+
+
+ org.apache.jackrabbit.test.integration
+ ${org.apache.jackrabbit.test.integration}
+
+
+
+
+
+ do_test
+ integration-test
+
+
+ **/integration/*Test.java
+
+
+
+ test
+
+
+
+
+
+ org.apache.rat
+ apache-rat-plugin
+
+
+ src/main/javadoc/**/*.uxf
+ src/test/repository/**
+ src/test/resources/**/*.txt
+ src/test/resources/**/*.rtf
+ src/test/resources/**/*.cnd
+ src/test/compatibility/**/target/**
+ src/test/compatibility/**/.*/**
+ src/test/compatibility/repositories.zip
+ repository/**
+ *.log
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 2.4
+
+
+ logback-test.xml
+
+
+
+
+
+ test-jar
+
+
+
+
+
+
+
+ src/main/resources
+
+
+ src/main/resources-filtered
+ true
+
+
+
+
+
+
+ org.eclipse.m2e
+ lifecycle-mapping
+ 1.0.0
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-antrun-plugin
+ [1.6,)
+
+ run
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ concurrent
+ concurrent
+
+
+ commons-collections
+ commons-collections
+
+
+ commons-io
+ commons-io
+
+
+ commons-dbcp
+ commons-dbcp
+ 1.3
+
+
+ javax.jcr
+ jcr
+
+
+ org.apache.jackrabbit
+ jackrabbit-api
+ ${project.version}
+
+
+ org.apache.jackrabbit
+ jackrabbit-jcr-commons
+ ${project.version}
+
+
+ org.apache.jackrabbit
+ jackrabbit-data
+ ${project.version}
+
+
+ org.apache.jackrabbit
+ jackrabbit-data
+ ${project.version}
+ test-jar
+ test
+
+
+ org.apache.jackrabbit
+ jackrabbit-spi-commons
+ ${project.version}
+
+
+ org.apache.jackrabbit
+ jackrabbit-spi
+ ${project.version}
+
+
+
+ org.apache.jackrabbit
+ jackrabbit-spi
+ ${project.version}
+ tests
+ test
+
+
+ org.apache.tika
+ tika-core
+
+
+ org.slf4j
+ slf4j-api
+
+
+ org.apache.lucene
+ lucene-core
+
+
+ org.apache.derby
+ derby
+
+
+ org.apache.jackrabbit
+ jackrabbit-jcr-tests
+ ${project.version}
+ true
+
+
+ junit
+ junit
+ test
+
+
+ org.apache.jackrabbit
+ jackrabbit-jcr-benchmark
+ test
+
+
+ org.apache.tika
+ tika-parsers
+ test
+
+
+ commons-logging
+ commons-logging
+
+
+
+
+ org.slf4j
+ jcl-over-slf4j
+
+
+ ch.qos.logback
+ logback-classic
+ test
+
+
+ org.apache.geronimo.specs
+ geronimo-jta_1.0.1B_spec
+ test
+
+
+ com.h2database
+ h2
+ 1.3.149
+ test
+
+
+ org.mockito
+ mockito-core
+ 1.10.19
+ test
+
+
+
+
+
+ integrationTesting
+
+ true
+
+
+
+
+ mysql
+
+ jackrabbit
+ org.apache.jackrabbit.core.fs.db.DbFileSystem
+ org.apache.jackrabbit.core.data.db.DbDataStore
+ org.apache.jackrabbit.core.persistence.pool.MySqlPersistenceManager
+ org.apache.jackrabbit.core.journal.DatabaseJournal
+ mysql
+ select 1
+ user
+ pwd
+ com.mysql.jdbc.Driver
+ jdbc:mysql://localhost:3306/${config.db.name}?autoReconnect=true
+ jdbc:mysql://localhost:3306/mysql?autoReconnect=true
+ drop database ${config.db.name}
+ create database ${config.db.name}
+
+
+
+ mssql
+
+ jackrabbit
+ org.apache.jackrabbit.core.fs.db.MSSqlFileSystem
+ org.apache.jackrabbit.core.data.db.DbDataStore
+ org.apache.jackrabbit.core.persistence.pool.MSSqlPersistenceManager
+ org.apache.jackrabbit.core.journal.MSSqlDatabaseJournal
+ mssql
+ select 1
+ user
+ pwd
+ net.sourceforge.jtds.jdbc.Driver
+ jdbc:jtds:sqlserver://localhost:2433/${config.db.name}
+ jdbc:jtds:sqlserver://localhost:2433/master
+ drop database ${config.db.name}
+ create database ${config.db.name}
+
+
+
+ oracle
+
+ unused
+ org.apache.jackrabbit.core.fs.db.OracleFileSystem
+ org.apache.jackrabbit.core.data.db.DbDataStore
+ org.apache.jackrabbit.core.persistence.pool.OraclePersistenceManager
+ org.apache.jackrabbit.core.journal.OracleDatabaseJournal
+ oracle
+ select 'validationQuery' from dual
+ user
+ password
+ oracle.jdbc.driver.OracleDriver
+ jdbc:oracle:thin:@localhost:1521:xe
+ unused
+ unused
+ unused
+
+
+
+ h2
+
+ jackrabbit
+ org.apache.jackrabbit.core.fs.db.DbFileSystem
+ org.apache.jackrabbit.core.data.db.DbDataStore
+ org.apache.jackrabbit.core.persistence.pool.H2PersistenceManager
+ org.apache.jackrabbit.core.journal.DatabaseJournal
+ h2
+ call 1
+ sa
+ sa
+ org.h2.Driver
+
+ jdbc:h2:~/jackrabbit2;MAX_LENGTH_INPLACE_LOB=10240;DB_CLOSE_ON_EXIT=FALSE
+ unused
+ drop all objects delete files
+ unused
+
+
+
+ use-descriptor-overlay
+
+
+
+
+ org.codehaus.mojo
+ sql-maven-plugin
+
+
+ mysql
+ mysql-connector-java
+ 5.1.6
+ jar
+ provided
+
+
+ net.sourceforge.jtds
+ jtds
+ 1.2.2
+ provided
+
+
+
+ ${config.db.driver}
+ ${config.db.metaurl}
+ ${config.db.user}
+ ${config.db.pwd}
+ sensibleKey
+
+
+
+ drop-db
+ clean
+
+ execute
+
+
+ true
+ ${config.db.dropcommand}
+ continue
+
+
+
+ create-db
+ clean
+
+ execute
+
+
+ true
+ ${config.db.createcommand}
+
+
+
+
+
+ maven-antrun-plugin
+
+
+ overlay-repository-descriptors
+ process-test-resources
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ run
+
+
+
+
+
+ ant
+ ant-optional
+ 1.5.3-1
+
+
+
+
+
+
+
+ mysql
+ mysql-connector-java
+ 5.1.6
+ jar
+ test
+
+
+ net.sourceforge.jtds
+ jtds
+ 1.2.2
+ test
+
+
+ com.oracle
+ ojdbc14
+ 10.2.0.3.0
+ test
+
+
+
+
+
diff --git a/jackrabbit-core/src/main/appended-resources/META-INF/NOTICE b/jackrabbit-core/src/main/appended-resources/META-INF/NOTICE
new file mode 100644
index 00000000000..45e7de5ff36
--- /dev/null
+++ b/jackrabbit-core/src/main/appended-resources/META-INF/NOTICE
@@ -0,0 +1,2 @@
+Based on source code originally developed by
+Day Software (http://www.day.com/).
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/AbstractNodeData.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/AbstractNodeData.java
new file mode 100644
index 00000000000..50954e086ee
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/AbstractNodeData.java
@@ -0,0 +1,126 @@
+/*
+ * 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.jackrabbit.core;
+
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.id.ItemId;
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.state.NodeState;
+
+/**
+ * Data object representing a node.
+ */
+public abstract class AbstractNodeData extends ItemData {
+
+ /** Primary parent id of a shareable node. */
+ private NodeId primaryParentId;
+
+ /**
+ * Create a new instance of this class.
+ *
+ * @param state node state
+ * @param itemMgr item manager
+ */
+ protected AbstractNodeData(NodeState state, ItemManager itemMgr) {
+ super(state, itemMgr);
+
+ if (state.isShareable()) {
+ this.primaryParentId = state.getParentId();
+ }
+ }
+
+ /**
+ * Create a new instance of this class.
+ *
+ * @param id item id
+ */
+ protected AbstractNodeData(ItemId id) {
+ super(id);
+ }
+
+ /**
+ * Return the associated node state.
+ *
+ * @return node state
+ */
+ public NodeState getNodeState() {
+ return (NodeState) getState();
+ }
+
+ /**
+ * Return the associated node definition.
+ *
+ * @return node definition
+ * @throws RepositoryException if the definition cannot be retrieved.
+ */
+ public NodeDefinition getNodeDefinition() throws RepositoryException {
+ return (NodeDefinition) getDefinition();
+ }
+
+ /**
+ * Sets the associated node definition.
+ *
+ * @param definition new node definition
+ */
+ public void setNodeDefinition(NodeDefinition definition) {
+ setDefinition(definition);
+ }
+
+ /**
+ * Return the parent id of this node. Every shareable node in a shared set
+ * has a different parent.
+ *
+ * @return parent id
+ */
+ @Override
+ public NodeId getParentId() {
+ if (primaryParentId != null) {
+ return primaryParentId;
+ }
+ return getState().getParentId();
+ }
+
+ /**
+ * Return the primary parent id of this node. Every shareable node in a
+ * shared set has a different primary parent. Returns null
+ * for nodes that are not shareable.
+ *
+ * @return primary parent id or null
+ */
+ public NodeId getPrimaryParentId() {
+ return primaryParentId;
+ }
+
+ /**
+ * Set the primary parent id of this node.
+ *
+ * @param primaryParentId primary parent id
+ */
+ protected void setPrimaryParentId(NodeId primaryParentId) {
+ this.primaryParentId = primaryParentId;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isNode() {
+ return true;
+ }
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/AddMixinOperation.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/AddMixinOperation.java
new file mode 100644
index 00000000000..f3049f894ce
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/AddMixinOperation.java
@@ -0,0 +1,179 @@
+/*
+ * 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.jackrabbit.core;
+
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_CHECKED_OUT;
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_CONSTRAINTS;
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_HOLD;
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_LOCK;
+import static org.apache.jackrabbit.spi.commons.name.NameConstants.MIX_SIMPLE_VERSIONABLE;
+import static org.apache.jackrabbit.spi.commons.name.NameConstants.MIX_VERSIONABLE;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.PropertyDefinition;
+
+import org.apache.jackrabbit.core.nodetype.EffectiveNodeType;
+import org.apache.jackrabbit.core.nodetype.NodeTypeConflictException;
+import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
+import org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl;
+import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.core.security.authorization.Permission;
+import org.apache.jackrabbit.core.session.SessionContext;
+import org.apache.jackrabbit.core.session.SessionWriteOperation;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.commons.nodetype.NodeDefinitionImpl;
+import org.apache.jackrabbit.spi.commons.nodetype.PropertyDefinitionImpl;
+
+/**
+ * Session operation for adding a mixin type to a node.
+ */
+class AddMixinOperation implements SessionWriteOperation
+ *
+ * @throws ConstraintViolationException
+ * @throws AccessDeniedException
+ * @throws VersionException
+ * @throws LockException
+ * @throws ItemNotFoundException
+ * @throws ItemExistsException
+ * @throws RepositoryException
+ */
+ public void checkAddNode(NodeState parentState, Name nodeName,
+ Name nodeTypeName, int options)
+ throws ConstraintViolationException, AccessDeniedException,
+ VersionException, LockException, ItemNotFoundException,
+ ItemExistsException, RepositoryException {
+
+ Path parentPath = hierMgr.getPath(parentState.getNodeId());
+
+ // 1. locking status
+
+ if ((options & CHECK_LOCK) == CHECK_LOCK) {
+ // make sure there's no foreign lock on parent node
+ verifyUnlocked(parentPath);
+ }
+
+ // 2. versioning status
+
+ if ((options & CHECK_CHECKED_OUT) == CHECK_CHECKED_OUT) {
+ // make sure parent node is checked-out
+ verifyCheckedOut(parentPath);
+ }
+
+ // 3. access rights
+
+ if ((options & CHECK_ACCESS) == CHECK_ACCESS) {
+ AccessManager accessMgr = context.getAccessManager();
+ // make sure current session is granted read access on parent node
+ if (!accessMgr.isGranted(parentPath, Permission.READ)) {
+ throw new ItemNotFoundException(safeGetJCRPath(parentState.getNodeId()));
+ }
+ // make sure current session is granted write access on parent node
+ if (!accessMgr.isGranted(parentPath, nodeName, Permission.ADD_NODE)) {
+ throw new AccessDeniedException(safeGetJCRPath(parentState.getNodeId())
+ + ": not allowed to add child node");
+ }
+ // make sure the editing session is allowed create nodes with a
+ // specified node type (and ev. mixins)
+ if (!accessMgr.isGranted(parentPath, nodeName, Permission.NODE_TYPE_MNGMT)) {
+ throw new AccessDeniedException(safeGetJCRPath(parentState.getNodeId())
+ + ": not allowed to add child node");
+ }
+ }
+
+ // 4. node type constraints
+
+ if ((options & CHECK_CONSTRAINTS) == CHECK_CONSTRAINTS) {
+ QItemDefinition parentDef =
+ context.getItemManager().getDefinition(parentState).unwrap();
+ // make sure parent node is not protected
+ if (parentDef.isProtected()) {
+ throw new ConstraintViolationException(
+ safeGetJCRPath(parentState.getNodeId())
+ + ": cannot add child node to protected parent node");
+ }
+ // make sure there's an applicable definition for new child node
+ EffectiveNodeType entParent = getEffectiveNodeType(parentState);
+ entParent.checkAddNodeConstraints(
+ nodeName, nodeTypeName, context.getNodeTypeRegistry());
+ QNodeDefinition newNodeDef =
+ findApplicableNodeDefinition(nodeName, nodeTypeName,
+ parentState);
+
+ // check for name collisions
+ if (parentState.hasChildNodeEntry(nodeName)) {
+ // there's already a node with that name...
+
+ // get definition of existing conflicting node
+ ChildNodeEntry entry = parentState.getChildNodeEntry(nodeName, 1);
+ NodeState conflictingState;
+ NodeId conflictingId = entry.getId();
+ try {
+ conflictingState = (NodeState) stateMgr.getItemState(conflictingId);
+ } catch (ItemStateException ise) {
+ String msg =
+ "internal error: failed to retrieve state of "
+ + safeGetJCRPath(conflictingId);
+ log.debug(msg);
+ throw new RepositoryException(msg, ise);
+ }
+ QNodeDefinition conflictingTargetDef =
+ context.getItemManager().getDefinition(conflictingState).unwrap();
+ // check same-name sibling setting of both target and existing node
+ if (!conflictingTargetDef.allowsSameNameSiblings()
+ || !newNodeDef.allowsSameNameSiblings()) {
+ throw new ItemExistsException(
+ "cannot add child node '" + nodeName.getLocalName()
+ + "' to " + safeGetJCRPath(parentState.getNodeId())
+ + ": colliding with same-named existing node");
+ }
+ }
+ }
+
+ RetentionRegistry retentionReg =
+ context.getSessionImpl().getRetentionRegistry();
+ if ((options & CHECK_HOLD) == CHECK_HOLD) {
+ if (retentionReg.hasEffectiveHold(parentPath, false)) {
+ throw new RepositoryException("Unable to add node. Parent is affected by a hold.");
+ }
+ }
+ if ((options & CHECK_RETENTION) == CHECK_RETENTION) {
+ if (retentionReg.hasEffectiveRetention(parentPath, false)) {
+ throw new RepositoryException("Unable to add node. Parent is affected by a retention.");
+ }
+ }
+ }
+
+ /**
+ * Checks if removing the given target node is allowed in the current context.
+ *
+ * @param targetState
+ * @param options bit-wise OR'ed flags specifying the checks that should be
+ * performed; any combination of the following constants:
+ *
+ *
{@link #CHECK_ACCESS}: make sure
+ * current session is granted read access on parent
+ * and remove privilege on target node
+ *
{@link #CHECK_LOCK}: make sure
+ * there's no foreign lock on parent node
+ *
{@link #CHECK_CHECKED_OUT}: make sure
+ * parent node is checked-out
+ *
{@link #CHECK_CONSTRAINTS}:
+ * make sure no node type constraints would be violated
+ *
{@link #CHECK_REFERENCES}:
+ * make sure no references exist on target node
+ *
{@link #CHECK_HOLD}: check for effective holds preventing the add operation
+ *
{@link #CHECK_RETENTION}
+ *
+ * @throws ConstraintViolationException
+ * @throws AccessDeniedException
+ * @throws VersionException
+ * @throws LockException
+ * @throws ItemNotFoundException
+ * @throws ReferentialIntegrityException
+ * @throws RepositoryException
+ */
+ public void checkRemoveNode(NodeState targetState, int options)
+ throws ConstraintViolationException, AccessDeniedException,
+ VersionException, LockException, ItemNotFoundException,
+ ReferentialIntegrityException, RepositoryException {
+ checkRemoveNode(targetState, targetState.getParentId(), options);
+ }
+
+ /**
+ * Checks if removing the given target node from the specifed parent
+ * is allowed in the current context.
+ *
+ * @param targetState
+ * @param parentId
+ * @param options bit-wise OR'ed flags specifying the checks that should be
+ * performed; any combination of the following constants:
+ *
+ *
{@link #CHECK_ACCESS}: make sure
+ * current session is granted read access on parent
+ * and remove privilege on target node
+ *
{@link #CHECK_LOCK}: make sure
+ * there's no foreign lock on parent node
+ *
{@link #CHECK_CHECKED_OUT}: make sure
+ * parent node is checked-out
+ *
{@link #CHECK_CONSTRAINTS}:
+ * make sure no node type constraints would be violated
+ *
{@link #CHECK_REFERENCES}:
+ * make sure no references exist on target node
+ *
{@link #CHECK_HOLD}: check for effective holds preventing the add operation
+ *
{@link #CHECK_RETENTION}: check for effective retention policy preventing the add operation
+ *
+ * @throws ConstraintViolationException
+ * @throws AccessDeniedException
+ * @throws VersionException
+ * @throws LockException
+ * @throws ItemNotFoundException
+ * @throws ReferentialIntegrityException
+ * @throws RepositoryException
+ */
+ public void checkRemoveNode(NodeState targetState, NodeId parentId,
+ int options)
+ throws ConstraintViolationException, AccessDeniedException,
+ VersionException, LockException, ItemNotFoundException,
+ ReferentialIntegrityException, RepositoryException {
+
+ if (targetState.getParentId() == null) {
+ // root or orphaned node
+ throw new ConstraintViolationException("cannot remove root node");
+ }
+ Path targetPath = hierMgr.getPath(targetState.getNodeId());
+ NodeState parentState = getNodeState(parentId);
+ Path parentPath = hierMgr.getPath(parentId);
+
+ // 1. locking status
+
+ if ((options & CHECK_LOCK) == CHECK_LOCK) {
+ // make sure there's no foreign lock on parent node
+ verifyUnlocked(parentPath);
+ }
+
+ // 2. versioning status
+
+ if ((options & CHECK_CHECKED_OUT) == CHECK_CHECKED_OUT) {
+ // make sure parent node is checked-out
+ verifyCheckedOut(parentPath);
+ }
+
+ // 3. access rights
+
+ if ((options & CHECK_ACCESS) == CHECK_ACCESS) {
+ try {
+ AccessManager accessMgr = context.getAccessManager();
+ // make sure current session is granted read access on parent node
+ if (!accessMgr.isGranted(targetPath, Permission.READ)) {
+ throw new PathNotFoundException(safeGetJCRPath(targetPath));
+ }
+ // make sure current session is allowed to remove target node
+ if (!accessMgr.isGranted(targetPath, Permission.REMOVE_NODE)) {
+ throw new AccessDeniedException(safeGetJCRPath(targetPath)
+ + ": not allowed to remove node");
+ }
+ } catch (ItemNotFoundException infe) {
+ String msg = "internal error: failed to check access rights for "
+ + safeGetJCRPath(targetPath);
+ log.debug(msg);
+ throw new RepositoryException(msg, infe);
+ }
+ }
+
+ // 4. node type constraints
+
+ if ((options & CHECK_CONSTRAINTS) == CHECK_CONSTRAINTS) {
+ QItemDefinition parentDef =
+ context.getItemManager().getDefinition(parentState).unwrap();
+ if (parentDef.isProtected()) {
+ throw new ConstraintViolationException(safeGetJCRPath(parentId)
+ + ": cannot remove child node of protected parent node");
+ }
+ QItemDefinition targetDef =
+ context.getItemManager().getDefinition(targetState).unwrap();
+ if (targetDef.isMandatory()) {
+ throw new ConstraintViolationException(safeGetJCRPath(targetPath)
+ + ": cannot remove mandatory node");
+ }
+ if (targetDef.isProtected()) {
+ throw new ConstraintViolationException(safeGetJCRPath(targetPath)
+ + ": cannot remove protected node");
+ }
+ }
+
+ // 5. referential integrity
+
+ if ((options & CHECK_REFERENCES) == CHECK_REFERENCES) {
+ EffectiveNodeType ent = getEffectiveNodeType(targetState);
+ if (ent.includesNodeType(NameConstants.MIX_REFERENCEABLE)) {
+ NodeId targetId = targetState.getNodeId();
+ if (stateMgr.hasNodeReferences(targetId)) {
+ try {
+ NodeReferences refs = stateMgr.getNodeReferences(targetId);
+ if (refs.hasReferences()) {
+ throw new ReferentialIntegrityException(safeGetJCRPath(targetPath)
+ + ": cannot remove node with references");
+ }
+ } catch (ItemStateException ise) {
+ String msg = "internal error: failed to check references on "
+ + safeGetJCRPath(targetPath);
+ log.error(msg, ise);
+ throw new RepositoryException(msg, ise);
+ }
+ }
+ }
+ }
+
+ RetentionRegistry retentionReg =
+ context.getSessionImpl().getRetentionRegistry();
+ if ((options & CHECK_HOLD) == CHECK_HOLD) {
+ if (retentionReg.hasEffectiveHold(targetPath, true)) {
+ throw new RepositoryException("Unable to perform removal. Node is affected by a hold.");
+ }
+ }
+ if ((options & CHECK_RETENTION) == CHECK_RETENTION) {
+ if (retentionReg.hasEffectiveRetention(targetPath, true)) {
+ throw new RepositoryException("Unable to perform removal. Node is affected by a retention.");
+ }
+ }
+ }
+
+ /**
+ * Verifies that the node at nodePath is writable. The
+ * following conditions must hold true:
+ *
+ *
the node must exist
+ *
the current session must be granted read & write access on it
+ *
the node must not be locked by another session
+ *
the node must not be checked-in
+ *
the node must not be protected
+ *
the node must not be affected by a hold or a retention policy
+ *
+ *
+ * @param nodePath path of node to check
+ * @throws PathNotFoundException if no node exists at
+ * nodePath of the current
+ * session is not granted read access
+ * to the specified path
+ * @throws AccessDeniedException if write access to the specified
+ * path is not allowed
+ * @throws ConstraintViolationException if the node at nodePath
+ * is protected
+ * @throws VersionException if the node at nodePath
+ * is checked-in
+ * @throws LockException if the node at nodePath
+ * is locked by another session
+ * @throws RepositoryException if another error occurs
+ */
+ public void verifyCanWrite(Path nodePath)
+ throws PathNotFoundException, AccessDeniedException,
+ ConstraintViolationException, VersionException, LockException,
+ RepositoryException {
+
+ NodeState node = getNodeState(nodePath);
+
+ // access rights
+ // make sure current session is granted read access on node
+ AccessManager accessMgr = context.getAccessManager();
+ if (!accessMgr.isGranted(nodePath, Permission.READ)) {
+ throw new PathNotFoundException(safeGetJCRPath(node.getNodeId()));
+ }
+ // TODO: removed check for 'WRITE' permission on node due to the fact,
+ // TODO: that add_node and set_property permission are granted on the
+ // TODO: items to be create/modified and not on their parent.
+ // in any case, the ability to add child-nodes and properties is checked
+ // while executing the corresponding operation.
+
+ // locking status
+ verifyUnlocked(nodePath);
+
+ // node type constraints
+ verifyNotProtected(nodePath);
+
+ // versioning status
+ verifyCheckedOut(nodePath);
+
+ RetentionRegistry retentionReg =
+ context.getSessionImpl().getRetentionRegistry();
+ if (retentionReg.hasEffectiveHold(nodePath, false)) {
+ throw new RepositoryException("Unable to write. Node is affected by a hold.");
+ }
+ if (retentionReg.hasEffectiveRetention(nodePath, false)) {
+ throw new RepositoryException("Unable to write. Node is affected by a retention.");
+ }
+ }
+
+ /**
+ * Verifies that the node at nodePath can be read. The
+ * following conditions must hold true:
+ *
+ *
the node must exist
+ *
the current session must be granted read access on it
+ *
+ *
+ * @param nodePath path of node to check
+ * @throws PathNotFoundException if no node exists at
+ * nodePath of the current
+ * session is not granted read access
+ * to the specified path
+ * @throws RepositoryException if another error occurs
+ */
+ public void verifyCanRead(Path nodePath)
+ throws PathNotFoundException, RepositoryException {
+ // access rights
+ // make sure current session is granted read access on node
+ AccessManager accessMgr = context.getAccessManager();
+ if (!accessMgr.isGranted(nodePath, Permission.READ)) {
+ throw new PathNotFoundException(safeGetJCRPath(nodePath));
+ }
+ }
+
+ //--------------------------------------------< low-level item operations >
+ /**
+ * Creates a new node.
+ *
+ * Note that access rights are not enforced!
+ *
+ * Precondition: the state manager needs to be in edit mode.
+ *
+ * @param parent
+ * @param nodeName
+ * @param nodeTypeName
+ * @param mixinNames
+ * @param id
+ * @return
+ * @throws ItemExistsException
+ * @throws ConstraintViolationException
+ * @throws RepositoryException
+ * @throws IllegalStateException if the state manager is not in edit mode.
+ */
+ public NodeState createNodeState(NodeState parent,
+ Name nodeName,
+ Name nodeTypeName,
+ Name[] mixinNames,
+ NodeId id)
+ throws ItemExistsException, ConstraintViolationException,
+ RepositoryException, IllegalStateException {
+
+ // check precondition
+ if (!stateMgr.inEditMode()) {
+ throw new IllegalStateException(
+ "cannot create node state for " + nodeName
+ + " because manager is not in edit mode");
+ }
+
+ QNodeDefinition def = findApplicableNodeDefinition(nodeName, nodeTypeName, parent);
+ return createNodeState(parent, nodeName, nodeTypeName, mixinNames, id, def);
+ }
+
+ /**
+ * Creates a new node based on the given definition.
+ *
+ * Note that access rights are not enforced!
+ *
+ * Precondition: the state manager needs to be in edit mode.
+ *
+ * @param parent
+ * @param nodeName
+ * @param nodeTypeName
+ * @param mixinNames
+ * @param id
+ * @param def
+ * @return
+ * @throws ItemExistsException
+ * @throws ConstraintViolationException
+ * @throws RepositoryException
+ * @throws IllegalStateException
+ */
+ public NodeState createNodeState(NodeState parent,
+ Name nodeName,
+ Name nodeTypeName,
+ Name[] mixinNames,
+ NodeId id,
+ QNodeDefinition def)
+ throws ItemExistsException, ConstraintViolationException,
+ RepositoryException, IllegalStateException {
+
+ // check for name collisions with existing nodes
+ if (!def.allowsSameNameSiblings() && parent.hasChildNodeEntry(nodeName)) {
+ NodeId errorId = parent.getChildNodeEntry(nodeName, 1).getId();
+ throw new ItemExistsException(safeGetJCRPath(errorId));
+ }
+ if (nodeTypeName == null) {
+ // no primary node type specified,
+ // try default primary type from definition
+ nodeTypeName = def.getDefaultPrimaryType();
+ if (nodeTypeName == null) {
+ String msg =
+ "an applicable node type could not be determined for "
+ + nodeName;
+ log.debug(msg);
+ throw new ConstraintViolationException(msg);
+ }
+ }
+ NodeState node = stateMgr.createNew(id, nodeTypeName, parent.getNodeId());
+ if (mixinNames != null && mixinNames.length > 0) {
+ node.setMixinTypeNames(new HashSet(Arrays.asList(mixinNames)));
+ }
+
+ // now add new child node entry to parent
+ parent.addChildNodeEntry(nodeName, node.getNodeId());
+
+ EffectiveNodeType ent = getEffectiveNodeType(node);
+
+ // check shareable
+ if (ent.includesNodeType(NameConstants.MIX_SHAREABLE)) {
+ node.addShare(parent.getNodeId());
+ }
+
+ if (!node.getMixinTypeNames().isEmpty()) {
+ // create jcr:mixinTypes property
+ QPropertyDefinition pd = ent.getApplicablePropertyDef(NameConstants.JCR_MIXINTYPES,
+ PropertyType.NAME, true);
+ createPropertyState(node, pd.getName(), pd.getRequiredType(), pd);
+ }
+
+ // add 'auto-create' properties defined in node type
+ for (QPropertyDefinition pd : ent.getAutoCreatePropDefs()) {
+ createPropertyState(node, pd.getName(), pd.getRequiredType(), pd);
+ }
+
+ // recursively add 'auto-create' child nodes defined in node type
+ for (QNodeDefinition nd : ent.getAutoCreateNodeDefs()) {
+ createNodeState(node, nd.getName(), nd.getDefaultPrimaryType(),
+ null, null, nd);
+ }
+
+ // store node
+ stateMgr.store(node);
+ // store parent
+ stateMgr.store(parent);
+
+ return node;
+ }
+
+ /**
+ * Creates a new property.
+ *
+ * Note that access rights are not enforced!
+ *
+ * Precondition: the state manager needs to be in edit mode.
+ *
+ * @param parent
+ * @param propName
+ * @param type
+ * @param numValues
+ * @return
+ * @throws ItemExistsException
+ * @throws ConstraintViolationException
+ * @throws RepositoryException
+ * @throws IllegalStateException if the state manager is not in edit mode
+ */
+ public PropertyState createPropertyState(NodeState parent,
+ Name propName,
+ int type,
+ int numValues)
+ throws ItemExistsException, ConstraintViolationException,
+ RepositoryException, IllegalStateException {
+
+ // check precondition
+ if (!stateMgr.inEditMode()) {
+ throw new IllegalStateException(
+ "cannot create property state for " + propName
+ + " because manager is not in edit mode");
+ }
+
+ // find applicable definition
+ QPropertyDefinition def;
+ // multi- or single-valued property?
+ if (numValues == 1) {
+ // could be single- or multi-valued (n == 1)
+ try {
+ // try single-valued
+ def = findApplicablePropertyDefinition(propName,
+ type, false, parent);
+ } catch (ConstraintViolationException cve) {
+ // try multi-valued
+ def = findApplicablePropertyDefinition(propName,
+ type, true, parent);
+ }
+ } else {
+ // can only be multi-valued (n == 0 || n > 1)
+ def = findApplicablePropertyDefinition(propName,
+ type, true, parent);
+ }
+ return createPropertyState(parent, propName, type, def);
+ }
+
+ /**
+ * Creates a new property based on the given definition.
+ *
+ * Note that access rights are not enforced!
+ *
+ * Precondition: the state manager needs to be in edit mode.
+ *
+ * @param parent
+ * @param propName
+ * @param type
+ * @param def
+ * @return
+ * @throws ItemExistsException
+ * @throws RepositoryException
+ */
+ public PropertyState createPropertyState(NodeState parent,
+ Name propName,
+ int type,
+ QPropertyDefinition def)
+ throws ItemExistsException, RepositoryException {
+
+ // check for name collisions with existing properties
+ if (parent.hasPropertyName(propName)) {
+ PropertyId errorId = new PropertyId(parent.getNodeId(), propName);
+ throw new ItemExistsException(safeGetJCRPath(errorId));
+ }
+
+ // create property
+ PropertyState prop = stateMgr.createNew(propName, parent.getNodeId());
+
+ if (def.getRequiredType() != PropertyType.UNDEFINED) {
+ prop.setType(def.getRequiredType());
+ } else if (type != PropertyType.UNDEFINED) {
+ prop.setType(type);
+ } else {
+ prop.setType(PropertyType.STRING);
+ }
+ prop.setMultiValued(def.isMultiple());
+
+ // compute system generated values if necessary
+ new NodeTypeInstanceHandler(session.getUserID()).setDefaultValues(
+ prop, parent, def);
+
+ // now add new property entry to parent
+ parent.addPropertyName(propName);
+ // store parent
+ stateMgr.store(parent);
+
+ return prop;
+ }
+
+ /**
+ * Unlinks the specified node state from its parent and recursively
+ * removes it including its properties and child nodes.
+ *
+ * Note that no checks (access rights etc.) are performed on the specified
+ * target node state. Those checks have to be performed beforehand by the
+ * caller. However, the (recursive) removal of target node's child nodes are
+ * subject to the following checks: access rights, locking, versioning.
+ *
+ * @param target
+ * @throws RepositoryException if an error occurs
+ */
+ public void removeNodeState(NodeState target)
+ throws RepositoryException {
+
+ NodeId parentId = target.getParentId();
+ if (parentId == null) {
+ String msg = "root node cannot be removed";
+ log.debug(msg);
+ throw new RepositoryException(msg);
+ }
+ // remove target
+ recursiveRemoveNodeState(target);
+ // remove child node entry from parent
+ NodeState parent = getNodeState(parentId);
+ parent.removeChildNodeEntry(target.getNodeId());
+ // store parent
+ stateMgr.store(parent);
+ }
+
+ /**
+ * Retrieves the state of the node at the given path.
+ *
+ * Note that access rights are not enforced!
+ *
+ * @param nodePath
+ * @return
+ * @throws PathNotFoundException
+ * @throws RepositoryException
+ */
+ public NodeState getNodeState(Path nodePath)
+ throws PathNotFoundException, RepositoryException {
+ return getNodeState(stateMgr, hierMgr, nodePath);
+ }
+
+ /**
+ * Retrieves the state of the node with the given id.
+ *
+ * Note that access rights are not enforced!
+ *
+ * @param id
+ * @return
+ * @throws ItemNotFoundException
+ * @throws RepositoryException
+ */
+ public NodeState getNodeState(NodeId id)
+ throws ItemNotFoundException, RepositoryException {
+ return (NodeState) getItemState(stateMgr, id);
+ }
+
+ /**
+ * Retrieves the state of the property with the given id.
+ *
+ * Note that access rights are not enforced!
+ *
+ * @param id
+ * @return
+ * @throws ItemNotFoundException
+ * @throws RepositoryException
+ */
+ public PropertyState getPropertyState(PropertyId id)
+ throws ItemNotFoundException, RepositoryException {
+ return (PropertyState) getItemState(stateMgr, id);
+ }
+
+ /**
+ * Retrieves the state of the item with the given id.
+ *
+ * Note that access rights are not enforced!
+ *
+ * @param id
+ * @return
+ * @throws ItemNotFoundException
+ * @throws RepositoryException
+ */
+ public ItemState getItemState(ItemId id)
+ throws ItemNotFoundException, RepositoryException {
+ return getItemState(stateMgr, id);
+ }
+
+ //----------------------------------------------------< protected methods >
+ /**
+ * Verifies that the node at nodePath is checked-out; throws a
+ * VersionException if that's not the case.
+ *
+ * A node is considered checked-out if it is versionable and
+ * checked-out, or is non-versionable but its nearest versionable ancestor
+ * is checked-out, or is non-versionable and there are no versionable
+ * ancestors.
+ *
+ * @param nodePath
+ * @throws PathNotFoundException
+ * @throws VersionException
+ * @throws RepositoryException
+ */
+ protected void verifyCheckedOut(Path nodePath)
+ throws PathNotFoundException, VersionException, RepositoryException {
+ // search nearest ancestor that is versionable, start with node at nodePath
+ /**
+ * FIXME should not only rely on existence of jcr:isCheckedOut property
+ * but also verify that node.isNodeType("mix:versionable")==true;
+ * this would have a negative impact on performance though...
+ */
+ NodeState nodeState = getNodeState(nodePath);
+ while (!nodeState.hasPropertyName(NameConstants.JCR_ISCHECKEDOUT)) {
+ if (nodePath.denotesRoot()) {
+ return;
+ }
+ nodePath = nodePath.getAncestor(1);
+ nodeState = getNodeState(nodePath);
+ }
+ PropertyId propId =
+ new PropertyId(nodeState.getNodeId(), NameConstants.JCR_ISCHECKEDOUT);
+ PropertyState propState;
+ try {
+ propState = (PropertyState) stateMgr.getItemState(propId);
+ } catch (ItemStateException ise) {
+ String msg = "internal error: failed to retrieve state of "
+ + safeGetJCRPath(propId);
+ log.debug(msg);
+ throw new RepositoryException(msg, ise);
+ }
+ boolean checkedOut = propState.getValues()[0].getBoolean();
+ if (!checkedOut) {
+ throw new VersionException(safeGetJCRPath(nodePath) + " is checked-in");
+ }
+ }
+
+ /**
+ * Verifies that the node at nodePath is not locked by
+ * somebody else than the current session.
+ *
+ * @param nodePath path of node to check
+ * @throws PathNotFoundException
+ * @throws LockException if write access to the specified path is not allowed
+ * @throws RepositoryException if another error occurs
+ */
+ protected void verifyUnlocked(Path nodePath)
+ throws LockException, RepositoryException {
+ // make sure there's no foreign lock on node at nodePath
+ context.getWorkspace().getInternalLockManager().checkLock(
+ nodePath, session);
+ }
+
+ /**
+ * Verifies that the node at nodePath is not protected.
+ *
+ * @param nodePath path of node to check
+ * @throws PathNotFoundException if no node exists at nodePath
+ * @throws ConstraintViolationException if write access to the specified
+ * path is not allowed
+ * @throws RepositoryException if another error occurs
+ */
+ protected void verifyNotProtected(Path nodePath)
+ throws PathNotFoundException, ConstraintViolationException,
+ RepositoryException {
+ NodeState node = getNodeState(nodePath);
+ if (context.getItemManager().getDefinition(node).isProtected()) {
+ throw new ConstraintViolationException(safeGetJCRPath(nodePath)
+ + ": node is protected");
+ }
+ }
+
+ /**
+ * Retrieves the state of the node at nodePath using the given
+ * item state manager.
+ *
+ * Note that access rights are not enforced!
+ *
+ * @param srcStateMgr
+ * @param srcHierMgr
+ * @param nodePath
+ * @return
+ * @throws PathNotFoundException
+ * @throws RepositoryException
+ */
+ protected NodeState getNodeState(ItemStateManager srcStateMgr,
+ HierarchyManager srcHierMgr,
+ Path nodePath)
+ throws PathNotFoundException, RepositoryException {
+ try {
+ NodeId id = srcHierMgr.resolveNodePath(nodePath);
+ if (id == null) {
+ throw new PathNotFoundException(safeGetJCRPath(nodePath));
+ }
+ return (NodeState) getItemState(srcStateMgr, id);
+ } catch (ItemNotFoundException infe) {
+ throw new PathNotFoundException(safeGetJCRPath(nodePath));
+ }
+ }
+
+ /**
+ * Retrieves the state of the item with the specified id using the given
+ * item state manager.
+ *
+ * Note that access rights are not enforced!
+ *
+ * @param srcStateMgr
+ * @param id
+ * @return
+ * @throws ItemNotFoundException
+ * @throws RepositoryException
+ */
+ protected ItemState getItemState(ItemStateManager srcStateMgr, ItemId id)
+ throws ItemNotFoundException, RepositoryException {
+ try {
+ return srcStateMgr.getItemState(id);
+ } catch (NoSuchItemStateException nsise) {
+ throw new ItemNotFoundException(safeGetJCRPath(id));
+ } catch (ItemStateException ise) {
+ String msg = "internal error: failed to retrieve state of "
+ + safeGetJCRPath(id);
+ log.debug(msg);
+ throw new RepositoryException(msg, ise);
+ }
+ }
+
+ //------------------------------------------------------< private methods >
+
+ /**
+ * Recursively removes the given node state including its properties and
+ * child nodes.
+ *
+ * The removal of child nodes is subject to the following checks:
+ * access rights, locking & versioning status. Referential integrity
+ * (references) is checked on commit.
+ *
+ * Note that the child node entry refering to targetState is
+ * not automatically removed from targetState's
+ * parent.
+ *
+ * @param targetState
+ * @throws RepositoryException if an error occurs
+ */
+ private void recursiveRemoveNodeState(NodeState targetState)
+ throws RepositoryException {
+
+ if (targetState.hasChildNodeEntries()) {
+ // remove child nodes
+ // use temp array to avoid ConcurrentModificationException
+ ArrayList tmp = new ArrayList(targetState.getChildNodeEntries());
+ // remove from tail to avoid problems with same-name siblings
+ for (int i = tmp.size() - 1; i >= 0; i--) {
+ ChildNodeEntry entry = tmp.get(i);
+ NodeId nodeId = entry.getId();
+ try {
+ NodeState nodeState = (NodeState) stateMgr.getItemState(nodeId);
+ // check if child node can be removed
+ // (access rights, locking & versioning status as well
+ // as retention and hold);
+ // referential integrity (references) is checked
+ // on commit
+ checkRemoveNode(nodeState, targetState.getNodeId(),
+ CHECK_ACCESS
+ | CHECK_LOCK
+ | CHECK_CHECKED_OUT
+ | CHECK_HOLD
+ | CHECK_RETENTION
+ );
+ // remove child node
+ recursiveRemoveNodeState(nodeState);
+ } catch (ItemStateException ise) {
+ String msg = "internal error: failed to retrieve state of "
+ + nodeId;
+ log.debug(msg);
+ throw new RepositoryException(msg, ise);
+ }
+ // remove child node entry
+ targetState.removeChildNodeEntry(entry.getName(), entry.getIndex());
+ }
+ }
+
+ // remove properties
+ // use temp set to avoid ConcurrentModificationException
+ HashSet tmp = new HashSet(targetState.getPropertyNames());
+ for (Name propName : tmp) {
+ PropertyId propId =
+ new PropertyId(targetState.getNodeId(), propName);
+ try {
+ PropertyState propState =
+ (PropertyState) stateMgr.getItemState(propId);
+ // remove property entry
+ targetState.removePropertyName(propId.getName());
+ // destroy property state
+ stateMgr.destroy(propState);
+ } catch (ItemStateException ise) {
+ String msg = "internal error: failed to retrieve state of "
+ + propId;
+ log.debug(msg);
+ throw new RepositoryException(msg, ise);
+ }
+ }
+
+ // now actually do unlink target state
+ targetState.setParentId(null);
+ // destroy target state (pass overlayed state since target state
+ // might have been modified during unlinking)
+ stateMgr.destroy(targetState.getOverlayedState());
+ }
+
+ /**
+ * Recursively copies the specified node state including its properties and
+ * child nodes.
+ *
+ * @param srcState
+ * @param srcPath
+ * @param srcStateMgr
+ * @param srcAccessMgr
+ * @param destParentId
+ * @param flag one of
+ *
+ *
COPY
+ *
CLONE
+ *
CLONE_REMOVE_EXISTING
+ *
+ * @param refTracker tracks uuid mappings and processed reference properties
+ * @return a deep copy of the given node state and its children
+ * @throws RepositoryException if an error occurs
+ */
+ private NodeState copyNodeState(NodeState srcState,
+ Path srcPath,
+ ItemStateManager srcStateMgr,
+ AccessManager srcAccessMgr,
+ NodeId destParentId,
+ int flag,
+ ReferenceChangeTracker refTracker)
+ throws RepositoryException {
+
+ NodeState newState;
+ try {
+ NodeId id = null;
+ EffectiveNodeType ent = getEffectiveNodeType(srcState);
+ boolean referenceable = ent.includesNodeType(NameConstants.MIX_REFERENCEABLE);
+ boolean versionable = ent.includesNodeType(NameConstants.MIX_SIMPLE_VERSIONABLE);
+ boolean fullVersionable = ent.includesNodeType(NameConstants.MIX_VERSIONABLE);
+ boolean shareable = ent.includesNodeType(NameConstants.MIX_SHAREABLE);
+ switch (flag) {
+ case COPY:
+ /* if this node is shareable and another node in the same shared set
+ * has been already been copied and given a new uuid, use this one
+ * (see section 14.5 of the specification)
+ */
+ if (shareable && refTracker.getMappedId(srcState.getNodeId()) != null) {
+ NodeId newId = refTracker.getMappedId(srcState.getNodeId());
+ NodeState sharedState = (NodeState) stateMgr.getItemState(newId);
+ sharedState.addShare(destParentId);
+ return sharedState;
+ }
+ break;
+ case CLONE:
+ if (!referenceable) {
+ // non-referenceable node: always create new node id
+ break;
+ }
+ // use same uuid as source node
+ id = srcState.getNodeId();
+
+ if (stateMgr.hasItemState(id)) {
+ if (shareable) {
+ NodeState sharedState = (NodeState) stateMgr.getItemState(id);
+ sharedState.addShare(destParentId);
+ return sharedState;
+ }
+ // node with this uuid already exists
+ throw new ItemExistsException(safeGetJCRPath(id));
+ }
+ break;
+ case CLONE_REMOVE_EXISTING:
+ if (!referenceable) {
+ // non-referenceable node: always create new node id
+ break;
+ }
+ // use same uuid as source node
+ id = srcState.getNodeId();
+ if (stateMgr.hasItemState(id)) {
+ NodeState existingState = (NodeState) stateMgr.getItemState(id);
+ // make sure existing node is not the parent
+ // or an ancestor thereof
+ if (id.equals(destParentId)
+ || hierMgr.isAncestor(id, destParentId)) {
+ String msg =
+ "cannot remove node " + safeGetJCRPath(srcPath)
+ + " because it is an ancestor of the destination";
+ log.debug(msg);
+ throw new RepositoryException(msg);
+ }
+
+ // check if existing can be removed
+ // (access rights, locking & versioning status,
+ // node type constraints and retention/hold)
+ checkRemoveNode(existingState,
+ CHECK_ACCESS
+ | CHECK_LOCK
+ | CHECK_CHECKED_OUT
+ | CHECK_CONSTRAINTS
+ | CHECK_HOLD
+ | CHECK_RETENTION);
+ // do remove existing
+ removeNodeState(existingState);
+ }
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "unknown flag for copying node state: " + flag);
+ }
+ newState = stateMgr.createNew(id, srcState.getNodeTypeName(), destParentId);
+ id = newState.getNodeId();
+ if (flag == COPY && referenceable) {
+ // remember uuid mapping
+ refTracker.mappedId(srcState.getNodeId(), id);
+ }
+ // copy node state
+ newState.setMixinTypeNames(srcState.getMixinTypeNames());
+ if (shareable) {
+ // initialize shared set
+ newState.addShare(destParentId);
+ }
+ // copy child nodes
+ for (ChildNodeEntry entry : srcState.getChildNodeEntries()) {
+ Path srcChildPath = PathFactoryImpl.getInstance().create(srcPath, entry.getName(), true);
+ if (!srcAccessMgr.isGranted(srcChildPath, Permission.READ)) {
+ continue;
+ }
+ NodeId nodeId = entry.getId();
+ NodeState srcChildState = (NodeState) srcStateMgr.getItemState(nodeId);
+
+ /**
+ * special handling required for child nodes with special semantics
+ * (e.g. those defined by nt:version, et.al.)
+ *
+ * todo FIXME delegate to 'node type instance handler'
+ */
+
+ /**
+ * If child is shareble and its UUID has already been remapped,
+ * then simply add a reference to the state with that remapped
+ * UUID instead of copying the whole subtree.
+ */
+ if (srcChildState.isShareable()) {
+ NodeId mappedId = refTracker.getMappedId(srcChildState.getNodeId());
+ if (mappedId != null) {
+ if (stateMgr.hasItemState(mappedId)) {
+ NodeState destState = (NodeState) stateMgr.getItemState(mappedId);
+ if (!destState.isShareable()) {
+ String msg =
+ "Remapped child (" + safeGetJCRPath(srcPath)
+ + ") is not shareable.";
+ throw new ItemStateException(msg);
+ }
+ if (!destState.addShare(id)) {
+ String msg = "Unable to add share to node: " + id;
+ throw new ItemStateException(msg);
+ }
+ stateMgr.store(destState);
+ newState.addChildNodeEntry(entry.getName(), mappedId);
+ continue;
+ }
+ }
+ }
+
+ // recursive copying of child node
+ NodeState newChildState = copyNodeState(srcChildState, srcChildPath,
+ srcStateMgr, srcAccessMgr, id, flag, refTracker);
+ // store new child node
+ stateMgr.store(newChildState);
+ // add new child node entry to new node
+ newState.addChildNodeEntry(entry.getName(), newChildState.getNodeId());
+ }
+ // init version history if needed
+ VersionHistoryInfo history = null;
+ if (versionable && flag == COPY) {
+ NodeId copiedFrom = null;
+ if (fullVersionable) {
+ // base version of copied versionable node is reference value of
+ // the histories jcr:copiedFrom property
+ PropertyId propId = new PropertyId(srcState.getNodeId(), NameConstants.JCR_BASEVERSION);
+ PropertyState prop = (PropertyState) srcStateMgr.getItemState(propId);
+ copiedFrom = prop.getValues()[0].getNodeId();
+ }
+ InternalVersionManager manager = session.getInternalVersionManager();
+ history = manager.getVersionHistory(session, newState, copiedFrom);
+ }
+ // copy properties
+ for (Name propName : srcState.getPropertyNames()) {
+ Path propPath = PathFactoryImpl.getInstance().create(srcPath, propName, true);
+ PropertyId propId = new PropertyId(srcState.getNodeId(), propName);
+ if (!srcAccessMgr.canRead(propPath, propId)) {
+ continue;
+ }
+ PropertyState srcChildState =
+ (PropertyState) srcStateMgr.getItemState(propId);
+
+ /**
+ * special handling required for properties with special semantics
+ * (e.g. those defined by mix:referenceable, mix:versionable,
+ * mix:lockable, et.al.)
+ *
+ * todo FIXME delegate to 'node type instance handler'
+ */
+ QPropertyDefinition def = ent.getApplicablePropertyDef(
+ srcChildState.getName(), srcChildState.getType(),
+ srcChildState.isMultiValued());
+ if (NameConstants.MIX_LOCKABLE.equals(def.getDeclaringNodeType())) {
+ // skip properties defined by mix:lockable
+ continue;
+ }
+
+ PropertyState newChildState =
+ copyPropertyState(srcChildState, id, propName, def);
+
+ if (history != null) {
+ if (fullVersionable) {
+ if (propName.equals(NameConstants.JCR_VERSIONHISTORY)) {
+ // jcr:versionHistory
+ InternalValue value = InternalValue.create(
+ history.getVersionHistoryId());
+ newChildState.setValues(new InternalValue[] { value });
+ } else if (propName.equals(NameConstants.JCR_BASEVERSION)
+ || propName.equals(NameConstants.JCR_PREDECESSORS)) {
+ // jcr:baseVersion or jcr:predecessors
+ InternalValue value = InternalValue.create(
+ history.getRootVersionId());
+ newChildState.setValues(new InternalValue[] { value });
+ } else if (propName.equals(NameConstants.JCR_ISCHECKEDOUT)) {
+ // jcr:isCheckedOut
+ newChildState.setValues(new InternalValue[]{InternalValue.create(true)});
+ }
+ } else {
+ // for simple versionable, we just initialize the
+ // version history when we see the jcr:isCheckedOut
+ if (propName.equals(NameConstants.JCR_ISCHECKEDOUT)) {
+ // jcr:isCheckedOut
+ newChildState.setValues(new InternalValue[]{InternalValue.create(true)});
+ }
+ }
+ }
+
+ if (newChildState.getType() == PropertyType.REFERENCE
+ || newChildState.getType() == PropertyType.WEAKREFERENCE) {
+ refTracker.processedReference(newChildState);
+ }
+ // store new property
+ stateMgr.store(newChildState);
+ // add new property entry to new node
+ newState.addPropertyName(propName);
+ }
+ return newState;
+ } catch (ItemStateException ise) {
+ String msg = "internal error: failed to copy state of " + srcState.getNodeId();
+ log.debug(msg);
+ throw new RepositoryException(msg, ise);
+ }
+ }
+
+ /**
+ * Copies the specified property state.
+ *
+ * @param srcState the property state to copy.
+ * @param parentId the id of the parent node.
+ * @param propName the name of the property.
+ * @param def the definition of the property.
+ * @return a copy of the property state.
+ * @throws RepositoryException if an error occurs while copying.
+ */
+ private PropertyState copyPropertyState(PropertyState srcState,
+ NodeId parentId,
+ Name propName,
+ QPropertyDefinition def)
+ throws RepositoryException {
+
+ PropertyState newState = stateMgr.createNew(propName, parentId);
+
+ newState.setType(srcState.getType());
+ newState.setMultiValued(srcState.isMultiValued());
+ InternalValue[] values = srcState.getValues();
+ if (values != null) {
+ /**
+ * special handling required for properties with special semantics
+ * (e.g. those defined by mix:referenceable, mix:versionable,
+ * mix:lockable, et.al.)
+ *
+ * todo FIXME delegate to 'node type instance handler'
+ */
+ if (propName.equals(NameConstants.JCR_UUID)
+ && def.getDeclaringNodeType().equals(NameConstants.MIX_REFERENCEABLE)) {
+ // set correct value of jcr:uuid property
+ newState.setValues(new InternalValue[]{InternalValue.create(parentId.toString())});
+ } else {
+ InternalValue[] newValues = new InternalValue[values.length];
+ for (int i = 0; i < values.length; i++) {
+ newValues[i] = values[i].createCopy();
+ }
+ newState.setValues(newValues);
+ }
+ }
+ return newState;
+ }
+
+ /**
+ * Check that the updatable item state manager is in edit mode.
+ *
+ * @throws IllegalStateException if it isn't
+ */
+ private void checkInEditMode() throws IllegalStateException {
+ if (!stateMgr.inEditMode()) {
+ throw new IllegalStateException("not in edit mode");
+ }
+ }
+
+ /**
+ * Determines whether the specified node is shareable, i.e.
+ * whether the mixin type mix:shareable is either
+ * directly assigned or indirectly inherited.
+ *
+ * @param state node state to check
+ * @return true if the specified node is shareable, false otherwise.
+ * @throws RepositoryException if an error occurs
+ */
+ private boolean isShareable(NodeState state) throws RepositoryException {
+ // shortcut: check some wellknown built-in types first
+ Name primary = state.getNodeTypeName();
+ Set mixins = state.getMixinTypeNames();
+ if (mixins.contains(NameConstants.MIX_SHAREABLE)) {
+ return true;
+ }
+
+ try {
+ NodeTypeRegistry registry = context.getNodeTypeRegistry();
+ EffectiveNodeType type =
+ registry.getEffectiveNodeType(primary, mixins);
+ return type.includesNodeType(NameConstants.MIX_REFERENCEABLE);
+ } catch (NodeTypeConflictException ntce) {
+ String msg = "internal error: failed to build effective node type for node "
+ + state.getNodeId();
+ log.debug(msg);
+ throw new RepositoryException(msg, ntce);
+ }
+ }
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java
new file mode 100644
index 00000000000..0bc3500ea8c
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/CachingHierarchyManager.java
@@ -0,0 +1,1072 @@
+/*
+ * 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.jackrabbit.core;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.RepositoryException;
+
+import org.apache.commons.collections.map.ReferenceMap;
+import org.apache.jackrabbit.core.id.ItemId;
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.state.ChildNodeEntry;
+import org.apache.jackrabbit.core.state.ItemState;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.ItemStateManager;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.NodeStateListener;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.commons.conversion.MalformedPathException;
+import org.apache.jackrabbit.spi.commons.name.PathBuilder;
+import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl;
+import org.apache.jackrabbit.spi.commons.name.PathMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation of a HierarchyManager that caches paths of
+ * items.
+ */
+public class CachingHierarchyManager extends HierarchyManagerImpl
+ implements NodeStateListener {
+
+ /**
+ * Default upper limit of cached states
+ */
+ public static final int DEFAULT_UPPER_LIMIT = 10000;
+
+ private static final int MAX_UPPER_LIMIT =
+ Integer.getInteger("org.apache.jackrabbit.core.CachingHierarchyManager.cacheSize", DEFAULT_UPPER_LIMIT);
+
+ private static final int CACHE_STATISTICS_LOG_INTERVAL_MILLIS =
+ Integer.getInteger("org.apache.jackrabbit.core.CachingHierarchyManager.logInterval", 60000);
+
+ /**
+ * Logger instance
+ */
+ private static Logger log = LoggerFactory.getLogger(CachingHierarchyManager.class);
+
+ /**
+ * Mapping of paths to children in the path map
+ */
+ private final PathMap pathCache = new PathMap();
+
+ /**
+ * Mapping of item ids to LRUEntry in the path map
+ */
+ private final ReferenceMap idCache = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.HARD);
+
+ /**
+ * Cache monitor object
+ */
+ private final Object cacheMonitor = new Object();
+
+ /**
+ * Upper limit
+ */
+ private final int upperLimit;
+
+ /**
+ * Object collecting and logging statistics about the idCache
+ */
+ private final CacheStatistics idCacheStatistics;
+
+ /**
+ * Head of LRU
+ */
+ private LRUEntry head;
+
+ /**
+ * Tail of LRU
+ */
+ private LRUEntry tail;
+
+ /**
+ * Flag indicating whether consistency checking is enabled.
+ */
+ private boolean consistencyCheckEnabled;
+
+ /**
+ * Log interval for item state exceptions.
+ */
+ private static final int ITEM_STATE_EXCEPTION_LOG_INTERVAL_MILLIS = 60 * 1000;
+
+ /**
+ * Last time-stamp item state exception was logged with a stacktrace.
+ */
+ private long itemStateExceptionLogTimestamp = 0;
+
+ /**
+ * Create a new instance of this class.
+ *
+ * @param rootNodeId root node id
+ * @param provider item state manager
+ */
+ public CachingHierarchyManager(NodeId rootNodeId,
+ ItemStateManager provider) {
+ super(rootNodeId, provider);
+ upperLimit = MAX_UPPER_LIMIT;
+ idCacheStatistics = new CacheStatistics();
+ if (log.isTraceEnabled()) {
+ log.trace("CachingHierarchyManager initialized. Max cache size = {}", upperLimit, new Exception());
+ } else {
+ log.debug("CachingHierarchyManager initialized. Max cache size = {}", upperLimit);
+ }
+ }
+
+ /**
+ * Enable or disable consistency checks in this instance.
+ *
+ * @param enable true to enable consistency checks;
+ * false to disable
+ */
+ public void enableConsistencyChecks(boolean enable) {
+ this.consistencyCheckEnabled = enable;
+ }
+
+ //-------------------------------------------------< base class overrides >
+
+ /**
+ * {@inheritDoc}
+ */
+ protected ItemId resolvePath(Path path, int typesAllowed)
+ throws RepositoryException {
+
+ Path pathToNode = path;
+ if ((typesAllowed & RETURN_NODE) == 0) {
+ // if we must not return a node, pass parent path
+ // (since we only cache nodes)
+ pathToNode = path.getAncestor(1);
+ }
+
+ PathMap.Element element = map(pathToNode);
+ if (element == null) {
+ // not even intermediate match: call base class
+ return super.resolvePath(path, typesAllowed);
+ }
+
+ LRUEntry entry = element.get();
+ if (element.hasPath(path)) {
+ // exact match: return answer
+ synchronized (cacheMonitor) {
+ entry.touch();
+ }
+ return entry.getId();
+ }
+ Path.Element[] elements = path.getElements();
+ try {
+ return resolvePath(elements, element.getDepth() + 1, entry.getId(), typesAllowed);
+ } catch (ItemStateException e) {
+ String msg = "failed to retrieve state of intermediary node for entry: "
+ + entry.getId() + ", path: " + path.getString();
+ logItemStateException(msg, e);
+ log.debug(msg);
+ // probably stale cache entry -> evict
+ evictAll(entry.getId(), true);
+ }
+ // JCR-3617: fall back to super class in case of ItemStateException
+ return super.resolvePath(path, typesAllowed);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void pathResolved(ItemId id, PathBuilder builder)
+ throws MalformedPathException {
+
+ if (id.denotesNode()) {
+ cache((NodeId) id, builder.getPath());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Overridden method tries to find a mapping for the intermediate item
+ * state and add its path elements to the builder currently
+ * being used. If no mapping is found, the item is cached instead after
+ * the base implementation has been invoked.
+ */
+ protected void buildPath(
+ PathBuilder builder, ItemState state, CycleDetector detector)
+ throws ItemStateException, RepositoryException {
+
+ if (state.isNode()) {
+ PathMap.Element element = get(state.getId());
+ if (element != null) {
+ try {
+ Path.Element[] elements = element.getPath().getElements();
+ for (int i = elements.length - 1; i >= 0; i--) {
+ builder.addFirst(elements[i]);
+ }
+ return;
+ } catch (MalformedPathException mpe) {
+ String msg = "Failed to build path of " + state.getId();
+ log.debug(msg);
+ throw new RepositoryException(msg, mpe);
+ }
+ }
+ }
+
+ super.buildPath(builder, state, detector);
+
+ if (state.isNode()) {
+ try {
+ cache(((NodeState) state).getNodeId(), builder.getPath());
+ } catch (MalformedPathException mpe) {
+ log.warn("Failed to build path of " + state.getId());
+ }
+ }
+ }
+
+ //-----------------------------------------------------< HierarchyManager >
+
+ /**
+ * {@inheritDoc}
+ *
+ * Overridden method simply checks whether we have an item matching the id
+ * and returns its path, otherwise calls base implementation.
+ */
+ public Path getPath(ItemId id)
+ throws ItemNotFoundException, RepositoryException {
+
+ if (id.denotesNode()) {
+ PathMap.Element element = get(id);
+ if (element != null) {
+ try {
+ return element.getPath();
+ } catch (MalformedPathException mpe) {
+ String msg = "Failed to build path of " + id;
+ log.debug(msg);
+ throw new RepositoryException(msg, mpe);
+ }
+ }
+ }
+ return super.getPath(id);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Name getName(ItemId id)
+ throws ItemNotFoundException, RepositoryException {
+
+ if (id.denotesNode()) {
+ PathMap.Element element = get(id);
+ if (element != null) {
+ return element.getName();
+ }
+ }
+ return super.getName(id);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getDepth(ItemId id)
+ throws ItemNotFoundException, RepositoryException {
+
+ if (id.denotesNode()) {
+ PathMap.Element element = get(id);
+ if (element != null) {
+ return element.getDepth();
+ }
+ }
+ return super.getDepth(id);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isAncestor(NodeId nodeId, ItemId itemId)
+ throws ItemNotFoundException, RepositoryException {
+
+ if (itemId.denotesNode()) {
+ PathMap.Element element = get(nodeId);
+ if (element != null) {
+ PathMap.Element child = get(itemId);
+ if (child != null) {
+ return element.isAncestorOf(child);
+ }
+ }
+ }
+ return super.isAncestor(nodeId, itemId);
+ }
+
+ //----------------------------------------------------< ItemStateListener >
+
+ /**
+ * {@inheritDoc}
+ */
+ public void stateCreated(ItemState created) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void stateModified(ItemState modified) {
+ if (modified.isNode()) {
+ nodeModified((NodeState) modified);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * If path information is cached for modified, this iterates
+ * over all child nodes in the path map, evicting the ones that do not
+ * (longer) exist in the underlying NodeState.
+ */
+ public void nodeModified(NodeState modified) {
+ synchronized (cacheMonitor) {
+ for (PathMap.Element element
+ : getCachedPaths(modified.getNodeId())) {
+ for (PathMap.Element child : element.getChildren()) {
+ ChildNodeEntry cne = modified.getChildNodeEntry(
+ child.getName(), child.getNormalizedIndex());
+ if (cne == null) {
+ // Item does not exist, remove
+ evict(child, true);
+ } else {
+ LRUEntry childEntry = child.get();
+ if (childEntry != null
+ && !cne.getId().equals(childEntry.getId())) {
+ // Different child item, remove
+ evict(child, true);
+ }
+ }
+ }
+ }
+ checkConsistency();
+ }
+ }
+
+ private List> getCachedPaths(NodeId id) {
+ // JCR-2720: Handle the root path as a special case
+ if (rootNodeId.equals(id)) {
+ return Collections.singletonList(pathCache.map(
+ PathFactoryImpl.getInstance().getRootPath(), true));
+ }
+
+ LRUEntry entry = (LRUEntry) idCache.get(id);
+ if (entry != null) {
+ return Arrays.asList(entry.getElements());
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void stateDestroyed(ItemState destroyed) {
+ evictAll(destroyed.getId(), true);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void stateDiscarded(ItemState discarded) {
+ if (discarded.isTransient() && !discarded.hasOverlayedState()
+ && discarded.getStatus() == ItemState.STATUS_NEW) {
+ // a new node has been discarded -> remove from cache
+ evictAll(discarded.getId(), true);
+ } else if (provider.hasItemState(discarded.getId())) {
+ evictAll(discarded.getId(), false);
+ } else {
+ evictAll(discarded.getId(), true);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void nodeAdded(NodeState state, Name name, int index, NodeId id) {
+ synchronized (cacheMonitor) {
+ if (idCache.containsKey(state.getNodeId())) {
+ // Optimization: ignore notifications for nodes that are not in the cache
+ try {
+ Path path = PathFactoryImpl.getInstance().create(getPath(state.getNodeId()), name, index, true);
+ nodeAdded(state, path, id);
+ checkConsistency();
+ } catch (PathNotFoundException e) {
+ log.warn("Unable to get path of node " + state.getNodeId()
+ + ", event ignored.");
+ } catch (MalformedPathException e) {
+ log.warn("Unable to create path of " + id, e);
+ } catch (ItemNotFoundException e) {
+ log.warn("Unable to find item " + state.getNodeId(), e);
+ } catch (ItemStateException e) {
+ log.warn("Unable to find item " + id, e);
+ } catch (RepositoryException e) {
+ log.warn("Unable to get path of " + state.getNodeId(), e);
+ }
+ } else if (state.getParentId() == null && idCache.containsKey(id)) {
+ // A top level node was added
+ evictAll(id, true);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Iterate over all cached children of this state and verify each
+ * child's position.
+ */
+ public void nodesReplaced(NodeState state) {
+ synchronized (cacheMonitor) {
+ LRUEntry entry = (LRUEntry) idCache.get(state.getNodeId());
+ if (entry == null) {
+ return;
+ }
+ for (PathMap.Element parent : entry.getElements()) {
+ HashMap> newChildrenOrder =
+ new HashMap>();
+ boolean orderChanged = false;
+
+ for (PathMap.Element child : parent.getChildren()) {
+ LRUEntry childEntry = (LRUEntry) child.get();
+ if (childEntry == null) {
+ // Child has no associated UUID information: we're
+ // therefore unable to determine if this child's
+ // position is still accurate and have to assume
+ // the worst and remove it.
+ evict(child, false);
+ } else {
+ NodeId childId = childEntry.getId();
+ ChildNodeEntry cne = state.getChildNodeEntry(childId);
+ if (cne == null) {
+ // Child no longer in parent node, so remove it
+ evict(child, false);
+ } else {
+ // Put all children into map of new children order
+ // - regardless whether their position changed or
+ // not - as we might need to reorder them later on.
+ Path.Element newNameIndex =
+ PathFactoryImpl.getInstance().createElement(
+ cne.getName(), cne.getIndex());
+ newChildrenOrder.put(newNameIndex, child);
+
+ if (!newNameIndex.equals(child.getPathElement())) {
+ orderChanged = true;
+ }
+ }
+ }
+ }
+
+ if (orderChanged) {
+ /* If at least one child changed its position, reorder */
+ parent.setChildren(newChildrenOrder);
+ }
+ }
+ checkConsistency();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void nodeRemoved(NodeState state, Name name, int index, NodeId id) {
+ synchronized (cacheMonitor) {
+ if (idCache.containsKey(state.getNodeId())) {
+ // Optimization: ignore notifications for nodes that are not in the cache
+ try {
+ Path path = PathFactoryImpl.getInstance().create(getPath(state.getNodeId()), name, index, true);
+ nodeRemoved(state, path, id);
+ checkConsistency();
+ } catch (PathNotFoundException e) {
+ log.warn("Unable to get path of node " + state.getNodeId()
+ + ", event ignored.");
+ } catch (MalformedPathException e) {
+ log.warn("Unable to create path of " + id, e);
+ } catch (ItemStateException e) {
+ log.warn("Unable to find item " + id, e);
+ } catch (ItemNotFoundException e) {
+ log.warn("Unable to get path of " + state.getNodeId(), e);
+ } catch (RepositoryException e) {
+ log.warn("Unable to get path of " + state.getNodeId(), e);
+ }
+ } else if (state.getParentId() == null && idCache.containsKey(id)) {
+ // A top level node was removed
+ evictAll(id, true);
+ }
+ }
+ }
+
+ //------------------------------------------------------< private methods >
+
+ /**
+ * Return the first cached path that is mapped to given id.
+ *
+ * @param id node id
+ * @return cached element, null if not found
+ */
+ private PathMap.Element get(ItemId id) {
+ synchronized (cacheMonitor) {
+ LRUEntry entry = (LRUEntry) idCache.get(id);
+ if (entry != null) {
+ entry.touch();
+ return entry.getElements()[0];
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Return the nearest cached element in the path map, given a path.
+ * The returned element is guaranteed to have an associated object that
+ * is not null.
+ *
+ * @param path path
+ * @return cached element, null if not found
+ */
+ private PathMap.Element map(Path path) {
+ synchronized (cacheMonitor) {
+ PathMap.Element element = pathCache.map(path, false);
+ while (element != null) {
+ LRUEntry entry = element.get();
+ if (entry != null) {
+ entry.touch();
+ return element;
+ }
+ element = element.getParent();
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Cache an item in the hierarchy given its id and path.
+ *
+ * @param id node id
+ * @param path path to item
+ */
+ private void cache(NodeId id, Path path) {
+ synchronized (cacheMonitor) {
+ if (isCached(id, path)) {
+ return;
+ }
+ if (idCache.size() >= upperLimit) {
+
+ idCacheStatistics.log();
+
+ /**
+ * Remove least recently used item. Scans the LRU list from
+ * head to tail and removes the first item that has no children.
+ */
+ LRUEntry entry = head;
+ while (entry != null) {
+ PathMap.Element[] elements = entry.getElements();
+ int childrenCount = 0;
+ for (int i = 0; i < elements.length; i++) {
+ childrenCount += elements[i].getChildrenCount();
+ }
+ if (childrenCount == 0) {
+ evictAll(entry.getId(), false);
+ return;
+ }
+ entry = entry.getNext();
+ }
+ }
+ PathMap.Element element = pathCache.put(path);
+ if (element.get() != null) {
+ if (!id.equals(((LRUEntry) element.get()).getId())) {
+ log.debug("overwriting PathMap.Element");
+ }
+ }
+ LRUEntry entry = (LRUEntry) idCache.get(id);
+ if (entry == null) {
+ entry = new LRUEntry(id, element);
+ idCache.put(id, entry);
+ } else {
+ entry.addElement(element);
+ }
+ element.set(entry);
+
+ checkConsistency();
+ }
+ }
+
+ /**
+ * Return a flag indicating whether a certain node and/or path is cached.
+ * If path is null, check whether the item is
+ * cached at all. If path is notnull,
+ * check whether the item is cached with that path.
+ *
+ * @param id item id
+ * @param path path, may be null
+ * @return true if the item is already cached;
+ * false otherwise
+ */
+ boolean isCached(NodeId id, Path path) {
+ synchronized (cacheMonitor) {
+ LRUEntry entry = (LRUEntry) idCache.get(id);
+ if (entry == null) {
+ return false;
+ }
+ if (path == null) {
+ return true;
+ }
+ PathMap.Element[] elements = entry.getElements();
+ for (int i = 0; i < elements.length; i++) {
+ if (elements[i].hasPath(path)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Return a flag indicating whether a certain path is cached.
+ *
+ * @param path item path
+ * @return true if the item is already cached;
+ * false otherwise
+ */
+ boolean isCached(Path path) {
+ synchronized (cacheMonitor) {
+ PathMap.Element element = pathCache.map(path, true);
+ if (element != null) {
+ return element.get() != null;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Remove all path mapping for a given item id. Removes the associated
+ * LRUEntry and the PathMap.Element with it.
+ * Indexes of same name sibling elements are shifted!
+ *
+ * @param id item id
+ */
+ private void evictAll(ItemId id, boolean shift) {
+ synchronized (cacheMonitor) {
+ LRUEntry entry = (LRUEntry) idCache.get(id);
+ if (entry != null) {
+ PathMap.Element[] elements = entry.getElements();
+ for (int i = 0; i < elements.length; i++) {
+ evict(elements[i], shift);
+ }
+ }
+ checkConsistency();
+ }
+ }
+
+ /**
+ * Evict path map element from cache. This will traverse all children
+ * of this element and remove the objects associated with them.
+ * Index of same name sibling items are shifted!
+ *
+ * @param element path map element
+ */
+ private void evict(PathMap.Element element, boolean shift) {
+ // assert: synchronized (cacheMonitor)
+ element.traverse(new PathMap.ElementVisitor() {
+ public void elementVisited(PathMap.Element element) {
+ LRUEntry entry = (LRUEntry) element.get();
+ if (entry.removeElement(element) == 0) {
+ idCache.remove(entry.getId());
+ entry.remove();
+ }
+ }
+ }, false);
+ element.remove(shift);
+ }
+
+ /**
+ * Invoked when a notification about a child node addition has been received.
+ *
+ * @param state node state where child was added
+ * @param path path to child node
+ * @param id child node id
+ *
+ * @throws PathNotFoundException if the path was not found
+ * @throws RepositoryException If the path's direct ancestor cannot be determined.
+ * @throws ItemStateException If the id cannot be resolved to a NodeState.
+ */
+ private void nodeAdded(NodeState state, Path path, NodeId id)
+ throws RepositoryException, ItemStateException {
+
+ // assert: synchronized (cacheMonitor)
+ PathMap.Element element = null;
+
+ LRUEntry entry = (LRUEntry) idCache.get(id);
+ if (entry != null) {
+ // child node already cached: this can have the following
+ // reasons:
+ // 1) node was moved, cached path is outdated
+ // 2) node was cloned, cached path is still valid
+ NodeState child = null;
+ if (hasItemState(id)) {
+ child = (NodeState) getItemState(id);
+ }
+ if (child == null || !child.isShareable()) {
+ PathMap.Element[] elements = entry.getElements();
+ element = elements[0];
+ for (int i = 0; i < elements.length; i++) {
+ elements[i].remove();
+ }
+ }
+ }
+ PathMap.Element parent = pathCache.map(path.getAncestor(1), true);
+ if (parent != null) {
+ parent.insert(path.getNameElement());
+ }
+ if (element != null) {
+ // store remembered element at new position
+ pathCache.put(path, element);
+ }
+ }
+
+ /**
+ * Invoked when a notification about a child node removal has been received.
+ *
+ * @param state node state
+ * @param path node path
+ * @param id node id
+ *
+ * @throws PathNotFoundException if the path was not found.
+ * @throws RepositoryException If the path's direct ancestor cannot be determined.
+ * @throws ItemStateException If the id cannot be resolved to a NodeState.
+ */
+ private void nodeRemoved(NodeState state, Path path, NodeId id)
+ throws RepositoryException, ItemStateException {
+
+ // assert: synchronized (cacheMonitor)
+ PathMap.Element parent =
+ pathCache.map(path.getAncestor(1), true);
+ if (parent == null) {
+ return;
+ }
+ PathMap.Element element =
+ parent.getDescendant(path.getLastElement(), true);
+ if (element != null) {
+ // with SNS, this might evict a child that is NOT the one
+ // having id, check first whether item has
+ // the id passed as argument
+ LRUEntry entry = (LRUEntry) element.get();
+ if (entry != null && !entry.getId().equals(id)) {
+ return;
+ }
+ // if item is shareable, remove this path only, otherwise
+ // every path this item has been mapped to
+ NodeState child = null;
+ if (hasItemState(id)) {
+ child = (NodeState) getItemState(id);
+ }
+ if (child == null || !child.isShareable()) {
+ evictAll(id, true);
+ } else {
+ evict(element, true);
+ }
+ } else {
+ // element itself is not cached, but removal might cause SNS
+ // index shifting
+ parent.remove(path.getNameElement());
+ }
+ }
+
+ /**
+ * Dump contents of path map and elements included to a string.
+ */
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ synchronized (cacheMonitor) {
+ pathCache.traverse(new PathMap.ElementVisitor() {
+ public void elementVisited(PathMap.Element element) {
+ for (int i = 0; i < element.getDepth(); i++) {
+ builder.append("--");
+ }
+ builder.append(element.getName());
+ int index = element.getIndex();
+ if (index != 0 && index != 1) {
+ builder.append('[');
+ builder.append(index);
+ builder.append(']');
+ }
+ builder.append(" ");
+ builder.append(element.get());
+ builder.append("\n");
+ }
+ }, true);
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Check consistency.
+ */
+ private void checkConsistency() throws IllegalStateException {
+ // assert: synchronized (cacheMonitor)
+ if (!consistencyCheckEnabled) {
+ return;
+ }
+
+ int elementsInCache = 0;
+
+ Iterator iter = idCache.values().iterator();
+ while (iter.hasNext()) {
+ LRUEntry entry = (LRUEntry) iter.next();
+ elementsInCache += entry.getElements().length;
+ }
+
+ class PathMapElementCounter implements PathMap.ElementVisitor {
+ int count;
+ public void elementVisited(PathMap.Element element) {
+ LRUEntry mappedEntry = (LRUEntry) element.get();
+ LRUEntry cachedEntry = (LRUEntry) idCache.get(mappedEntry.getId());
+ if (cachedEntry == null) {
+ String msg = "Path element (" + element +
+ " ) cached in path map, associated id (" +
+ mappedEntry.getId() + ") isn't.";
+ throw new IllegalStateException(msg);
+ }
+ if (cachedEntry != mappedEntry) {
+ String msg = "LRUEntry associated with element (" + element +
+ " ) in path map is not equal to cached LRUEntry (" +
+ cachedEntry.getId() + ").";
+ throw new IllegalStateException(msg);
+ }
+ PathMap.Element[] elements = cachedEntry.getElements();
+ for (int i = 0; i < elements.length; i++) {
+ if (elements[i] == element) {
+ count++;
+ return;
+ }
+ }
+ String msg = "Element (" + element +
+ ") cached in path map, but not in associated LRUEntry (" +
+ cachedEntry.getId() + ").";
+ throw new IllegalStateException(msg);
+ }
+ }
+
+ PathMapElementCounter counter = new PathMapElementCounter();
+ pathCache.traverse(counter, false);
+ if (counter.count != elementsInCache) {
+ String msg = "PathMap element and cached element count don't match (" +
+ counter.count + " != " + elementsInCache + ")";
+ throw new IllegalStateException(msg);
+ }
+ }
+
+ /**
+ * Helper method to log item state exception with stack trace every so often.
+ *
+ * @param logMessage log message
+ * @param e item state exception
+ */
+ private void logItemStateException(String logMessage, ItemStateException e) {
+ long now = System.currentTimeMillis();
+ if ((now - itemStateExceptionLogTimestamp) >= ITEM_STATE_EXCEPTION_LOG_INTERVAL_MILLIS) {
+ itemStateExceptionLogTimestamp = now;
+ log.debug(logMessage, e);
+ } else {
+ log.debug(logMessage);
+ }
+ }
+
+ /**
+ * Entry in the LRU list
+ */
+ private class LRUEntry {
+
+ /**
+ * Previous entry
+ */
+ private LRUEntry previous;
+
+ /**
+ * Next entry
+ */
+ private LRUEntry next;
+
+ /**
+ * Node id
+ */
+ private final NodeId id;
+
+ /**
+ * Elements in path map
+ */
+ private PathMap.Element[] elements;
+
+ /**
+ * Create a new instance of this class
+ *
+ * @param id node id
+ * @param element the path map element for this entry
+ */
+ public LRUEntry(NodeId id, PathMap.Element element) {
+ this.id = id;
+ this.elements = new PathMap.Element[] { element };
+
+ append();
+ }
+
+ /**
+ * Append entry to end of LRU list
+ */
+ public void append() {
+ if (tail == null) {
+ head = this;
+ tail = this;
+ } else {
+ previous = tail;
+ tail.next = this;
+ tail = this;
+ }
+ }
+
+ /**
+ * Remove entry from LRU list
+ */
+ public void remove() {
+ if (previous != null) {
+ previous.next = next;
+ }
+ if (next != null) {
+ next.previous = previous;
+ }
+ if (head == this) {
+ head = next;
+ }
+ if (tail == this) {
+ tail = previous;
+ }
+ previous = null;
+ next = null;
+ }
+
+ /**
+ * Touch entry. Removes it from its current position in the LRU list
+ * and moves it to the end.
+ */
+ public void touch() {
+ remove();
+ append();
+ }
+
+ /**
+ * Return next LRU entry
+ *
+ * @return next LRU entry
+ */
+ public LRUEntry getNext() {
+ return next;
+ }
+
+ /**
+ * Return node ID
+ *
+ * @return node ID
+ */
+ public NodeId getId() {
+ return id;
+ }
+
+ /**
+ * Return elements in path map that are mapped to id. If
+ * this entry is a shareable node or one of its descendant, it can
+ * be reached by more than one path.
+ *
+ * @return element in path map
+ */
+ public PathMap.Element[] getElements() {
+ return elements;
+ }
+
+ /**
+ * Add a mapping to some element.
+ */
+ public void addElement(PathMap.Element element) {
+ PathMap.Element[] tmp =
+ new PathMap.Element[elements.length + 1];
+ System.arraycopy(elements, 0, tmp, 0, elements.length);
+ tmp[elements.length] = element;
+ elements = tmp;
+ }
+
+ /**
+ * Remove a mapping to some element from this entry.
+ *
+ * @return number of mappings left
+ */
+ public int removeElement(PathMap.Element element) {
+ boolean found = false;
+ for (int i = 0; i < elements.length; i++) {
+ if (found) {
+ elements[i - 1] = elements[i];
+ } else if (elements[i] == element) {
+ found = true;
+ }
+ }
+ if (found) {
+ PathMap.Element[] tmp =
+ new PathMap.Element[elements.length - 1];
+ System.arraycopy(elements, 0, tmp, 0, tmp.length);
+ elements = tmp;
+ }
+ return elements.length;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String toString() {
+ return id.toString();
+ }
+ }
+
+ private final class CacheStatistics {
+
+ private final String id;
+
+ private final ReferenceMap cache;
+
+ private long timeStamp = 0;
+
+ public CacheStatistics() {
+ this.id = cacheMonitor.toString();
+ this.cache = idCache;
+ }
+
+ public void log() {
+ if (log.isDebugEnabled()) {
+ long now = System.currentTimeMillis();
+ final String msg = "Cache id = {};size = {};max = {}";
+ if (log.isTraceEnabled()) {
+ log.trace(msg, new Object[]{id, this.cache.size(), upperLimit}, new Exception());
+ } else if (now > timeStamp + CACHE_STATISTICS_LOG_INTERVAL_MILLIS) {
+ timeStamp = now;
+ log.debug(msg, new Object[]{id, this.cache.size(), upperLimit}, new Exception());
+ }
+ }
+ }
+ }
+
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/DefaultSecurityManager.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/DefaultSecurityManager.java
new file mode 100644
index 00000000000..955a0f35d57
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/DefaultSecurityManager.java
@@ -0,0 +1,680 @@
+/*
+ * 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.jackrabbit.core;
+
+import java.security.Principal;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.Credentials;
+import javax.jcr.NoSuchWorkspaceException;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.security.AccessControlException;
+import javax.security.auth.Subject;
+
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.core.config.AccessManagerConfig;
+import org.apache.jackrabbit.core.config.LoginModuleConfig;
+import org.apache.jackrabbit.core.config.SecurityConfig;
+import org.apache.jackrabbit.core.config.SecurityManagerConfig;
+import org.apache.jackrabbit.core.config.WorkspaceConfig;
+import org.apache.jackrabbit.core.config.WorkspaceSecurityConfig;
+import org.apache.jackrabbit.core.config.UserManagerConfig;
+import org.apache.jackrabbit.core.security.AMContext;
+import org.apache.jackrabbit.core.security.AccessManager;
+import org.apache.jackrabbit.core.security.DefaultAccessManager;
+import org.apache.jackrabbit.core.security.JackrabbitSecurityManager;
+import org.apache.jackrabbit.core.security.SecurityConstants;
+import org.apache.jackrabbit.core.security.SystemPrincipal;
+import org.apache.jackrabbit.core.security.authentication.AuthContext;
+import org.apache.jackrabbit.core.security.authentication.AuthContextProvider;
+import org.apache.jackrabbit.core.security.authorization.AccessControlProvider;
+import org.apache.jackrabbit.core.security.authorization.AccessControlProviderFactory;
+import org.apache.jackrabbit.core.security.authorization.AccessControlProviderFactoryImpl;
+import org.apache.jackrabbit.core.security.authorization.WorkspaceAccessManager;
+import org.apache.jackrabbit.core.security.principal.AbstractPrincipalProvider;
+import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
+import org.apache.jackrabbit.core.security.principal.DefaultPrincipalProvider;
+import org.apache.jackrabbit.core.security.principal.PrincipalManagerImpl;
+import org.apache.jackrabbit.core.security.principal.PrincipalProvider;
+import org.apache.jackrabbit.core.security.principal.PrincipalProviderRegistry;
+import org.apache.jackrabbit.core.security.principal.ProviderRegistryImpl;
+import org.apache.jackrabbit.core.security.user.MembershipCache;
+import org.apache.jackrabbit.core.security.user.UserManagerImpl;
+import org.apache.jackrabbit.core.security.user.action.AuthorizableAction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The security manager acts as central managing class for all security related
+ * operations on a low-level non-protected level. It manages the
+ *
+ *
{@link PrincipalProvider}s
+ *
{@link AccessControlProvider}s
+ *
{@link WorkspaceAccessManager}
+ *
{@link UserManager}
+ *
+ */
+public class DefaultSecurityManager implements JackrabbitSecurityManager {
+
+ /**
+ * the default logger
+ */
+ private static final Logger log = LoggerFactory.getLogger(DefaultSecurityManager.class);
+
+ /**
+ * Flag indicating if the security manager was properly initialized.
+ */
+ private boolean initialized;
+
+ /**
+ * the repository implementation
+ */
+ private RepositoryImpl repository;
+
+ /**
+ * System session.
+ */
+ private SystemSession systemSession;
+
+ /**
+ * System user manager. Implementation needed here for the DefaultPrincipalProvider.
+ */
+ private UserManager systemUserManager;
+
+ /**
+ * The user id of the administrator. The value is retrieved from
+ * configuration. If the config entry is missing a default id is used (see
+ * {@link SecurityConstants#ADMIN_ID}).
+ */
+ protected String adminId;
+
+ /**
+ * The user id of the anonymous user. The value is retrieved from
+ * configuration. If the config entry is missing a default id is used (see
+ * {@link SecurityConstants#ANONYMOUS_ID}).
+ */
+ protected String anonymousId;
+
+ /**
+ * Contains the access control providers per workspace.
+ * key = name of the workspace,
+ * value = {@link AccessControlProvider}
+ */
+ private final Map acProviders = new HashMap();
+
+ /**
+ * the AccessControlProviderFactory
+ */
+ private AccessControlProviderFactory acProviderFactory;
+
+ /**
+ * the configured WorkspaceAccessManager
+ */
+ private WorkspaceAccessManager workspaceAccessManager;
+
+ /**
+ * the principal provider registry
+ */
+ private PrincipalProviderRegistry principalProviderRegistry;
+
+ /**
+ * factory for login-context {@see Repository#login())
+ */
+ private AuthContextProvider authContextProvider;
+
+ //------------------------------------------< JackrabbitSecurityManager >---
+ /**
+ * @see JackrabbitSecurityManager#init(Repository, Session)
+ */
+ public synchronized void init(Repository repository, Session systemSession) throws RepositoryException {
+ if (initialized) {
+ throw new IllegalStateException("already initialized");
+ }
+ if (!(repository instanceof RepositoryImpl)) {
+ throw new RepositoryException("RepositoryImpl expected");
+ }
+ if (!(systemSession instanceof SystemSession)) {
+ throw new RepositoryException("SystemSession expected");
+ }
+
+ this.systemSession = (SystemSession) systemSession;
+ this.repository = (RepositoryImpl) repository;
+
+ SecurityConfig config = this.repository.getConfig().getSecurityConfig();
+ LoginModuleConfig loginModConf = config.getLoginModuleConfig();
+
+ // build AuthContextProvider based on appName + optional LoginModuleConfig
+ authContextProvider = new AuthContextProvider(config.getAppName(), loginModConf);
+ if (authContextProvider.isLocal()) {
+ log.info("init: use Repository Login-Configuration for " + config.getAppName());
+ } else if (authContextProvider.isJAAS()) {
+ log.info("init: use JAAS login-configuration for " + config.getAppName());
+ } else {
+ String msg = "Neither JAAS nor RepositoryConfig contained a valid configuration for " + config.getAppName();
+ log.error(msg);
+ throw new RepositoryException(msg);
+ }
+
+ Properties[] moduleConfig = authContextProvider.getModuleConfig();
+
+ // retrieve default-ids (admin and anonymous) from login-module-configuration.
+ for (Properties props : moduleConfig) {
+ if (props.containsKey(LoginModuleConfig.PARAM_ADMIN_ID)) {
+ adminId = props.getProperty(LoginModuleConfig.PARAM_ADMIN_ID);
+ }
+ if (props.containsKey(LoginModuleConfig.PARAM_ANONYMOUS_ID)) {
+ anonymousId = props.getProperty(LoginModuleConfig.PARAM_ANONYMOUS_ID);
+ }
+ }
+ // fallback:
+ if (adminId == null) {
+ log.debug("No adminID defined in LoginModule/JAAS config -> using default.");
+ adminId = SecurityConstants.ADMIN_ID;
+ }
+ if (anonymousId == null) {
+ log.debug("No anonymousID defined in LoginModule/JAAS config -> using default.");
+ anonymousId = SecurityConstants.ANONYMOUS_ID;
+ }
+
+ // create the system userManager and make sure the system-users exist.
+ systemUserManager = createUserManager(this.systemSession);
+ createSystemUsers(systemUserManager, this.systemSession, adminId, anonymousId);
+
+ // init default ac-provider-factory
+ acProviderFactory = new AccessControlProviderFactoryImpl();
+ acProviderFactory.init(this.systemSession);
+
+ // create the workspace access manager
+ SecurityManagerConfig smc = config.getSecurityManagerConfig();
+ if (smc != null && smc.getWorkspaceAccessConfig() != null) {
+ workspaceAccessManager =
+ smc.getWorkspaceAccessConfig().newInstance(WorkspaceAccessManager.class);
+ } else {
+ // fallback -> the default implementation
+ log.debug("No WorkspaceAccessManager configured; using default.");
+ workspaceAccessManager = createDefaultWorkspaceAccessManager();
+ }
+ workspaceAccessManager.init(this.systemSession);
+
+ // initialize principal-provider registry
+ // 1) create default
+ PrincipalProvider defaultPP = createDefaultPrincipalProvider(moduleConfig);
+ // 2) create registry instance
+ principalProviderRegistry = new ProviderRegistryImpl(defaultPP);
+ // 3) register all configured principal providers.
+ for (Properties props : moduleConfig) {
+ principalProviderRegistry.registerProvider(props);
+ }
+
+ initialized = true;
+ }
+
+ /**
+ * @see JackrabbitSecurityManager#dispose(String)
+ */
+ public void dispose(String workspaceName) {
+ checkInitialized();
+ synchronized (acProviders) {
+ AccessControlProvider prov = acProviders.remove(workspaceName);
+ if (prov != null) {
+ prov.close();
+ }
+ }
+ }
+
+ /**
+ * @see JackrabbitSecurityManager#close()
+ */
+ public void close() {
+ checkInitialized();
+ synchronized (acProviders) {
+ for (AccessControlProvider accessControlProvider : acProviders.values()) {
+ accessControlProvider.close();
+ }
+ acProviders.clear();
+ }
+ }
+
+ /**
+ * @see JackrabbitSecurityManager#getAccessManager(Session,AMContext)
+ */
+ public AccessManager getAccessManager(Session session, AMContext amContext) throws RepositoryException {
+ checkInitialized();
+ AccessManagerConfig amConfig = repository.getConfig().getSecurityConfig().getAccessManagerConfig();
+ try {
+ String wspName = session.getWorkspace().getName();
+ AccessControlProvider pp = getAccessControlProvider(wspName);
+ AccessManager accessMgr;
+ if (amConfig == null) {
+ log.debug("No configuration entry for AccessManager. Using org.apache.jackrabbit.core.security.DefaultAccessManager");
+ accessMgr = new DefaultAccessManager();
+ } else {
+ accessMgr = amConfig.newInstance(AccessManager.class);
+ }
+
+ accessMgr.init(amContext, pp, workspaceAccessManager);
+ return accessMgr;
+ } catch (AccessDeniedException e) {
+ // re-throw
+ throw e;
+ } catch (Exception e) {
+ // wrap in RepositoryException
+ String clsName = (amConfig == null) ? "-- missing access manager configuration --" : amConfig.getClassName();
+ String msg = "Failed to instantiate AccessManager (" + clsName + ")";
+ log.error(msg, e);
+ throw new RepositoryException(msg, e);
+ }
+ }
+
+ /**
+ * @see JackrabbitSecurityManager#getPrincipalManager(Session)
+ */
+ public PrincipalManager getPrincipalManager(Session session) throws RepositoryException {
+ checkInitialized();
+ if (session instanceof SessionImpl) {
+ SessionImpl sImpl = (SessionImpl) session;
+ return createPrincipalManager(sImpl);
+ } else {
+ throw new RepositoryException("Internal error: SessionImpl expected.");
+ }
+ }
+
+ /**
+ * @see JackrabbitSecurityManager#getUserManager(Session)
+ */
+ public UserManager getUserManager(Session session) throws RepositoryException {
+ checkInitialized();
+ if (session == systemSession) {
+ return systemUserManager;
+ } else if (session instanceof SessionImpl) {
+ String workspaceName = systemSession.getWorkspace().getName();
+ try {
+ SessionImpl sImpl = (SessionImpl) session;
+ UserManagerImpl uMgr;
+ if (workspaceName.equals(sImpl.getWorkspace().getName())) {
+ uMgr = createUserManager(sImpl);
+ } else {
+ SessionImpl s = (SessionImpl) sImpl.createSession(workspaceName);
+ uMgr = createUserManager(s);
+ sImpl.addListener(uMgr);
+ }
+ return uMgr;
+ } catch (NoSuchWorkspaceException e) {
+ throw new AccessControlException("Cannot build UserManager for " + session.getUserID(), e);
+ }
+ } else {
+ throw new RepositoryException("Internal error: SessionImpl expected.");
+ }
+ }
+
+ /**
+ * @see JackrabbitSecurityManager#getUserID(javax.security.auth.Subject, String)
+ */
+ public String getUserID(Subject subject, String workspaceName) throws RepositoryException {
+ checkInitialized();
+
+ // shortcut if the subject contains the AdminPrincipal or
+ // SystemPrincipal in which cases the userID is already known.
+ if (!subject.getPrincipals(AdminPrincipal.class).isEmpty()) {
+ return adminId;
+ } else if (!subject.getPrincipals(SystemPrincipal.class).isEmpty()) {
+ // system session does not have a userId
+ return null;
+ }
+
+ /* if there is a configure principal class that should be used to
+ determine the UserID -> try this one. */
+ Class cl = getConfig().getUserIdClass();
+ if (cl != null) {
+ Set s = subject.getPrincipals(cl);
+ if (!s.isEmpty()) {
+ for (Principal p : s) {
+ if (!(p instanceof java.security.acl.Group)) {
+ return p.getName();
+ }
+ }
+ // all principals found with the given p-Class were Group principals
+ log.debug("Only Group principals found with class '" + cl.getName() + "' -> Not used for UserID.");
+ } else {
+ log.debug("No principal found with class '" + cl.getName() + "'.");
+ }
+ }
+
+ /*
+ Fallback scenario to retrieve userID from the subject:
+ Since the subject may contain multiple principals and the principal
+ name may not be equals to the UserID, the id is retrieved by
+ searching for the corresponding authorizable and if this doesn't
+ succeed an attempt is made to obtained it from the login-credentials.
+ */
+ String uid = null;
+
+ // first try to retrieve an authorizable corresponding to
+ // a non-group principal. the first one present is used
+ // to determine the userID.
+ try {
+ UserManager umgr = getSystemUserManager(workspaceName);
+ for (Principal p : subject.getPrincipals()) {
+ if (!(p instanceof Group)) {
+ Authorizable authorz = umgr.getAuthorizable(p);
+ if (authorz != null && !authorz.isGroup()) {
+ uid = authorz.getID();
+ break;
+ }
+ }
+ }
+ } catch (RepositoryException e) {
+ // failed to access userid via user manager -> use fallback 2.
+ log.error("Unexpected error while retrieving UserID.", e);
+ }
+
+ // 2. if no matching user is found try simple access to userID over
+ // SimpleCredentials.
+ if (uid == null) {
+ Iterator creds = subject.getPublicCredentials(
+ SimpleCredentials.class).iterator();
+ if (creds.hasNext()) {
+ SimpleCredentials sc = creds.next();
+ uid = sc.getUserID();
+ }
+ }
+
+ return uid;
+ }
+
+ /**
+ * Creates an AuthContext for the given {@link Credentials} and
+ * {@link Subject}. The workspace name is ignored and users are
+ * stored and retrieved from a specific (separate) workspace.
+ * This includes selection of application specific LoginModules and
+ * initialization with credentials and Session to System-Workspace
+ *
+ * @return an {@link AuthContext} for the given Credentials, Subject
+ * @throws RepositoryException in other exceptional repository states
+ */
+ public AuthContext getAuthContext(Credentials creds, Subject subject, String workspaceName)
+ throws RepositoryException {
+ checkInitialized();
+ return getAuthContextProvider().getAuthContext(creds, subject, systemSession,
+ getPrincipalProviderRegistry(), adminId, anonymousId);
+ }
+
+ //----------------------------------------------------------< protected >---
+ /**
+ * @return The SecurityManagerConfig configured for the
+ * repository this manager has been created for.
+ */
+ protected SecurityManagerConfig getConfig() {
+ return repository.getConfig().getSecurityConfig().getSecurityManagerConfig();
+ }
+
+ /**
+ * @param workspaceName The name of the target workspace.
+ * @return The system user manager. Since this implementation stores users
+ * in a dedicated workspace the system user manager is the same for all
+ * sessions irrespective of the workspace.
+ * @throws javax.jcr.RepositoryException If an error occurs.
+ */
+ protected UserManager getSystemUserManager(String workspaceName) throws RepositoryException {
+ return systemUserManager;
+ }
+
+ /**
+ * @param session The session for which to retrieve the membership cache.
+ * @return The membership cache.
+ * @throws RepositoryException If an error occurs.
+ */
+ protected MembershipCache getMembershipCache(SessionImpl session) throws RepositoryException {
+ if (session == systemSession || session instanceof SystemSession) {
+ // force creation of the membership cache within the corresponding uMgr
+ return null;
+ } else {
+ return ((UserManagerImpl) getSystemUserManager(session.getWorkspace().getName())).getMembershipCache();
+ }
+ }
+
+ /**
+ * Creates a {@link UserManagerImpl} for the given session. May be overridden
+ * to return a custom implementation.
+ *
+ * @param session session
+ * @return user manager
+ * @throws RepositoryException if an error occurs
+ */
+ protected UserManagerImpl createUserManager(SessionImpl session) throws RepositoryException {
+ UserManagerConfig umc = getConfig().getUserManagerConfig();
+ UserManagerImpl um;
+ if (umc != null) {
+ Class>[] paramTypes = new Class[] {
+ SessionImpl.class,
+ String.class,
+ Properties.class,
+ MembershipCache.class};
+ um = (UserManagerImpl) umc.getUserManager(UserManagerImpl.class,
+ paramTypes, session, adminId, umc.getParameters(), getMembershipCache(session));
+ } else {
+ um = new UserManagerImpl(session, adminId, null, getMembershipCache(session));
+ }
+
+ if (umc != null && !(session instanceof SystemSession)) {
+ AuthorizableAction[] actions = umc.getAuthorizableActions();
+ um.setAuthorizableActions(actions);
+ }
+ return um;
+ }
+
+ /**
+ * @param session The session used to create the principal manager.
+ * @return A new instance of PrincipalManagerImpl
+ * @throws javax.jcr.RepositoryException If an error occurs.
+ */
+ protected PrincipalManager createPrincipalManager(SessionImpl session) throws RepositoryException {
+ return new PrincipalManagerImpl(session, getPrincipalProviderRegistry().getProviders());
+ }
+
+ /**
+ * @return A nwe instance of WorkspaceAccessManagerImpl to be used as
+ * default workspace access manager if the configuration doesn't specify one.
+ */
+ protected WorkspaceAccessManager createDefaultWorkspaceAccessManager() {
+ return new WorkspaceAccessManagerImpl();
+ }
+
+ /**
+ * Creates the default principal provider used to create the
+ * {@link PrincipalProviderRegistry}.
+ *
+ * @return An new instance of DefaultPrincipalProvider.
+ * @throws RepositoryException If an error occurs.
+ */
+ protected PrincipalProvider createDefaultPrincipalProvider(Properties[] moduleConfig) throws RepositoryException {
+ boolean initialized = false;
+ PrincipalProvider defaultPP = new DefaultPrincipalProvider(this.systemSession, (UserManagerImpl) systemUserManager);
+ for (Properties props : moduleConfig) {
+ //GRANITE-4470: apply config to DefaultPrincipalProvider if there is no explicit PrincipalProvider configured
+ if (!props.containsKey(LoginModuleConfig.PARAM_PRINCIPAL_PROVIDER_CLASS) && props.containsKey(AbstractPrincipalProvider.MAXSIZE_KEY)) {
+ defaultPP.init(props);
+ initialized = true;
+ break;
+ }
+ }
+ if (!initialized) {
+ defaultPP.init(new Properties());
+ }
+ return defaultPP;
+ }
+
+ /**
+ * @return The PrincipalProviderRegistry created during initialization.
+ */
+ protected PrincipalProviderRegistry getPrincipalProviderRegistry() {
+ return principalProviderRegistry;
+ }
+
+ /**
+ * @return The AuthContextProvider created during initialization.
+ */
+ protected AuthContextProvider getAuthContextProvider() {
+ return authContextProvider;
+ }
+
+ /**
+ * Throws IllegalStateException if this manager hasn't been
+ * initialized.
+ */
+ protected void checkInitialized() {
+ if (!initialized) {
+ throw new IllegalStateException("Not initialized");
+ }
+ }
+
+ /**
+ * @return The system session used to initialize this SecurityManager.
+ */
+ protected Session getSystemSession() {
+ return systemSession;
+ }
+
+ /**
+ * @return The repository used to initialize this SecurityManager.
+ */
+ protected Repository getRepository() {
+ return repository;
+ }
+ //--------------------------------------------------------------------------
+ /**
+ * Returns the access control provider for the specified
+ * workspaceName.
+ *
+ * @param workspaceName Name of the workspace.
+ * @return access control provider
+ * @throws NoSuchWorkspaceException If no workspace with 'workspaceName' exists.
+ * @throws RepositoryException
+ */
+ private AccessControlProvider getAccessControlProvider(String workspaceName)
+ throws NoSuchWorkspaceException, RepositoryException {
+ checkInitialized();
+ AccessControlProvider provider = acProviders.get(workspaceName);
+ if (provider == null || !provider.isLive()) {
+ // mark this workspace as 'active' so the workspace does not
+ // get disposed by the workspace-janitor
+ // TODO: There should be a cleaner way to do this.
+ repository.markWorkspaceActive(workspaceName);
+
+ WorkspaceSecurityConfig secConf = null;
+ WorkspaceConfig conf =
+ repository.getConfig().getWorkspaceConfig(workspaceName);
+ if (conf != null) {
+ secConf = conf.getSecurityConfig();
+ }
+
+ provider = acProviderFactory.createProvider(
+ repository.getSystemSession(workspaceName), secConf);
+ synchronized (acProviders) {
+ acProviders.put(workspaceName, provider);
+ }
+ }
+ return provider;
+ }
+
+ /**
+ * Make sure the system users (admin and anonymous) exist.
+ *
+ * @param userManager Manager to create users/groups.
+ * @param session The editing session.
+ * @param adminId UserID of the administrator.
+ * @param anonymousId UserID of the anonymous user.
+ * @throws RepositoryException If an error occurs.
+ */
+ static void createSystemUsers(UserManager userManager,
+ SystemSession session,
+ String adminId,
+ String anonymousId) throws RepositoryException {
+
+ Authorizable admin;
+ if (adminId != null) {
+ admin = userManager.getAuthorizable(adminId);
+ if (admin == null) {
+ userManager.createUser(adminId, adminId);
+ if (!userManager.isAutoSave()) {
+ session.save();
+ }
+ log.info("... created admin-user with id \'" + adminId + "\' ...");
+ }
+ }
+
+ if (anonymousId != null) {
+ Authorizable anonymous = userManager.getAuthorizable(anonymousId);
+ if (anonymous == null) {
+ try {
+ userManager.createUser(anonymousId, "");
+ if (!userManager.isAutoSave()) {
+ session.save();
+ }
+ log.info("... created anonymous user with id \'" + anonymousId + "\' ...");
+ } catch (RepositoryException e) {
+ // exception while creating the anonymous user.
+ // log an error but don't abort the repository start-up
+ log.error("Failed to create anonymous user.", e);
+ }
+ }
+ }
+ }
+
+ //------------------------------------------------------< inner classes >---
+ /**
+ * WorkspaceAccessManager that upon {@link #grants(Set principals, String)}
+ * evaluates if access to the root node of a workspace with the specified
+ * name is granted.
+ */
+ private final class WorkspaceAccessManagerImpl implements SecurityConstants, WorkspaceAccessManager {
+
+ //-----------------------------------------< WorkspaceAccessManager >---
+ /**
+ * {@inheritDoc}
+ */
+ public void init(Session systemSession) throws RepositoryException {
+ // nothing to do here.
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void close() throws RepositoryException {
+ // nothing to do here.
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean grants(Set principals, String workspaceName) throws RepositoryException {
+ AccessControlProvider prov = getAccessControlProvider(workspaceName);
+ return prov.canAccessRoot(principals);
+ }
+ }
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/HierarchyManager.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/HierarchyManager.java
new file mode 100644
index 00000000000..9daaed6bc7b
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/HierarchyManager.java
@@ -0,0 +1,208 @@
+/*
+ * 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.jackrabbit.core;
+
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.id.ItemId;
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.id.PropertyId;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+
+/**
+ * The HierarchyManager interface ...
+ */
+public interface HierarchyManager {
+
+ /**
+ * Resolves a path into an item id.
+ *
+ * If there is both a node and a property at the specified path, this method
+ * will return the id of the node.
+ *
+ * Note that, for performance reasons, this method returns null
+ * rather than throwing a PathNotFoundException if there's no
+ * item to be found at path.
+ *
+ * @deprecated As of JSR 283, a Path doesn't anymore uniquely
+ * identify an Item, therefore {@link #resolveNodePath(Path)} and
+ * {@link #resolvePropertyPath(Path)} should be used instead.
+ *
+ * @param path path to resolve
+ * @return item id referred to by path or null
+ * if there's no item at path.
+ * @throws RepositoryException if an error occurs
+ */
+ ItemId resolvePath(Path path) throws RepositoryException;
+
+ /**
+ * Resolves a path into a node id.
+ *
+ * Note that, for performance reasons, this method returns null
+ * rather than throwing a PathNotFoundException if there's no
+ * node to be found at path.
+ *
+ * @param path path to resolve
+ * @return node id referred to by path or null
+ * if there's no node at path.
+ * @throws RepositoryException if an error occurs
+ */
+ NodeId resolveNodePath(Path path) throws RepositoryException;
+
+ /**
+ * Resolves a path into a property id.
+ *
+ * Note that, for performance reasons, this method returns null
+ * rather than throwing a PathNotFoundException if there's no
+ * property to be found at path.
+ *
+ * @param path path to resolve
+ * @return property id referred to by path or null
+ * if there's no property at path.
+ * @throws RepositoryException if an error occurs
+ */
+ PropertyId resolvePropertyPath(Path path) throws RepositoryException;
+
+ /**
+ * Returns the path to the given item.
+ * @param id
+ * @return
+ * @throws ItemNotFoundException
+ * @throws RepositoryException
+ */
+ Path getPath(ItemId id) throws ItemNotFoundException, RepositoryException;
+
+ /**
+ * Returns the name of the specified item.
+ * @param id id of item whose name should be returned
+ * @return
+ * @throws ItemNotFoundException
+ * @throws RepositoryException
+ */
+ Name getName(ItemId id) throws ItemNotFoundException, RepositoryException;
+
+ /**
+ * Returns the name of the specified item, with the given parent id. If the
+ * given item is not shareable, this is identical to {@link #getName(ItemId)}.
+ *
+ * @param id node id
+ * @param parentId parent node id
+ * @return name
+ * @throws ItemNotFoundException
+ * @throws RepositoryException
+ */
+ Name getName(NodeId id, NodeId parentId)
+ throws ItemNotFoundException, RepositoryException;
+
+ /**
+ * Returns the depth of the specified item which is equivalent to
+ * getPath(id).getAncestorCount(). The depth reflects the
+ * absolute hierarchy level.
+ *
+ * @param id item id
+ * @return the depth of the specified item
+ * @throws ItemNotFoundException if the specified id does not
+ * denote an existing item.
+ * @throws RepositoryException if another error occurs
+ */
+ int getDepth(ItemId id) throws ItemNotFoundException, RepositoryException;
+
+ /**
+ * Returns the depth of the specified descendant relative to the given
+ * ancestor. If ancestorId and descendantId
+ * denote the same item 0 is returned. If ancestorId does not
+ * denote an ancestor -1 is returned.
+ *
+ * @param ancestorId ancestor id
+ * @param descendantId descendant id
+ * @return the relative depth; -1 if ancestorId does not
+ * denote an ancestor of the item denoted by descendantId
+ * (or itself).
+ * @throws ItemNotFoundException if either of the specified id's does not
+ * denote an existing item.
+ * @throws RepositoryException if another error occurs
+ */
+ int getRelativeDepth(NodeId ancestorId, ItemId descendantId)
+ throws ItemNotFoundException, RepositoryException;
+
+ /**
+ * Determines whether the node with the specified nodeId
+ * is an ancestor of the item denoted by the given itemId.
+ * This is equivalent to
+ * getPath(nodeId).isAncestorOf(getPath(itemId)).
+ *
+ * @param nodeId node id
+ * @param itemId item id
+ * @return true if the node with the specified
+ * nodeId is an ancestor of the item denoted by the
+ * given itemIdfalse
otherwise
+ * @throws ItemNotFoundException if any of the specified id's does not
+ * denote an existing item.
+ * @throws RepositoryException if another error occurs
+ */
+ boolean isAncestor(NodeId nodeId, ItemId itemId)
+ throws ItemNotFoundException, RepositoryException;
+
+ //------------------------------------------- operation with shareable nodes
+
+ /**
+ * Determines whether the node with the specified ancestor
+ * is a share ancestor of the item denoted by the given descendant.
+ * This is true for two nodes A, B
+ * if either:
+ *
+ *
A is a (proper) ancestor of B
+ *
there is a non-empty sequence of nodes N1,...
+ * ,Nk such that A=
+ * N1 and B=Nk
+ * and Ni is the parent or a share-parent of
+ * Ni+1 (for every i in 1
+ * ...k-1.
+ *
+ *
+ * @param ancestor node id
+ * @param descendant item id
+ * @return true if the node denoted by ancestor
+ * is a share ancestor of the item denoted by descendant,
+ * false otherwise
+ * @throws ItemNotFoundException if any of the specified id's does not
+ * denote an existing item.
+ * @throws RepositoryException if another error occurs
+ */
+ boolean isShareAncestor(NodeId ancestor, NodeId descendant)
+ throws ItemNotFoundException, RepositoryException;
+
+ /**
+ * Returns the depth of the specified share-descendant relative to the given
+ * share-ancestor. If ancestor and descendant
+ * denote the same item, 0 is returned. If ancestor
+ * does not denote an share-ancestor -1 is returned.
+ *
+ * @param ancestorId ancestor id
+ * @param descendantId descendant id
+ * @return the relative depth; -1 if ancestor does
+ * not denote a share-ancestor of the item denoted by descendant
+ * (or itself).
+ * @throws ItemNotFoundException if either of the specified id's does not
+ * denote an existing item.
+ * @throws RepositoryException if another error occurs
+ */
+ int getShareRelativeDepth(NodeId ancestorId, ItemId descendantId)
+ throws ItemNotFoundException, RepositoryException;
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/HierarchyManagerImpl.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/HierarchyManagerImpl.java
new file mode 100644
index 00000000000..c4ccf3d97b8
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/HierarchyManagerImpl.java
@@ -0,0 +1,687 @@
+/*
+ * 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.jackrabbit.core;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.id.ItemId;
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.id.PropertyId;
+import org.apache.jackrabbit.core.state.ChildNodeEntry;
+import org.apache.jackrabbit.core.state.ItemState;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.ItemStateManager;
+import org.apache.jackrabbit.core.state.NoSuchItemStateException;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.PropertyState;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.commons.conversion.MalformedPathException;
+import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
+import org.apache.jackrabbit.spi.commons.name.PathBuilder;
+import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * HierarchyManagerImpl ...
+ */
+public class HierarchyManagerImpl implements HierarchyManager {
+
+ private static Logger log = LoggerFactory.getLogger(HierarchyManagerImpl.class);
+
+ /**
+ * The parent name returned for orphaned or root nodes.
+ * TODO: Is it proper to use an invalid Name for this.
+ */
+ private static final Name EMPTY_NAME = NameFactoryImpl.getInstance().create("", "");
+
+ protected final NodeId rootNodeId;
+ protected final ItemStateManager provider;
+
+ /**
+ * Flags describing what items to return in {@link #resolvePath(Path, int)}.
+ */
+ static final int RETURN_NODE = 1;
+ static final int RETURN_PROPERTY = 2;
+ static final int RETURN_ANY = (RETURN_NODE | RETURN_PROPERTY);
+
+ public HierarchyManagerImpl(NodeId rootNodeId,
+ ItemStateManager provider) {
+ this.rootNodeId = rootNodeId;
+ this.provider = provider;
+ }
+
+ public NodeId getRootNodeId() {
+ return rootNodeId;
+ }
+
+ //-------------------------------------------------------< implementation >
+
+ /**
+ * Internal implementation that iteratively resolves a path into an item.
+ *
+ * @param elements path elements
+ * @param next index of next item in elements to inspect
+ * @param id id of item at path elements[0]..elements[next - 1]
+ * @param typesAllowed one of RETURN_ANY, RETURN_NODE
+ * or RETURN_PROPERTY
+ * @return id or null
+ * @throws ItemStateException if an intermediate item state is not found
+ * @throws MalformedPathException if building an intermediate path fails
+ */
+ protected ItemId resolvePath(Path.Element[] elements, int next,
+ ItemId id, int typesAllowed)
+ throws ItemStateException, MalformedPathException {
+
+ PathBuilder builder = new PathBuilder();
+ for (int i = 0; i < next; i++) {
+ builder.addLast(elements[i]);
+ }
+ for (int i = next; i < elements.length; i++) {
+ Path.Element elem = elements[i];
+ NodeId parentId = (NodeId) id;
+ id = null;
+
+ Name name = elem.getName();
+ int index = elem.getIndex();
+ if (index == 0) {
+ index = 1;
+ }
+ int typeExpected = typesAllowed;
+ if (i < elements.length - 1) {
+ // intermediate items must always be nodes
+ typeExpected = RETURN_NODE;
+ }
+ NodeState parentState = (NodeState) getItemState(parentId);
+ if ((typeExpected & RETURN_NODE) != 0) {
+ ChildNodeEntry nodeEntry =
+ getChildNodeEntry(parentState, name, index);
+ if (nodeEntry != null) {
+ id = nodeEntry.getId();
+ }
+ }
+ if (id == null && (typeExpected & RETURN_PROPERTY) != 0) {
+ if (parentState.hasPropertyName(name) && (index <= 1)) {
+ // property
+ id = new PropertyId(parentState.getNodeId(), name);
+ }
+ }
+ if (id == null) {
+ break;
+ }
+ builder.addLast(elements[i]);
+ pathResolved(id, builder);
+ }
+ return id;
+ }
+
+ //---------------------------------------------------------< overridables >
+ /**
+ * Return an item state, given its item id.
+ *
+ * Low-level hook provided for specialized derived classes.
+ *
+ * @param id item id
+ * @return item state
+ * @throws NoSuchItemStateException if the item does not exist
+ * @throws ItemStateException if an error occurs
+ * @see ZombieHierarchyManager#getItemState(ItemId)
+ */
+ protected ItemState getItemState(ItemId id)
+ throws NoSuchItemStateException, ItemStateException {
+ return provider.getItemState(id);
+ }
+
+ /**
+ * Determines whether an item state for a given item id exists.
+ *
+ * Low-level hook provided for specialized derived classes.
+ *
+ * @param id item id
+ * @return true if an item state exists, otherwise
+ * false
+ * @see ZombieHierarchyManager#hasItemState(ItemId)
+ */
+ protected boolean hasItemState(ItemId id) {
+ return provider.hasItemState(id);
+ }
+
+ /**
+ * Returns the parentUUID of the given item.
+ *
+ * Low-level hook provided for specialized derived classes.
+ *
+ * @param state item state
+ * @return parentUUID of the given item
+ * @see ZombieHierarchyManager#getParentId(ItemState)
+ */
+ protected NodeId getParentId(ItemState state) {
+ return state.getParentId();
+ }
+
+ /**
+ * Return all parents of a node. A shareable node has possibly more than
+ * one parent.
+ *
+ * @param state item state
+ * @param useOverlayed whether to use overlayed state for shareable nodes
+ * @return set of parent NodeIds. If state has no parent,
+ * array has length 0.
+ */
+ protected Set getParentIds(ItemState state, boolean useOverlayed) {
+ if (state.isNode()) {
+ // if this is a node, quickly check whether it is shareable and
+ // whether it contains more than one parent
+ NodeState ns = (NodeState) state;
+ if (ns.isShareable() && useOverlayed && ns.hasOverlayedState()) {
+ ns = (NodeState) ns.getOverlayedState();
+ }
+ Set s = ns.getSharedSet();
+ if (s.size() > 1) {
+ return s;
+ }
+ }
+ NodeId parentId = getParentId(state);
+ if (parentId != null) {
+ LinkedHashSet s = new LinkedHashSet();
+ s.add(parentId);
+ return s;
+ }
+ return Collections.emptySet();
+ }
+
+ /**
+ * Returns the ChildNodeEntry of parent with the
+ * specified uuid or null if there's no such entry.
+ *
+ * Low-level hook provided for specialized derived classes.
+ *
+ * @param parent node state
+ * @param id id of child node entry
+ * @return the ChildNodeEntry of parent with
+ * the specified uuid or null if there's
+ * no such entry.
+ * @see ZombieHierarchyManager#getChildNodeEntry(NodeState, NodeId)
+ */
+ protected ChildNodeEntry getChildNodeEntry(NodeState parent,
+ NodeId id) {
+ return parent.getChildNodeEntry(id);
+ }
+
+ /**
+ * Returns the ChildNodeEntry of parent with the
+ * specified name and index or null
+ * if there's no such entry.
+ *
+ * Low-level hook provided for specialized derived classes.
+ *
+ * @param parent node state
+ * @param name name of child node entry
+ * @param index index of child node entry
+ * @return the ChildNodeEntry of parent with
+ * the specified name and index or
+ * null if there's no such entry.
+ * @see ZombieHierarchyManager#getChildNodeEntry(NodeState, Name, int)
+ */
+ protected ChildNodeEntry getChildNodeEntry(NodeState parent,
+ Name name,
+ int index) {
+ return parent.getChildNodeEntry(name, index);
+ }
+
+ /**
+ * Adds the path element of an item id to the path currently being built.
+ * Recursively invoked method that may be overridden by some subclass to
+ * either return cached responses or add response to cache. On exit,
+ * builder contains the path of state.
+ *
+ * @param builder builder currently being used
+ * @param state item to find path of
+ * @param detector path cycle detector
+ */
+ protected void buildPath(
+ PathBuilder builder, ItemState state, CycleDetector detector)
+ throws ItemStateException, RepositoryException {
+
+ // shortcut
+ if (state.getId().equals(rootNodeId)) {
+ builder.addRoot();
+ return;
+ }
+
+ NodeId parentId = getParentId(state);
+ if (parentId == null) {
+ String msg = "failed to build path of " + state.getId()
+ + ": orphaned item";
+ log.debug(msg);
+ throw new ItemNotFoundException(msg);
+ } else if (detector.checkCycle(parentId)) {
+ throw new InvalidItemStateException(
+ "Path cycle detected: " + parentId);
+ }
+
+ NodeState parent = (NodeState) getItemState(parentId);
+ // recursively build path of parent
+ buildPath(builder, parent, detector);
+
+ if (state.isNode()) {
+ NodeState nodeState = (NodeState) state;
+ NodeId id = nodeState.getNodeId();
+ ChildNodeEntry entry = getChildNodeEntry(parent, id);
+ if (entry == null) {
+ String msg = "failed to build path of " + state.getId() + ": "
+ + parent.getNodeId() + " has no child entry for "
+ + id;
+ log.debug(msg);
+ throw new ItemNotFoundException(msg);
+ }
+ // add to path
+ if (entry.getIndex() == 1) {
+ builder.addLast(entry.getName());
+ } else {
+ builder.addLast(entry.getName(), entry.getIndex());
+ }
+ } else {
+ PropertyState propState = (PropertyState) state;
+ Name name = propState.getName();
+ // add to path
+ builder.addLast(name);
+ }
+ }
+
+ /**
+ * Internal implementation of {@link #resolvePath(Path)} that will either
+ * resolve to a node or a property. Should be overridden by a subclass
+ * that can resolve an intermediate path into an ItemId. This
+ * subclass can then invoke {@link #resolvePath(org.apache.jackrabbit.spi.Path.Element[], int, ItemId, int)}
+ * with a value of next greater than 1.
+ *
+ * @param path path to resolve
+ * @param typesAllowed one of RETURN_ANY, RETURN_NODE
+ * or RETURN_PROPERTY
+ * @return id or null
+ * @throws RepositoryException if an error occurs
+ */
+ protected ItemId resolvePath(Path path, int typesAllowed)
+ throws RepositoryException {
+
+ Path.Element[] elements = path.getElements();
+ ItemId id = rootNodeId;
+
+ try {
+ return resolvePath(elements, 1, id, typesAllowed);
+ } catch (ItemStateException e) {
+ String msg = "failed to retrieve state of intermediary node";
+ log.debug(msg);
+ throw new RepositoryException(msg, e);
+ }
+ }
+
+ /**
+ * Called by {@link #resolvePath(org.apache.jackrabbit.spi.Path.Element[], int, ItemId, int)}.
+ * May be overridden by some subclass to process/cache intermediate state.
+ *
+ * @param id id of resolved item
+ * @param builder path builder containing path resolved
+ * @throws MalformedPathException if the path contained in builder
+ * is malformed
+ */
+ protected void pathResolved(ItemId id, PathBuilder builder)
+ throws MalformedPathException {
+
+ // do nothing
+ }
+
+ //-----------------------------------------------------< HierarchyManager >
+
+ /**
+ * {@inheritDoc}
+ */
+ public final ItemId resolvePath(Path path) throws RepositoryException {
+ // shortcut
+ if (path.denotesRoot()) {
+ return rootNodeId;
+ }
+ if (!path.isCanonical()) {
+ String msg = "path is not canonical";
+ log.debug(msg);
+ throw new RepositoryException(msg);
+ }
+ return resolvePath(path, RETURN_ANY);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public NodeId resolveNodePath(Path path) throws RepositoryException {
+ return (NodeId) resolvePath(path, RETURN_NODE);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public PropertyId resolvePropertyPath(Path path) throws RepositoryException {
+ return (PropertyId) resolvePath(path, RETURN_PROPERTY);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Path getPath(ItemId id)
+ throws ItemNotFoundException, RepositoryException {
+ // shortcut
+ if (id.equals(rootNodeId)) {
+ return PathFactoryImpl.getInstance().getRootPath();
+ }
+
+ PathBuilder builder = new PathBuilder();
+
+ try {
+ buildPath(builder, getItemState(id), new CycleDetector());
+ return builder.getPath();
+ } catch (NoSuchItemStateException nsise) {
+ String msg = "failed to build path of " + id;
+ log.debug(msg);
+ throw new ItemNotFoundException(msg, nsise);
+ } catch (ItemStateException ise) {
+ String msg = "failed to build path of " + id;
+ log.debug(msg);
+ throw new RepositoryException(msg, ise);
+ } catch (MalformedPathException mpe) {
+ String msg = "failed to build path of " + id;
+ log.debug(msg);
+ throw new RepositoryException(msg, mpe);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Name getName(ItemId itemId)
+ throws ItemNotFoundException, RepositoryException {
+ if (itemId.denotesNode()) {
+ NodeId nodeId = (NodeId) itemId;
+ try {
+ NodeState nodeState = (NodeState) getItemState(nodeId);
+ NodeId parentId = getParentId(nodeState);
+ if (parentId == null) {
+ // this is the root or an orphaned node
+ // FIXME
+ return EMPTY_NAME;
+ }
+ return getName(nodeId, parentId);
+ } catch (NoSuchItemStateException nsis) {
+ String msg = "failed to resolve name of " + nodeId;
+ log.debug(msg);
+ throw new ItemNotFoundException(nodeId.toString());
+ } catch (ItemStateException ise) {
+ String msg = "failed to resolve name of " + nodeId;
+ log.debug(msg);
+ throw new RepositoryException(msg, ise);
+ }
+ } else {
+ return ((PropertyId) itemId).getName();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Name getName(NodeId id, NodeId parentId)
+ throws ItemNotFoundException, RepositoryException {
+
+ NodeState parentState;
+
+ try {
+ parentState = (NodeState) getItemState(parentId);
+ } catch (NoSuchItemStateException nsis) {
+ String msg = "failed to resolve name of " + id;
+ log.debug(msg);
+ throw new ItemNotFoundException(id.toString());
+ } catch (ItemStateException ise) {
+ String msg = "failed to resolve name of " + id;
+ log.debug(msg);
+ throw new RepositoryException(msg, ise);
+ }
+
+ ChildNodeEntry entry =
+ getChildNodeEntry(parentState, id);
+ if (entry == null) {
+ String msg = "failed to resolve name of " + id;
+ log.debug(msg);
+ throw new ItemNotFoundException(msg);
+ }
+ return entry.getName();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getDepth(ItemId id)
+ throws ItemNotFoundException, RepositoryException {
+ // shortcut
+ if (id.equals(rootNodeId)) {
+ return 0;
+ }
+ try {
+ ItemState state = getItemState(id);
+ NodeId parentId = getParentId(state);
+ int depth = 0;
+ while (parentId != null) {
+ depth++;
+ state = getItemState(parentId);
+ parentId = getParentId(state);
+ }
+ return depth;
+ } catch (NoSuchItemStateException nsise) {
+ String msg = "failed to determine depth of " + id;
+ log.debug(msg);
+ throw new ItemNotFoundException(msg, nsise);
+ } catch (ItemStateException ise) {
+ String msg = "failed to determine depth of " + id;
+ log.debug(msg);
+ throw new RepositoryException(msg, ise);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getRelativeDepth(NodeId ancestorId, ItemId descendantId)
+ throws ItemNotFoundException, RepositoryException {
+ if (ancestorId.equals(descendantId)) {
+ return 0;
+ }
+ int depth = 1;
+ try {
+ ItemState state = getItemState(descendantId);
+ NodeId parentId = getParentId(state);
+ while (parentId != null) {
+ if (parentId.equals(ancestorId)) {
+ return depth;
+ }
+ depth++;
+ state = getItemState(parentId);
+ parentId = getParentId(state);
+ }
+ // not an ancestor
+ return -1;
+ } catch (NoSuchItemStateException nsise) {
+ String msg = "failed to determine depth of " + descendantId
+ + " relative to " + ancestorId;
+ log.debug(msg);
+ throw new ItemNotFoundException(msg, nsise);
+ } catch (ItemStateException ise) {
+ String msg = "failed to determine depth of " + descendantId
+ + " relative to " + ancestorId;
+ log.debug(msg);
+ throw new RepositoryException(msg, ise);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isAncestor(NodeId nodeId, ItemId itemId)
+ throws ItemNotFoundException, RepositoryException {
+ if (nodeId.equals(itemId)) {
+ // can't be ancestor of self
+ return false;
+ }
+ try {
+ ItemState state = getItemState(itemId);
+ NodeId parentId = getParentId(state);
+ while (parentId != null) {
+ if (parentId.equals(nodeId)) {
+ return true;
+ }
+ state = getItemState(parentId);
+ parentId = getParentId(state);
+ }
+ // not an ancestor
+ return false;
+ } catch (NoSuchItemStateException nsise) {
+ String msg = "failed to determine degree of relationship of "
+ + nodeId + " and " + itemId;
+ log.debug(msg);
+ throw new ItemNotFoundException(msg, nsise);
+ } catch (ItemStateException ise) {
+ String msg = "failed to determine degree of relationship of "
+ + nodeId + " and " + itemId;
+ log.debug(msg);
+ throw new RepositoryException(msg, ise);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isShareAncestor(NodeId ancestor, NodeId descendant)
+ throws ItemNotFoundException, RepositoryException {
+ if (ancestor.equals(descendant)) {
+ // can't be ancestor of self
+ return false;
+ }
+ try {
+ ItemState state = getItemState(descendant);
+ Set parentIds = getParentIds(state, false);
+ while (parentIds.size() > 0) {
+ if (parentIds.contains(ancestor)) {
+ return true;
+ }
+ Set grandparentIds = new LinkedHashSet();
+ for (NodeId parentId : parentIds) {
+ grandparentIds.addAll(getParentIds(getItemState(parentId), false));
+ }
+ parentIds = grandparentIds;
+ }
+ // not an ancestor
+ return false;
+ } catch (NoSuchItemStateException nsise) {
+ String msg = "failed to determine degree of relationship of "
+ + ancestor + " and " + descendant;
+ log.debug(msg);
+ throw new ItemNotFoundException(msg, nsise);
+ } catch (ItemStateException ise) {
+ String msg = "failed to determine degree of relationship of "
+ + ancestor + " and " + descendant;
+ log.debug(msg);
+ throw new RepositoryException(msg, ise);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getShareRelativeDepth(NodeId ancestor, ItemId descendant)
+ throws ItemNotFoundException, RepositoryException {
+
+ if (ancestor.equals(descendant)) {
+ return 0;
+ }
+ int depth = 1;
+ try {
+ ItemState state = getItemState(descendant);
+ Set parentIds = getParentIds(state, true);
+ while (parentIds.size() > 0) {
+ if (parentIds.contains(ancestor)) {
+ return depth;
+ }
+ depth++;
+ Set grandparentIds = new LinkedHashSet();
+ for (NodeId parentId : parentIds) {
+ state = getItemState(parentId);
+ grandparentIds.addAll(getParentIds(state, true));
+ }
+ parentIds = grandparentIds;
+ }
+ // not an ancestor
+ return -1;
+ } catch (NoSuchItemStateException nsise) {
+ String msg = "failed to determine degree of relationship of "
+ + ancestor + " and " + descendant;
+ log.debug(msg);
+ throw new ItemNotFoundException(msg, nsise);
+ } catch (ItemStateException ise) {
+ String msg = "failed to determine degree of relationship of "
+ + ancestor + " and " + descendant;
+ log.debug(msg);
+ throw new RepositoryException(msg, ise);
+ }
+ }
+
+ /**
+ * Utility class used to detect path cycles with as little overhead
+ * as possible. The {@link #checkCycle(ItemId)} method is called for
+ * each path element as the
+ * {@link HierarchyManagerImpl#buildPath(PathBuilder, ItemState, CycleDetector)}
+ * method walks up the hierarchy. At first, during the first fifteen
+ * path elements, the detector does nothing in order to avoid
+ * introducing any unnecessary overhead to normal paths that seldom
+ * are deeper than that. After that initial threshold all item
+ * identifiers along the path are tracked, and a cycle is reported
+ * if an identifier is encountered that already occurred along the
+ * same path.
+ */
+ protected static class CycleDetector {
+
+ private int count = 0;
+
+ private Set ids;
+
+ boolean checkCycle(ItemId id) throws InvalidItemStateException {
+ if (count++ >= 15) {
+ if (ids == null) {
+ ids = new HashSet();
+ } else {
+ return !ids.add(id);
+ }
+ }
+ return false;
+ }
+
+ }
+
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemData.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemData.java
new file mode 100644
index 00000000000..e9815eaf6b1
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemData.java
@@ -0,0 +1,168 @@
+/*
+ * 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.jackrabbit.core;
+
+import javax.jcr.nodetype.ItemDefinition;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.id.ItemId;
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.state.ItemState;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.PropertyState;
+
+/**
+ * Data object referenced by different ItemImpl instances that
+ * all represent the same item, i.e. items having the same ItemId.
+ */
+public abstract class ItemData {
+
+ /** Associated item id */
+ private final ItemId id;
+
+ /** Associated item state */
+ private ItemState state;
+
+ /** Associated item definition */
+ private ItemDefinition definition;
+
+ /** Status */
+ private int status;
+
+ /** The item manager */
+ private ItemManager itemMgr;
+
+ /**
+ * Create a new instance of this class.
+ *
+ * @param state item state
+ * @param itemMgr item manager
+ */
+ protected ItemData(ItemState state, ItemManager itemMgr) {
+ this.id = state.getId();
+ this.state = state;
+ this.itemMgr = itemMgr;
+ this.status = ItemImpl.STATUS_NORMAL;
+ }
+
+ /**
+ * Create a new instance of this class.
+ *
+ * @param id item id
+ */
+ protected ItemData(ItemId id) {
+ this.id = id;
+ this.status = ItemImpl.STATUS_NORMAL;
+ }
+
+ /**
+ * Return the associated item state.
+ *
+ * @return item state
+ */
+ public ItemState getState() {
+ return state;
+ }
+
+ /**
+ * Set the associated item state.
+ *
+ * @param state item state
+ */
+ protected void setState(ItemState state) {
+ this.state = state;
+ }
+
+ /**
+ * Return the associated item definition.
+ *
+ * @return item definition
+ * @throws RepositoryException if the definition cannot be retrieved.
+ */
+ public ItemDefinition getDefinition() throws RepositoryException {
+ if (definition == null && itemMgr != null) {
+ if (isNode()) {
+ definition = itemMgr.getDefinition((NodeState) state);
+ } else {
+ definition = itemMgr.getDefinition((PropertyState) state);
+ }
+ }
+ return definition;
+ }
+
+ /**
+ * Set the associated item definition.
+ *
+ * @param definition item definition
+ */
+ protected void setDefinition(ItemDefinition definition) {
+ this.definition = definition;
+ }
+
+ /**
+ * Return the status.
+ *
+ * @return status
+ */
+ public int getStatus() {
+ return status;
+ }
+
+ /**
+ * Set the status.
+ *
+ * @param status
+ */
+ protected void setStatus(int status) {
+ this.status = status;
+ }
+
+ /**
+ * Return a flag indicating whether item is a node.
+ *
+ * @return true if this item is a node;
+ * false otherwise.
+ */
+ public boolean isNode() {
+ return false;
+ }
+
+ /**
+ * Return the id associated with this item.
+ *
+ * @return item id
+ */
+ public ItemId getId() {
+ return id;
+ }
+
+ /**
+ * Return the parent id of this item.
+ *
+ * @return parent id
+ */
+ public NodeId getParentId() {
+ return getState().getParentId();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String toString() {
+ return getId().toString();
+ }
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java
new file mode 100644
index 00000000000..858cf3db2ed
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemImpl.java
@@ -0,0 +1,451 @@
+/*
+ * 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.jackrabbit.core;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.Item;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.ItemVisitor;
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+
+import org.apache.jackrabbit.core.id.ItemId;
+import org.apache.jackrabbit.core.session.SessionContext;
+import org.apache.jackrabbit.core.session.SessionOperation;
+import org.apache.jackrabbit.core.state.ItemState;
+import org.apache.jackrabbit.core.state.SessionItemStateManager;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.value.ValueHelper;
+
+/**
+ * ItemImpl implements the Item interface.
+ */
+public abstract class ItemImpl implements Item {
+
+ protected static final int STATUS_NORMAL = 0;
+ protected static final int STATUS_MODIFIED = 1;
+ protected static final int STATUS_DESTROYED = 2;
+ protected static final int STATUS_INVALIDATED = 3;
+
+ protected final ItemId id;
+
+ /**
+ * The component context of the session to which this item is associated.
+ */
+ protected final SessionContext sessionContext;
+
+ /**
+ * Item data associated with this item.
+ */
+ protected final ItemData data;
+
+ /**
+ * ItemManager that created this Item
+ */
+ protected final ItemManager itemMgr;
+
+ /**
+ * SessionItemStateManager associated with this Item
+ */
+ protected final SessionItemStateManager stateMgr;
+
+ /**
+ * Package private constructor.
+ *
+ * @param itemMgr the ItemManager that created this Item
+ * @param sessionContext the component context of the associated session
+ * @param data ItemData of this Item
+ */
+ ItemImpl(ItemManager itemMgr, SessionContext sessionContext, ItemData data) {
+ this.sessionContext = sessionContext;
+ this.stateMgr = sessionContext.getItemStateManager();
+ this.id = data.getId();
+ this.itemMgr = itemMgr;
+ this.data = data;
+ }
+
+ protected T perform(final SessionOperation operation)
+ throws RepositoryException {
+ itemSanityCheck();
+ return sessionContext.getSessionState().perform(operation);
+ }
+
+ /**
+ * Performs a sanity check on this item and the associated session.
+ *
+ * @throws RepositoryException if this item has been rendered invalid for some reason
+ */
+ protected void sanityCheck() throws RepositoryException {
+ // check session status
+ sessionContext.getSessionState().checkAlive();
+
+ // check status of this item for read operation
+ itemSanityCheck();
+ }
+
+ /**
+ * Checks the status of this item.
+ *
+ * @throws RepositoryException if this item no longer exists
+ */
+ protected void itemSanityCheck() throws RepositoryException {
+ // check status of this item for read operation
+ final int status = data.getStatus();
+ if (status == STATUS_DESTROYED || status == STATUS_INVALIDATED) {
+ throw new InvalidItemStateException(
+ "Item does not exist anymore: " + id);
+ }
+ }
+
+ protected boolean isTransient() {
+ return getItemState().isTransient();
+ }
+
+ protected abstract ItemState getOrCreateTransientItemState() throws RepositoryException;
+
+ protected abstract void makePersistent() throws RepositoryException;
+
+ /**
+ * Marks this instance as 'removed' and notifies its listeners.
+ * The resulting state is either 'temporarily invalidated' or
+ * 'permanently invalidated', depending on the initial state.
+ *
+ * @throws RepositoryException if an error occurs
+ */
+ protected void setRemoved() throws RepositoryException {
+ final int status = data.getStatus();
+ if (status == STATUS_INVALIDATED || status == STATUS_DESTROYED) {
+ // this instance is already 'invalid', get outta here
+ return;
+ }
+
+ ItemState transientState = getOrCreateTransientItemState();
+ if (transientState.getStatus() == ItemState.STATUS_NEW) {
+ // this is a 'new' item, simply dispose the transient state
+ // (it is no longer used); this will indirectly (through
+ // stateDiscarded listener method) invalidate this instance permanently
+ stateMgr.disposeTransientItemState(transientState);
+ } else {
+ // this is an 'existing' item (i.e. it is backed by persistent
+ // state), mark it as 'removed'
+ transientState.setStatus(ItemState.STATUS_EXISTING_REMOVED);
+ // transfer the transient state to the attic
+ stateMgr.moveTransientItemStateToAttic(transientState);
+
+ // set state of this instance to 'invalid'
+ data.setStatus(STATUS_INVALIDATED);
+ // notify the manager that this instance has been
+ // temporarily invalidated
+ itemMgr.itemInvalidated(id, data);
+ }
+ }
+
+ /**
+ * Returns the item-state associated with this Item.
+ *
+ * @return state associated with this Item
+ */
+ ItemState getItemState() {
+ return data.getState();
+ }
+
+ /**
+ * Return the id of this Item.
+ *
+ * @return the id of this Item
+ */
+ public ItemId getId() {
+ return id;
+ }
+
+ /**
+ * Returns the primary path to this Item.
+ *
+ * @return the primary path to this Item
+ */
+ public Path getPrimaryPath() throws RepositoryException {
+ return sessionContext.getHierarchyManager().getPath(id);
+ }
+
+ /**
+ * Failsafe mapping of internal id to JCR path for use in
+ * diagnostic output, error messages etc.
+ *
+ * @return JCR path or some fallback value
+ */
+ public String safeGetJCRPath() {
+ return itemMgr.safeGetJCRPath(id);
+ }
+
+ /**
+ * Same as {@link Item#getName()} except that
+ * this method returns a Name instead of a
+ * String.
+ *
+ * @return the name of this item as Name
+ * @throws RepositoryException if an error occurs.
+ */
+ public abstract Name getQName() throws RepositoryException;
+
+ /**
+ * Utility method that converts the given string into a qualified JCR name.
+ *
+ * @param name name string
+ * @return qualified name
+ * @throws RepositoryException if the given name is invalid
+ */
+ protected Name getQName(String name) throws RepositoryException {
+ return sessionContext.getQName(name);
+ }
+
+ /**
+ * Utility method that returns the value factory of this session.
+ *
+ * @return value factory
+ * @throws RepositoryException if the value factory is not available
+ */
+ protected ValueFactory getValueFactory() throws RepositoryException {
+ return getSession().getValueFactory();
+ }
+
+ /**
+ * Utility method that converts the given strings into JCR values of the
+ * given type
+ *
+ * @param values value strings
+ * @param type value type
+ * @return JCR values
+ * @throws RepositoryException if the values can not be converted
+ */
+ protected Value[] getValues(String[] values, int type)
+ throws RepositoryException {
+ if (values != null) {
+ return ValueHelper.convert(values, type, getValueFactory());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Utility method that returns the type of the first of the given values,
+ * or {@link PropertyType#UNDEFINED} when given no values.
+ *
+ * @param values given values, or null
+ * @return value type, or {@link PropertyType#UNDEFINED}
+ */
+ protected int getType(Value[] values) {
+ if (values != null) {
+ for (Value value : values) {
+ if (value != null) {
+ return value.getType();
+ }
+ }
+ }
+ return PropertyType.UNDEFINED;
+ }
+
+ //-----------------------------------------------------------------< Item >
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract void accept(ItemVisitor visitor)
+ throws RepositoryException;
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract boolean isNode();
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract String getName() throws RepositoryException;
+
+ /**
+ * {@inheritDoc}
+ */
+ public abstract Node getParent()
+ throws ItemNotFoundException, AccessDeniedException, RepositoryException;
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isNew() {
+ final ItemState state = getItemState();
+ return state.isTransient() && state.getOverlayedState() == null;
+ }
+
+ /**
+ * checks if this item is new. running outside of transactions, this
+ * is the same as {@link #isNew()} but within a transaction an item can
+ * be saved but not yet persisted.
+ */
+ protected boolean isTransactionalNew() {
+ final ItemState state = getItemState();
+ return state.getStatus() == ItemState.STATUS_NEW;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isModified() {
+ final ItemState state = getItemState();
+ return state.isTransient() && state.getOverlayedState() != null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void remove() throws RepositoryException {
+ perform(new ItemRemoveOperation(this, true));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void save() throws RepositoryException {
+ perform(new ItemSaveOperation(getItemState()));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void refresh(boolean keepChanges) throws RepositoryException {
+ perform(new ItemRefreshOperation(getItemState(), keepChanges));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Item getAncestor(final int degree) throws RepositoryException {
+ return perform(new SessionOperation() {
+ public Item perform(SessionContext context)
+ throws RepositoryException {
+ if (degree == 0) {
+ return context.getItemManager().getRootNode();
+ }
+
+ try {
+ // Path.getAncestor requires relative degree, i.e. we need
+ // to convert absolute to relative ancestor degree
+ Path path = getPrimaryPath();
+ int relDegree = path.getAncestorCount() - degree;
+ if (relDegree < 0) {
+ throw new ItemNotFoundException();
+ } else if (relDegree == 0) {
+ return ItemImpl.this; // shortcut
+ }
+ Path ancestorPath = path.getAncestor(relDegree);
+ return context.getItemManager().getNode(ancestorPath);
+ } catch (PathNotFoundException e) {
+ throw new ItemNotFoundException("Ancestor not found", e);
+ }
+ }
+ public String toString() {
+ return "item.getAncestor(" + degree + ")";
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getPath() throws RepositoryException {
+ return perform(new SessionOperation() {
+ public String perform(SessionContext context)
+ throws RepositoryException {
+ return context.getJCRPath(getPrimaryPath());
+ }
+ public String toString() {
+ return "item.getPath()";
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getDepth() throws RepositoryException {
+ return perform(new SessionOperation() {
+ public Integer perform(SessionContext context)
+ throws RepositoryException {
+ ItemState state = getItemState();
+ if (state.getParentId() == null) {
+ return 0; // shortcut
+ } else {
+ return context.getHierarchyManager().getDepth(id);
+ }
+ }
+ public String toString() {
+ return "item.getDepth()";
+ }
+ });
+ }
+
+ /**
+ * Returns the session associated with this item.
+ *
+ * Since Jackrabbit 1.4 it is safe to use this method regardless
+ * of item state.
+ *
+ * @see Issue JCR-911
+ * @return current session
+ */
+ public Session getSession() {
+ return sessionContext.getSessionImpl();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isSame(Item otherItem) throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ if (this == otherItem) {
+ return true;
+ }
+ if (otherItem instanceof ItemImpl) {
+ ItemImpl other = (ItemImpl) otherItem;
+ return id.equals(other.id)
+ && getSession().getWorkspace().getName().equals(
+ other.getSession().getWorkspace().getName());
+ }
+ return false;
+ }
+
+ //--------------------------------------------------------------< Object >
+
+ /**
+ * Returns the({@link #safeGetJCRPath() safe}) path of this item for use
+ * in diagnostic output.
+ *
+ * @return "/path/to/item"
+ */
+ public String toString() {
+ return safeGetJCRPath();
+ }
+
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemLifeCycleListener.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemLifeCycleListener.java
new file mode 100644
index 00000000000..9954ed3ef94
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemLifeCycleListener.java
@@ -0,0 +1,61 @@
+/*
+ * 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.jackrabbit.core;
+
+import org.apache.jackrabbit.core.id.ItemId;
+
+/**
+ * The ItemLifeCycleListener interface allows an implementing
+ * object to be informed about changes on an Item instance.
+ */
+public interface ItemLifeCycleListener {
+
+ /**
+ * Called when an ItemImpl instance has been created.
+ *
+ * @param item the instance which has been created
+ */
+ void itemCreated(ItemImpl item);
+
+ /**
+ * Called when an ItemImpl instance has been invalidated
+ * (i.e. it has been temporarily rendered 'invalid').
+ *
+ * Note that most {@link javax.jcr.Item},
+ * {@link javax.jcr.Node} and {@link javax.jcr.Property}
+ * methods will throw an InvalidItemStateException when called
+ * on an 'invalidated' item.
+ *
+ * @param id the id of the instance that has been discarded
+ * @param item the instance which has been discarded
+ */
+ void itemInvalidated(ItemId id, ItemImpl item);
+
+ /**
+ * Called when an ItemImpl instance has been destroyed
+ * (i.e. it has been permanently rendered 'invalid').
+ *
+ * Note that most {@link javax.jcr.Item},
+ * {@link javax.jcr.Node} and {@link javax.jcr.Property}
+ * methods will throw an InvalidItemStateException when called
+ * on a 'destroyed' item.
+ *
+ * @param id the id of the instance that has been destroyed
+ * @param item the instance which has been destroyed
+ */
+ void itemDestroyed(ItemId id, ItemImpl item);
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java
new file mode 100644
index 00000000000..7b1ca35b7cc
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemManager.java
@@ -0,0 +1,1289 @@
+/*
+ * 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.jackrabbit.core;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.NamespaceException;
+import javax.jcr.NodeIterator;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.PropertyIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.ConstraintViolationException;
+
+import org.apache.commons.collections.map.ReferenceMap;
+import org.apache.jackrabbit.core.id.ItemId;
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.id.PropertyId;
+import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.core.nodetype.EffectiveNodeType;
+import org.apache.jackrabbit.core.nodetype.NodeTypeConflictException;
+import org.apache.jackrabbit.core.security.authorization.Permission;
+import org.apache.jackrabbit.core.state.ChildNodeEntry;
+import org.apache.jackrabbit.core.state.ItemState;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.ItemStateListener;
+import org.apache.jackrabbit.core.state.NoSuchItemStateException;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.PropertyState;
+import org.apache.jackrabbit.core.state.SessionItemStateManager;
+import org.apache.jackrabbit.core.version.VersionHistoryImpl;
+import org.apache.jackrabbit.core.version.VersionImpl;
+import org.apache.jackrabbit.core.security.AccessManager;
+import org.apache.jackrabbit.core.session.SessionContext;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.QPropertyDefinition;
+import org.apache.jackrabbit.spi.QNodeDefinition;
+import org.apache.jackrabbit.spi.commons.name.NameConstants;
+import org.apache.jackrabbit.spi.commons.nodetype.NodeDefinitionImpl;
+import org.apache.jackrabbit.spi.commons.nodetype.PropertyDefinitionImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * There's one ItemManager instance per Session
+ * instance. It is the factory for Node and Property
+ * instances.
+ *
+ * The ItemManager's responsibilities are:
+ *
+ *
providing access to Item instances by ItemId
+ * whereas Node and Item are only providing relative access.
+ *
returning the instance of an existing Node or Property,
+ * given its absolute path.
+ *
creating the per-session instance of a Node
+ * or Property that doesn't exist yet and needs to be created first.
+ *
guaranteeing that there aren't multiple instances representing the same
+ * Node or Property associated with the same
+ * Session instance.
+ *
maintaining a cache of the item instances it created.
+ *
respecting access rights of associated Session in all methods.
+ *
+ *
+ * If the parent Session is an XASession, there is
+ * one ItemManager instance per started global transaction.
+ */
+public class ItemManager implements ItemStateListener {
+
+ private static Logger log = LoggerFactory.getLogger(ItemManager.class);
+
+ private final org.apache.jackrabbit.spi.commons.nodetype.NodeDefinitionImpl rootNodeDef;
+
+ /**
+ * Component context of the associated session.
+ */
+ protected final SessionContext sessionContext;
+
+ protected final SessionImpl session;
+
+ private final SessionItemStateManager sism;
+ private final HierarchyManager hierMgr;
+
+ /**
+ * A cache for item instances created by this ItemManager
+ */
+ private final Map itemCache;
+
+ /**
+ * Shareable node cache.
+ */
+ private final ShareableNodesCache shareableNodesCache;
+
+ /**
+ * Creates a new per-session instance ItemManager instance.
+ *
+ * @param sessionContext component context of the associated session
+ */
+ @SuppressWarnings("unchecked")
+ protected ItemManager(SessionContext sessionContext) {
+ this.sism = sessionContext.getItemStateManager();
+ this.hierMgr = sessionContext.getHierarchyManager();
+ this.sessionContext = sessionContext;
+ this.session = sessionContext.getSessionImpl();
+ this.rootNodeDef = sessionContext.getNodeTypeManager().getRootNodeDefinition();
+
+ // setup item cache with weak references to items
+ itemCache = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
+
+ // setup shareable nodes cache
+ shareableNodesCache = new ShareableNodesCache();
+ }
+
+ /**
+ * Checks that this session is alive.
+ *
+ * @throws RepositoryException if the session has been closed
+ */
+ private void sanityCheck() throws RepositoryException {
+ sessionContext.getSessionState().checkAlive();
+ }
+
+ /**
+ * Disposes this ItemManager and frees resources.
+ */
+ void dispose() {
+ synchronized (itemCache) {
+ itemCache.clear();
+ }
+ shareableNodesCache.clear();
+ }
+
+ NodeDefinitionImpl getDefinition(NodeState state)
+ throws RepositoryException {
+ if (state.getId().equals(sessionContext.getRootNodeId())) {
+ // special handling required for root node
+ return rootNodeDef;
+ }
+
+ NodeId parentId = state.getParentId();
+ if (parentId == null) {
+ // removed state has parentId set to null
+ // get from overlayed state
+ ItemState overlaid = state.getOverlayedState();
+ if (overlaid != null) {
+ parentId = overlaid.getParentId();
+ } else {
+ throw new InvalidItemStateException(
+ "Could not find parent of node " + state.getNodeId());
+ }
+ }
+ NodeState parentState = null;
+ try {
+ // access the parent state circumventing permission check, since
+ // read permission on the parent isn't required in order to retrieve
+ // a node's definition. see also JCR-2418
+ ItemData parentData = getItemData(parentId, null, false);
+ parentState = (NodeState) parentData.getState();
+ if (state.getParentId() == null) {
+ // indicates state has been removed, must use
+ // overlayed state of parent, otherwise child node entry
+ // cannot be found. unless the parentState is new, which
+ // means it was recreated in place of a removed node
+ // that used to be the actual parent
+ if (parentState.getStatus() == ItemState.STATUS_NEW) {
+ // force getting parent from attic
+ parentState = null;
+ } else {
+ parentState = (NodeState) parentState.getOverlayedState();
+ }
+ }
+ } catch (ItemNotFoundException e) {
+ // parent probably removed, get it from attic. see below
+ }
+
+ if (parentState == null) {
+ try {
+ // use overlayed state if available
+ parentState = (NodeState) sism.getAttic().getItemState(
+ parentId).getOverlayedState();
+ } catch (ItemStateException ex) {
+ throw new RepositoryException(ex);
+ }
+ }
+
+ // get child node entry
+ ChildNodeEntry cne = parentState.getChildNodeEntry(state.getNodeId());
+ if (cne == null) {
+ throw new InvalidItemStateException(
+ "Could not find child " + state.getNodeId()
+ + " of node " + parentState.getNodeId());
+ }
+
+ NodeTypeRegistry ntReg = sessionContext.getNodeTypeRegistry();
+ try {
+ EffectiveNodeType ent = ntReg.getEffectiveNodeType(
+ parentState.getNodeTypeName(), parentState.getMixinTypeNames());
+ QNodeDefinition def;
+ try {
+ def = ent.getApplicableChildNodeDef(
+ cne.getName(), state.getNodeTypeName(), ntReg);
+ } catch (ConstraintViolationException e) {
+ // fallback to child node definition of a nt:unstructured
+ ent = ntReg.getEffectiveNodeType(NameConstants.NT_UNSTRUCTURED);
+ def = ent.getApplicableChildNodeDef(
+ cne.getName(), state.getNodeTypeName(), ntReg);
+ log.warn("Fallback to nt:unstructured due to unknown child " +
+ "node definition for type '" + state.getNodeTypeName() + "'");
+ }
+ return sessionContext.getNodeTypeManager().getNodeDefinition(def);
+ } catch (NodeTypeConflictException e) {
+ throw new RepositoryException(e);
+ }
+ }
+
+ PropertyDefinitionImpl getDefinition(PropertyState state)
+ throws RepositoryException {
+ // this is a bit ugly
+ // there might be cases where otherwise protected items turn into
+ // non-protected items because a mixin has been removed from the parent
+ // node state.
+ // see also: JCR-2408
+ if (state.getStatus() == ItemState.STATUS_EXISTING_REMOVED
+ && state.getName().equals(NameConstants.JCR_UUID)) {
+ NodeTypeRegistry ntReg = sessionContext.getNodeTypeRegistry();
+ QPropertyDefinition def = ntReg.getEffectiveNodeType(
+ NameConstants.MIX_REFERENCEABLE).getApplicablePropertyDef(
+ state.getName(), state.getType());
+ return sessionContext.getNodeTypeManager().getPropertyDefinition(def);
+ }
+ try {
+ // retrieve parent in 2 steps in order to avoid the check for
+ // read permissions on the parent which isn't required in order
+ // to read the property's definition. see also JCR-2418.
+ ItemData parentData = getItemData(state.getParentId(), null, false);
+ NodeImpl parent = (NodeImpl) createItemInstance(parentData);
+ return parent.getApplicablePropertyDefinition(
+ state.getName(), state.getType(), state.isMultiValued(), true);
+ } catch (ItemNotFoundException e) {
+ // parent probably removed, get it from attic
+ }
+ try {
+ NodeState parent = (NodeState) sism.getAttic().getItemState(
+ state.getParentId()).getOverlayedState();
+ NodeTypeRegistry ntReg = sessionContext.getNodeTypeRegistry();
+ EffectiveNodeType ent = ntReg.getEffectiveNodeType(
+ parent.getNodeTypeName(), parent.getMixinTypeNames());
+ QPropertyDefinition def;
+ try {
+ def = ent.getApplicablePropertyDef(
+ state.getName(), state.getType(), state.isMultiValued());
+ } catch (ConstraintViolationException e) {
+ ent = ntReg.getEffectiveNodeType(NameConstants.NT_UNSTRUCTURED);
+ def = ent.getApplicablePropertyDef(state.getName(),
+ state.getType(), state.isMultiValued());
+ log.warn("Fallback to nt:unstructured due to unknown property " +
+ "definition for '" + state.getName() + "'");
+ }
+ return sessionContext.getNodeTypeManager().getPropertyDefinition(def);
+ } catch (ItemStateException e) {
+ throw new RepositoryException(e);
+ } catch (NodeTypeConflictException e) {
+ throw new RepositoryException(e);
+ }
+ }
+
+ /**
+ * Common implementation for all variants of item/node/propertyExists
+ * with both itemId or path param.
+ *
+ * @param itemId The id of the item to test.
+ * @param path Path of the item to check if known or null. In
+ * the latter case the test for access permission is executed using the
+ * itemId.
+ * @return true if the item with the given itemId exists AND
+ * can be read by this session.
+ */
+ private boolean itemExists(ItemId itemId, Path path) {
+ try {
+ sanityCheck();
+
+ // shortcut: check if state exists for the given item
+ if (!sism.hasItemState(itemId)) {
+ return false;
+ }
+ getItemData(itemId, path, true);
+ return true;
+ } catch (RepositoryException re) {
+ return false;
+ }
+ }
+
+ /**
+ * Common implementation for all variants of getItem/getNode/getProperty
+ * with both itemId or path parameter.
+ *
+ * @param itemId
+ * @param path Path of the item to retrieve or null. In
+ * the latter case the test for access permission is executed using the
+ * itemId.
+ * @param permissionCheck
+ * @return The item identified by the given itemId.
+ * @throws ItemNotFoundException
+ * @throws AccessDeniedException
+ * @throws RepositoryException
+ */
+ private ItemImpl getItem(ItemId itemId, Path path, boolean permissionCheck) throws ItemNotFoundException, AccessDeniedException, RepositoryException {
+ sanityCheck();
+
+ ItemData data = getItemData(itemId, path, permissionCheck);
+ return createItemInstance(data);
+ }
+
+ /**
+ * Retrieves the data of the item with given id. If the
+ * specified item doesn't exist an ItemNotFoundException will
+ * be thrown.
+ * If the item exists but the current session is not granted read access an
+ * AccessDeniedException will be thrown.
+ *
+ * @param itemId id of item to be retrieved
+ * @return state state of said item
+ * @throws ItemNotFoundException if no item with given id exists
+ * @throws AccessDeniedException if the current session is not allowed to
+ * read the said item
+ * @throws RepositoryException if another error occurs
+ */
+ private ItemData getItemData(ItemId itemId)
+ throws ItemNotFoundException, AccessDeniedException,
+ RepositoryException {
+ return getItemData(itemId, null, true);
+ }
+
+ /**
+ * Retrieves the data of the item with given id. If the
+ * specified item doesn't exist an ItemNotFoundException will
+ * be thrown.
+ * If permissionCheck is true and the item exists
+ * but the current session is not granted read access an
+ * AccessDeniedException will be thrown.
+ *
+ * @param itemId id of item to be retrieved
+ * @param path The path of the item to retrieve the data for or
+ * null. In the latter case the id (instead of the path) is
+ * used to test if READ permission is granted.
+ * @param permissionCheck
+ * @return the ItemData for the item identified by the given itemId.
+ * @throws ItemNotFoundException if no item with given id exists
+ * @throws AccessDeniedException if the current session is not allowed to
+ * read the said item
+ * @throws RepositoryException if another error occurs
+ */
+ ItemData getItemData(ItemId itemId, Path path, boolean permissionCheck)
+ throws ItemNotFoundException, AccessDeniedException,
+ RepositoryException {
+ ItemData data = retrieveItem(itemId);
+ if (data == null) {
+ // not yet in cache, need to create instance:
+ // - retrieve item state
+ // - create instance of item data
+ // NOTE: permission check & caching within createItemData
+ ItemState state;
+ try {
+ state = sism.getItemState(itemId);
+ } catch (NoSuchItemStateException nsise) {
+ throw new ItemNotFoundException(itemId.toString(), nsise);
+ } catch (ItemStateException ise) {
+ String msg = "failed to retrieve item state of item " + itemId;
+ log.error(msg, ise);
+ throw new RepositoryException(msg, ise);
+ }
+ // create item data including: perm check and caching.
+ data = createItemData(state, path, permissionCheck);
+ } else {
+ // already cached: if 'permissionCheck' is true, make sure read
+ // permission is granted.
+ if (permissionCheck && !canRead(data, path)) {
+ // item exists but read-perm has been revoked in the mean time.
+ // -> remove from cache
+ evictItems(itemId);
+ throw new AccessDeniedException("cannot read item " + data.getId());
+ }
+ }
+ return data;
+ }
+
+ /**
+ * @param data
+ * @param path Path to be used for the permission check or null
+ * in which case the itemId present with the specified data is used.
+ * @return true if the item with the given data can be read;
+ * false otherwise.
+ * @throws AccessDeniedException
+ * @throws RepositoryException
+ */
+ private boolean canRead(ItemData data, Path path) throws AccessDeniedException, RepositoryException {
+ // JCR-1601: cached item may just have been invalidated
+ ItemState state = data.getState();
+ if (state == null) {
+ throw new InvalidItemStateException(data.getId() + ": the item does not exist anymore");
+ }
+ if (state.getStatus() == ItemState.STATUS_NEW) {
+ if (!data.getDefinition().isProtected()) {
+ /*
+ NEW items can always be read as long they have been added through
+ the API and NOT by the system (i.e. protected items).
+ */
+ return true;
+ } else {
+ /*
+ NEW protected (system) item:
+ need use the path to evaluate the effective permissions.
+ */
+ return (path == null) ?
+ sessionContext.getAccessManager().isGranted(data.getId(), AccessManager.READ) :
+ sessionContext.getAccessManager().isGranted(path, Permission.READ);
+ }
+ } else {
+ /* item is not NEW -> save to call acMgr.canRead(Path,ItemId) */
+ return sessionContext.getAccessManager().canRead(path, data.getId());
+ }
+ }
+
+ /**
+ * @param parent The item data of the parent node.
+ * @param childId
+ * @return true if the item with the given childId can be read;
+ * false otherwise.
+ * @throws RepositoryException
+ */
+ private boolean canRead(ItemData parent, ItemId childId) throws RepositoryException {
+ if (parent.getStatus() == ItemState.STATUS_EXISTING) {
+ // child item is for sure not NEW (because then the parent was modified).
+ // safe to use AccessManager#canRead(Path, ItemId).
+ return sessionContext.getAccessManager().canRead(null, childId);
+ } else {
+ // child could be NEW -> don't use AccessManager#canRead(Path, ItemId)
+ return sessionContext.getAccessManager().isGranted(childId, AccessManager.READ);
+ }
+ }
+
+ //--------------------------------------------------< item access methods >
+ /**
+ * Checks whether an item exists at the specified path.
+ *
+ * @deprecated As of JSR 283, a Path doesn't anymore uniquely
+ * identify an Item, therefore {@link #nodeExists(Path)} and
+ * {@link #propertyExists(Path)} should be used instead.
+ *
+ * @param path path to the item to be checked
+ * @return true if the specified item exists
+ */
+ public boolean itemExists(Path path) {
+ try {
+ sanityCheck();
+
+ ItemId id = hierMgr.resolvePath(path);
+ return (id != null) && itemExists(id, path);
+ } catch (RepositoryException re) {
+ return false;
+ }
+ }
+
+ /**
+ * Checks whether a node exists at the specified path.
+ *
+ * @param path path to the node to be checked
+ * @return true if a node exists at the specified path
+ */
+ public boolean nodeExists(Path path) {
+ try {
+ sanityCheck();
+
+ NodeId id = hierMgr.resolveNodePath(path);
+ return (id != null) && itemExists(id, path);
+ } catch (RepositoryException re) {
+ return false;
+ }
+ }
+
+ /**
+ * Checks whether a property exists at the specified path.
+ *
+ * @param path path to the property to be checked
+ * @return true if a property exists at the specified path
+ */
+ public boolean propertyExists(Path path) {
+ try {
+ sanityCheck();
+
+ PropertyId id = hierMgr.resolvePropertyPath(path);
+ return (id != null) && itemExists(id, path);
+ } catch (RepositoryException re) {
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the item with the given id exists.
+ *
+ * @param id id of the item to be checked
+ * @return true if the specified item exists
+ */
+ public boolean itemExists(ItemId id) {
+ return itemExists(id, null);
+ }
+
+ /**
+ * @return
+ * @throws RepositoryException
+ */
+ NodeImpl getRootNode() throws RepositoryException {
+ return (NodeImpl) getItem(sessionContext.getRootNodeId());
+ }
+
+ /**
+ * Returns the node at the specified absolute path in the workspace.
+ * If no such node exists, then it returns the property at the specified path.
+ * If no such property exists a PathNotFoundException is thrown.
+ *
+ * @deprecated As of JSR 283, a Path doesn't anymore uniquely
+ * identify an Item, therefore {@link #getNode(Path)} and
+ * {@link #getProperty(Path)} should be used instead.
+ * @param path
+ * @return
+ * @throws PathNotFoundException
+ * @throws AccessDeniedException
+ * @throws RepositoryException
+ */
+ public ItemImpl getItem(Path path) throws PathNotFoundException,
+ AccessDeniedException, RepositoryException {
+ ItemId id = hierMgr.resolvePath(path);
+ if (id == null) {
+ throw new PathNotFoundException(safeGetJCRPath(path));
+ }
+ try {
+ ItemImpl item = getItem(id, path, true);
+ // Test, if this item is a shareable node.
+ if (item.isNode() && ((NodeImpl) item).isShareable()) {
+ return getNode(path);
+ }
+ return item;
+ } catch (ItemNotFoundException infe) {
+ throw new PathNotFoundException(safeGetJCRPath(path));
+ }
+ }
+
+ /**
+ * @param path
+ * @return
+ * @throws PathNotFoundException
+ * @throws AccessDeniedException
+ * @throws RepositoryException
+ */
+ public NodeImpl getNode(Path path) throws PathNotFoundException,
+ AccessDeniedException, RepositoryException {
+ NodeId id = hierMgr.resolveNodePath(path);
+ if (id == null) {
+ throw new PathNotFoundException(safeGetJCRPath(path));
+ }
+ NodeId parentId = null;
+ if (!path.denotesRoot()) {
+ parentId = hierMgr.resolveNodePath(path.getAncestor(1));
+ }
+ try {
+ if (parentId == null) {
+ return (NodeImpl) getItem(id, path, true);
+ }
+ // if the node is shareable, it now returns the node with the right
+ // parent
+ return getNode(id, parentId);
+ } catch (ItemNotFoundException infe) {
+ throw new PathNotFoundException(safeGetJCRPath(path));
+ }
+ }
+
+ /**
+ * @param path
+ * @return
+ * @throws PathNotFoundException
+ * @throws AccessDeniedException
+ * @throws RepositoryException
+ */
+ public PropertyImpl getProperty(Path path)
+ throws PathNotFoundException, AccessDeniedException, RepositoryException {
+ PropertyId id = hierMgr.resolvePropertyPath(path);
+ if (id == null) {
+ throw new PathNotFoundException(safeGetJCRPath(path));
+ }
+ try {
+ return (PropertyImpl) getItem(id, path, true);
+ } catch (ItemNotFoundException infe) {
+ throw new PathNotFoundException(safeGetJCRPath(path));
+ }
+ }
+
+ /**
+ * @param id
+ * @return
+ * @throws RepositoryException
+ */
+ public synchronized ItemImpl getItem(ItemId id)
+ throws ItemNotFoundException, AccessDeniedException, RepositoryException {
+ return getItem(id, null, true);
+ }
+
+ /**
+ * @param id
+ * @return
+ * @throws RepositoryException
+ */
+ synchronized ItemImpl getItem(ItemId id, boolean permissionCheck)
+ throws ItemNotFoundException, AccessDeniedException, RepositoryException {
+ return getItem(id, null, permissionCheck);
+ }
+
+ /**
+ * Returns a node with a given id and parent id. If the indicated node is
+ * shareable, there might be multiple nodes associated with the same id,
+ * but there'is only one node with the given parent id.
+ *
+ * @param id node id
+ * @param parentId parent node id
+ * @return node
+ * @throws RepositoryException if an error occurs
+ */
+ public synchronized NodeImpl getNode(NodeId id, NodeId parentId)
+ throws ItemNotFoundException, AccessDeniedException, RepositoryException {
+ return getNode(id, parentId, true);
+ }
+
+ /**
+ * Returns a node with a given id and parent id. If the indicated node is
+ * shareable, there might be multiple nodes associated with the same id,
+ * but there'is only one node with the given parent id.
+ *
+ * @param id node id
+ * @param parentId parent node id
+ * @param permissionCheck Flag indicating if read permission must be check
+ * upon retrieving the node.
+ * @return node
+ * @throws RepositoryException if an error occurs
+ */
+ synchronized NodeImpl getNode(NodeId id, NodeId parentId, boolean permissionCheck)
+ throws ItemNotFoundException, AccessDeniedException, RepositoryException {
+ if (parentId == null) {
+ return (NodeImpl) getItem(id);
+ }
+ AbstractNodeData data = retrieveItem(id, parentId);
+ if (data == null) {
+ data = (AbstractNodeData) getItemData(id, null, permissionCheck);
+ } else if (permissionCheck && !canRead(data, id)) {
+ // item exists but read-perm has been revoked in the mean time.
+ // -> remove from cache
+ evictItems(id);
+ throw new AccessDeniedException("cannot read item " + data.getId());
+ }
+ if (!data.getParentId().equals(parentId)) {
+ // verify that parent actually appears in the shared set
+ if (!data.getNodeState().containsShare(parentId)) {
+ String msg = "Node with id '" + id
+ + "' does not have shared parent with id: " + parentId;
+ throw new ItemNotFoundException(msg);
+ }
+ // TODO: ev. need to check if read perm. is granted.
+ data = new NodeDataRef(data, parentId);
+ cacheItem(data);
+ }
+ return createNodeInstance(data);
+ }
+
+ /**
+ * Create an item instance from an item state. This method creates a
+ * new ItemData instance without looking at the cache nor
+ * testing if the item can be read and returns a new item instance.
+ *
+ * @param state item state
+ * @return item instance
+ * @throws RepositoryException if an error occurs
+ */
+ synchronized ItemImpl createItemInstance(ItemState state)
+ throws RepositoryException {
+ ItemData data = createItemData(state, null, false);
+ return createItemInstance(data);
+ }
+
+ /**
+ * @param parentId
+ * @return
+ * @throws ItemNotFoundException
+ * @throws AccessDeniedException
+ * @throws RepositoryException
+ */
+ synchronized boolean hasChildNodes(NodeId parentId)
+ throws ItemNotFoundException, AccessDeniedException, RepositoryException {
+ sanityCheck();
+
+ ItemData data = getItemData(parentId);
+ if (!data.isNode()) {
+ String msg = "can't list child nodes of property " + parentId;
+ log.debug(msg);
+ throw new RepositoryException(msg);
+ }
+
+ NodeState state = (NodeState) data.getState();
+ for (ChildNodeEntry entry : state.getChildNodeEntries()) {
+ // make sure any of the properties can be read.
+ if (canRead(data, entry.getId())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @param parentId
+ * @return
+ * @throws ItemNotFoundException
+ * @throws AccessDeniedException
+ * @throws RepositoryException
+ */
+ synchronized NodeIterator getChildNodes(NodeId parentId)
+ throws ItemNotFoundException, AccessDeniedException, RepositoryException {
+ sanityCheck();
+
+ ItemData data = getItemData(parentId);
+ if (!data.isNode()) {
+ String msg = "can't list child nodes of property " + parentId;
+ log.debug(msg);
+ throw new RepositoryException(msg);
+ }
+ ArrayList childIds = new ArrayList();
+ Iterator iter = ((NodeState) data.getState()).getChildNodeEntries().iterator();
+
+ while (iter.hasNext()) {
+ ChildNodeEntry entry = iter.next();
+ // delay check for read-access until item is being built
+ // thus avoid duplicate check
+ childIds.add(entry.getId());
+ }
+
+ return new LazyItemIterator(sessionContext, childIds, parentId);
+ }
+
+ /**
+ * @param parentId
+ * @return
+ * @throws ItemNotFoundException
+ * @throws AccessDeniedException
+ * @throws RepositoryException
+ */
+ synchronized boolean hasChildProperties(NodeId parentId)
+ throws ItemNotFoundException, AccessDeniedException, RepositoryException {
+ sanityCheck();
+
+ ItemData data = getItemData(parentId);
+ if (!data.isNode()) {
+ String msg = "can't list child properties of property " + parentId;
+ log.debug(msg);
+ throw new RepositoryException(msg);
+ }
+ Iterator iter = ((NodeState) data.getState()).getPropertyNames().iterator();
+
+ while (iter.hasNext()) {
+ Name propName = iter.next();
+ // make sure any of the properties can be read.
+ if (canRead(data, new PropertyId(parentId, propName))) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @param parentId
+ * @return
+ * @throws ItemNotFoundException
+ * @throws AccessDeniedException
+ * @throws RepositoryException
+ */
+ synchronized PropertyIterator getChildProperties(NodeId parentId)
+ throws ItemNotFoundException, AccessDeniedException, RepositoryException {
+ sanityCheck();
+
+ ItemData data = getItemData(parentId);
+ if (!data.isNode()) {
+ String msg = "can't list child properties of property " + parentId;
+ log.debug(msg);
+ throw new RepositoryException(msg);
+ }
+ ArrayList childIds = new ArrayList();
+ Iterator iter = ((NodeState) data.getState()).getPropertyNames().iterator();
+
+ while (iter.hasNext()) {
+ Name propName = iter.next();
+ PropertyId id = new PropertyId(parentId, propName);
+ // delay check for read-access until item is being built
+ // thus avoid duplicate check
+ childIds.add(id);
+ }
+
+ return new LazyItemIterator(sessionContext, childIds);
+ }
+
+ //-------------------------------------------------< item factory methods >
+ /**
+ * Builds the ItemData for the specified state.
+ * If permissionCheck is true, the access manager
+ * is used to determine if reading that item would be granted. If this is
+ * not the case an AccessDeniedException is thrown.
+ * Before returning the created ItemData it is put into the
+ * cache. In order to benefit from the cache
+ * {@link #getItemData(ItemId, Path, boolean)} should be called.
+ *
+ * @param state
+ * @return
+ * @throws RepositoryException
+ */
+ private ItemData createItemData(ItemState state, Path path, boolean permissionCheck) throws RepositoryException {
+ ItemData data;
+ if (state.isNode()) {
+ NodeState nodeState = (NodeState) state;
+ data = new NodeData(nodeState, this);
+ } else {
+ PropertyState propertyState = (PropertyState) state;
+ data = new PropertyData(propertyState, this);
+ }
+ // make sure read-perm. is granted before returning the data.
+ if (permissionCheck && !canRead(data, path)) {
+ throw new AccessDeniedException("cannot read item " + state.getId());
+ }
+ // before returning the data: put them into the cache.
+ cacheItem(data);
+ return data;
+ }
+
+ private ItemImpl createItemInstance(ItemData data) {
+ if (data.isNode()) {
+ return createNodeInstance((AbstractNodeData) data);
+ } else {
+ return createPropertyInstance((PropertyData) data);
+ }
+ }
+
+ private NodeImpl createNodeInstance(AbstractNodeData data) {
+ // check special nodes
+ final NodeState state = data.getNodeState();
+ if (state.getNodeTypeName().equals(NameConstants.NT_VERSION)) {
+ return new VersionImpl(this, sessionContext, data);
+ } else if (state.getNodeTypeName().equals(NameConstants.NT_VERSIONHISTORY)) {
+ return new VersionHistoryImpl(this, sessionContext, data);
+ } else {
+ // create node object
+ return new NodeImpl(this, sessionContext, data);
+ }
+ }
+
+ private PropertyImpl createPropertyInstance(PropertyData data) {
+ // check special nodes
+ return new PropertyImpl(this, sessionContext, data);
+ }
+
+ //---------------------------------------------------< item cache methods >
+
+ /**
+ * Returns an item reference from the cache.
+ *
+ * @param id id of the item that should be retrieved.
+ * @return the item reference stored in the corresponding cache entry
+ * or null if there's no corresponding cache entry.
+ */
+ private ItemData retrieveItem(ItemId id) {
+ synchronized (itemCache) {
+ ItemData data = itemCache.get(id);
+ if (data == null && id.denotesNode()) {
+ data = shareableNodesCache.retrieveFirst((NodeId) id);
+ }
+ return data;
+ }
+ }
+
+ /**
+ * Return a node from the cache.
+ *
+ * @param id id of the node that should be retrieved.
+ * @param parentId parent id of the node that should be retrieved
+ * @return reference stored in the corresponding cache entry
+ * or null if there's no corresponding cache entry.
+ */
+ private AbstractNodeData retrieveItem(NodeId id, NodeId parentId) {
+ synchronized (itemCache) {
+ AbstractNodeData data = shareableNodesCache.retrieve(id, parentId);
+ if (data == null) {
+ data = (AbstractNodeData) itemCache.get(id);
+ }
+ return data;
+ }
+ }
+
+ /**
+ * Puts the reference of an item in the cache with
+ * the item's path as the key.
+ *
+ * @param data the item data to cache
+ */
+ private void cacheItem(ItemData data) {
+ synchronized (itemCache) {
+ if (data.isNode()) {
+ AbstractNodeData nd = (AbstractNodeData) data;
+ if (nd.getPrimaryParentId() != null) {
+ shareableNodesCache.cache(nd);
+ return;
+ }
+ }
+ ItemId id = data.getId();
+ if (itemCache.containsKey(id)) {
+ log.debug("overwriting cached item " + id);
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("caching item " + id);
+ }
+ itemCache.put(id, data);
+ }
+ }
+
+ /**
+ * Removes all cache entries with the given item id. If the item is
+ * shareable, there might be more than one cache entry for this item.
+ *
+ * @param id id of the items to remove from the cache
+ */
+ private void evictItems(ItemId id) {
+ if (log.isDebugEnabled()) {
+ log.debug("removing items " + id + " from cache");
+ }
+ synchronized (itemCache) {
+ itemCache.remove(id);
+ if (id.denotesNode()) {
+ shareableNodesCache.evictAll((NodeId) id);
+ }
+ }
+ }
+
+ /**
+ * Removes a cache entry for a specific item.
+ *
+ * @param data The item data to remove from the cache
+ */
+ private void evictItem(ItemData data) {
+ if (log.isDebugEnabled()) {
+ log.debug("removing item " + data.getId() + " from cache");
+ }
+ synchronized (itemCache) {
+ if (data.isNode()) {
+ shareableNodesCache.evict((AbstractNodeData) data);
+ }
+ ItemData cached = itemCache.get(data.getId());
+ if (cached == data) {
+ itemCache.remove(data.getId());
+ }
+ }
+ }
+
+
+ //-------------------------------------------------< misc. helper methods >
+ /**
+ * Failsafe conversion of internal Path to JCR path for use in
+ * error messages etc.
+ *
+ * @param path path to convert
+ * @return JCR path
+ */
+ String safeGetJCRPath(Path path) {
+ try {
+ return session.getJCRPath(path);
+ } catch (NamespaceException e) {
+ log.error("failed to convert " + path.toString() + " to JCR path.");
+ // return string representation of internal path as a fallback
+ return path.toString();
+ }
+ }
+
+ /**
+ * Failsafe translation of internal ItemId to JCR path for use in
+ * error messages etc.
+ *
+ * @param id path to convert
+ * @return JCR path
+ */
+ String safeGetJCRPath(ItemId id) {
+ try {
+ return safeGetJCRPath(hierMgr.getPath(id));
+ } catch (RepositoryException re) {
+ log.error(id + ": failed to determine path to");
+ // return string representation if id as a fallback
+ return id.toString();
+ }
+ }
+
+ //------------------------------------------------< ItemLifeCycleListener >
+
+ /**
+ * {@inheritDoc}
+ */
+ public void itemInvalidated(ItemId id, ItemData data) {
+ if (log.isDebugEnabled()) {
+ log.debug("invalidated item " + id);
+ }
+ evictItem(data);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void itemDestroyed(ItemId id, ItemData data) {
+ if (log.isDebugEnabled()) {
+ log.debug("destroyed item " + id);
+ }
+ synchronized (itemCache) {
+ // remove instance from cache
+ evictItems(id);
+ }
+ }
+
+ //--------------------------------------------------------------< Object >
+ /**
+ * {@inheritDoc}
+ */
+ public synchronized String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("ItemManager (" + super.toString() + ")\n");
+ builder.append("Items in cache:\n");
+ synchronized (itemCache) {
+ for (ItemId id : itemCache.keySet()) {
+ ItemData item = itemCache.get(id);
+ if (item.isNode()) {
+ builder.append("Node: ");
+ } else {
+ builder.append("Property: ");
+ }
+ if (item.getState().isTransient()) {
+ builder.append("transient ");
+ } else {
+ builder.append(" ");
+ }
+ builder.append(id + "\t" + safeGetJCRPath(id) + " (" + item + ")\n");
+ }
+ }
+ return builder.toString();
+ }
+
+ //----------------------------------------------------< ItemStateListener >
+
+ /**
+ * {@inheritDoc}
+ */
+ public void stateCreated(ItemState created) {
+ ItemData data = retrieveItem(created.getId());
+ if (data != null) {
+ data.setStatus(ItemImpl.STATUS_NORMAL);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void stateModified(ItemState modified) {
+ ItemData data = retrieveItem(modified.getId());
+ if (data != null && data.getState() == modified) {
+ data.setStatus(ItemImpl.STATUS_MODIFIED);
+ /*
+ if (modified.isNode()) {
+ NodeState state = (NodeState) modified;
+ if (state.isShareable()) {
+ //evictItem(modified.getId());
+ NodeData nodeData = (NodeData) data;
+ NodeData shareSibling = new NodeData(nodeData, state.getParentId());
+ shareableNodesCache.cache(shareSibling);
+ }
+ }
+ */
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void stateDestroyed(ItemState destroyed) {
+ ItemData data = retrieveItem(destroyed.getId());
+ if (data != null && data.getState() == destroyed) {
+ itemDestroyed(destroyed.getId(), data);
+
+ data.setStatus(ItemImpl.STATUS_DESTROYED);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void stateDiscarded(ItemState discarded) {
+ ItemData data = retrieveItem(discarded.getId());
+ if (data != null && data.getState() == discarded) {
+ if (discarded.isTransient()) {
+ switch (discarded.getStatus()) {
+ /**
+ * persistent item that has been transiently removed
+ */
+ case ItemState.STATUS_EXISTING_REMOVED:
+ case ItemState.STATUS_EXISTING_MODIFIED:
+ ItemState persistentState = discarded.getOverlayedState();
+ // the state is a transient wrapper for the underlying
+ // persistent state, therefore restore the persistent state
+ // and resurrect this item instance if necessary
+ SessionItemStateManager stateMgr =
+ sessionContext.getItemStateManager();
+ stateMgr.disconnectTransientItemState(discarded);
+ data.setState(persistentState);
+ return;
+
+ /**
+ * persistent item that has been transiently modified or
+ * removed and the underlying persistent state has been
+ * externally destroyed since the transient
+ * modification/removal.
+ */
+ case ItemState.STATUS_STALE_DESTROYED:
+ /**
+ * first notify the listeners that this instance has been
+ * permanently invalidated
+ */
+ itemDestroyed(discarded.getId(), data);
+ // now set state of this instance to 'destroyed'
+ data.setStatus(ItemImpl.STATUS_DESTROYED);
+ data.setState(null);
+ return;
+
+ /**
+ * new item that has been transiently added
+ */
+ case ItemState.STATUS_NEW:
+ /**
+ * first notify the listeners that this instance has been
+ * permanently invalidated
+ */
+ itemDestroyed(discarded.getId(), data);
+ // now set state of this instance to 'destroyed'
+ // finally dispose state
+ data.setStatus(ItemImpl.STATUS_DESTROYED);
+ data.setState(null);
+ return;
+ }
+ }
+
+ /**
+ * first notify the listeners that this instance has been
+ * invalidated
+ */
+ itemInvalidated(discarded.getId(), data);
+ // now render this instance 'invalid'
+ data.setStatus(ItemImpl.STATUS_INVALIDATED);
+ }
+ }
+
+ /**
+ * Cache of shareable nodes. For performance reasons, methods are not
+ * synchronized and thread-safety must be guaranteed by caller.
+ */
+ static class ShareableNodesCache {
+
+ /**
+ * This cache is based on a reference map, that maps an item id to a map,
+ * which again maps a (hard-ref) parent id to a (weak-ref) shareable node.
+ */
+ private final ReferenceMap cache;
+
+ /**
+ * Create a new instance of this class.
+ */
+ public ShareableNodesCache() {
+ cache = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.HARD);
+ }
+
+ /**
+ * Clear cache.
+ *
+ * @see ReferenceMap#clear()
+ */
+ public void clear() {
+ cache.clear();
+ }
+
+ /**
+ * Return the first available node that maps to the given id.
+ *
+ * @param id node id
+ * @return node or null
+ */
+ public AbstractNodeData retrieveFirst(NodeId id) {
+ ReferenceMap map = (ReferenceMap) cache.get(id);
+ if (map != null) {
+ Iterator iter = map.values().iterator();
+ try {
+ while (iter.hasNext()) {
+ AbstractNodeData data = iter.next();
+ if (data != null) {
+ return data;
+ }
+ }
+ } finally {
+ iter = null;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return the node with the given id and parent id.
+ *
+ * @param id node id
+ * @param parentId parent id
+ * @return node or null
+ */
+ public AbstractNodeData retrieve(NodeId id, NodeId parentId) {
+ ReferenceMap map = (ReferenceMap) cache.get(id);
+ if (map != null) {
+ return (AbstractNodeData) map.get(parentId);
+ }
+ return null;
+ }
+
+ /**
+ * Cache some node.
+ *
+ * @param data data to cache
+ */
+ public void cache(AbstractNodeData data) {
+ NodeId id = data.getNodeState().getNodeId();
+ ReferenceMap map = (ReferenceMap) cache.get(id);
+ if (map == null) {
+ map = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK);
+ cache.put(id, map);
+ }
+ Object old = map.put(data.getPrimaryParentId(), data);
+ if (old != null) {
+ log.debug("overwriting cached item: " + old);
+ }
+ }
+
+ /**
+ * Evict some node from the cache.
+ *
+ * @param data data to evict
+ */
+ public void evict(AbstractNodeData data) {
+ ReferenceMap map = (ReferenceMap) cache.get(data.getId());
+ if (map != null) {
+ map.remove(data.getPrimaryParentId());
+ }
+ }
+
+ /**
+ * Evict all nodes with a given node id from the cache.
+ *
+ * @param id node id to evict
+ */
+ public synchronized void evictAll(NodeId id) {
+ cache.remove(id);
+ }
+ }
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemRefreshOperation.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemRefreshOperation.java
new file mode 100644
index 00000000000..b3c1fe98589
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemRefreshOperation.java
@@ -0,0 +1,147 @@
+/*
+ * 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.jackrabbit.core;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.session.SessionContext;
+import org.apache.jackrabbit.core.session.SessionOperation;
+import org.apache.jackrabbit.core.state.ItemState;
+import org.apache.jackrabbit.core.state.SessionItemStateManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ItemRefreshOperation implements SessionOperation {
+
+ /**
+ * Logger instance.
+ */
+ private static final Logger log =
+ LoggerFactory.getLogger(ItemRefreshOperation.class);
+
+ private final ItemState state;
+
+ private final boolean keepChanges;
+
+ public ItemRefreshOperation(ItemState state, boolean keepChanges) {
+ this.state = state;
+ this.keepChanges = keepChanges;
+ }
+
+ public Object perform(SessionContext context) throws RepositoryException {
+ if (keepChanges) {
+ // FIXME When keepChanges is true, should reset Item#status field
+ // to STATUS_NORMAL of all descendant non-transient instances;
+ // maybe also have to reset stale ItemState instances
+ return this;
+ }
+
+ SessionItemStateManager stateMgr = context.getItemStateManager();
+
+ // Optimisation for the root node
+ if (state.getParentId() == null) {
+ stateMgr.disposeAllTransientItemStates();
+ return this;
+ }
+
+ // list of transient items that should be discarded
+ List transientStates = new ArrayList();
+
+ // check status of this item's state
+ if (state.isTransient()) {
+ switch (state.getStatus()) {
+ case ItemState.STATUS_STALE_DESTROYED:
+ // add this item's state to the list
+ transientStates.add(state);
+ break;
+ case ItemState.STATUS_EXISTING_MODIFIED:
+ if (!state.getParentId().equals(
+ state.getOverlayedState().getParentId())) {
+ throw new RepositoryException(
+ "Cannot refresh a moved item,"
+ + " try refreshing the parent: " + this);
+ }
+ transientStates.add(state);
+ break;
+ case ItemState.STATUS_NEW:
+ throw new RepositoryException(
+ "Cannot refresh a new item: " + this);
+ default:
+ // log and ignore
+ log.warn("Unexpected item state status {} of {}",
+ state.getStatus(), this);
+ break;
+ }
+ }
+
+ if (state.isNode()) {
+ // build list of 'new', 'modified' or 'stale' descendants
+ for (ItemState transientState
+ : stateMgr.getDescendantTransientItemStates(state.getId())) {
+ switch (transientState.getStatus()) {
+ case ItemState.STATUS_STALE_DESTROYED:
+ case ItemState.STATUS_NEW:
+ case ItemState.STATUS_EXISTING_MODIFIED:
+ // add new or modified state to the list
+ transientStates.add(transientState);
+ break;
+
+ default:
+ // log and ignore
+ log.debug("unexpected state status ({})",
+ transientState.getStatus());
+ break;
+ }
+ }
+ }
+
+ // process list of 'new', 'modified' or 'stale' transient states
+ for (ItemState transientState : transientStates) {
+ // dispose the transient state, it is no longer used;
+ // this will indirectly (through stateDiscarded listener method)
+ // either restore or permanently invalidate the wrapping Item instances
+ stateMgr.disposeTransientItemState(transientState);
+ }
+
+ if (state.isNode()) {
+ // discard all transient descendants in the attic (i.e. those marked
+ // as 'removed'); this will resurrect the removed items
+ for (ItemState descendant
+ : stateMgr.getDescendantTransientItemStatesInAttic(state.getId())) {
+ // dispose the transient state; this will indirectly
+ // (through stateDiscarded listener method) resurrect
+ // the wrapping Item instances
+ stateMgr.disposeTransientItemStateInAttic(descendant);
+ }
+ }
+
+ return this;
+ }
+
+ //--------------------------------------------------------------< Object >
+
+ /**
+ * Returns a string representation of this operation.
+ */
+ public String toString() {
+ return "item.refresh(" + keepChanges + ")";
+ }
+
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemRemoveOperation.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemRemoveOperation.java
new file mode 100644
index 00000000000..e2d3cd039b4
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemRemoveOperation.java
@@ -0,0 +1,96 @@
+/*
+ * 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.jackrabbit.core;
+
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_CHECKED_OUT;
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_CONSTRAINTS;
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_HOLD;
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_LOCK;
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_RETENTION;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.security.authorization.Permission;
+import org.apache.jackrabbit.core.session.SessionContext;
+import org.apache.jackrabbit.core.session.SessionWriteOperation;
+
+/**
+ * Session operation for removing a given item, optionally with constraint
+ * checks enabled.
+ */
+class ItemRemoveOperation implements SessionWriteOperation {
+
+ /**
+ * The item to be removed.
+ */
+ private final ItemImpl item;
+
+ /**
+ * Flag to enabled constraint checks
+ */
+ private final boolean checks;
+
+ public ItemRemoveOperation(ItemImpl item, boolean checks) {
+ this.item = item;
+ this.checks = checks;
+ }
+
+ public Object perform(SessionContext context)
+ throws RepositoryException {
+ // check if this is the root node
+ if (item.getDepth() == 0) {
+ throw new RepositoryException("Cannot remove the root node");
+ }
+
+ NodeImpl parentNode = (NodeImpl) item.getParent();
+ if (checks) {
+ ItemValidator validator = context.getItemValidator();
+ validator.checkRemove(
+ item,
+ CHECK_CONSTRAINTS | CHECK_HOLD | CHECK_RETENTION,
+ Permission.NONE);
+
+ // Make sure the parent node is checked-out and
+ // neither protected nor locked.
+ validator.checkModify(
+ parentNode,
+ CHECK_LOCK | CHECK_CHECKED_OUT | CHECK_CONSTRAINTS,
+ Permission.NONE);
+ }
+
+ // delegate the removal of the child item to the parent node
+ if (item.isNode()) {
+ parentNode.removeChildNode((NodeId) item.getId());
+ } else {
+ parentNode.removeChildProperty(item.getPrimaryPath().getName());
+ }
+
+ return this;
+ }
+
+
+ //--------------------------------------------------------------< Object >
+
+ /**
+ * Returns a string representation of this operation.
+ */
+ public String toString() {
+ return "item.remove()";
+ }
+
+}
\ No newline at end of file
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemSaveOperation.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemSaveOperation.java
new file mode 100644
index 00000000000..26a84e57ff4
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemSaveOperation.java
@@ -0,0 +1,939 @@
+/*
+ * 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.jackrabbit.core;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.Item;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.Node;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.ItemDefinition;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.NodeType;
+
+import org.apache.jackrabbit.core.id.ItemId;
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.id.PropertyId;
+import org.apache.jackrabbit.core.nodetype.EffectiveNodeType;
+import org.apache.jackrabbit.core.nodetype.NodeTypeConflictException;
+import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
+import org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl;
+import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.core.security.AccessManager;
+import org.apache.jackrabbit.core.security.authorization.Permission;
+import org.apache.jackrabbit.core.session.SessionContext;
+import org.apache.jackrabbit.core.session.SessionWriteOperation;
+import org.apache.jackrabbit.core.state.ChildNodeEntry;
+import org.apache.jackrabbit.core.state.ItemState;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.PropertyState;
+import org.apache.jackrabbit.core.state.SessionItemStateManager;
+import org.apache.jackrabbit.core.state.StaleItemStateException;
+import org.apache.jackrabbit.core.value.InternalValue;
+import org.apache.jackrabbit.core.version.InternalVersionManager;
+import org.apache.jackrabbit.core.version.VersionHistoryInfo;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.QItemDefinition;
+import org.apache.jackrabbit.spi.QPropertyDefinition;
+import org.apache.jackrabbit.spi.commons.name.NameConstants;
+import org.apache.jackrabbit.util.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The session operation triggered by {@link Item#save()}.
+ */
+class ItemSaveOperation implements SessionWriteOperation {
+
+ /**
+ * Logger instance.
+ */
+ private static final Logger log =
+ LoggerFactory.getLogger(ItemSaveOperation.class);
+
+ private final ItemState state;
+
+ public ItemSaveOperation(ItemState state) {
+ this.state = state;
+ }
+
+ public Object perform(SessionContext context) throws RepositoryException {
+ SessionItemStateManager stateMgr = context.getItemStateManager();
+
+ /**
+ * build list of transient (i.e. new & modified) states that
+ * should be persisted
+ */
+ Collection dirty;
+ try {
+ dirty = getTransientStates(context.getItemStateManager());
+ } catch (ConcurrentModificationException e) {
+ String msg = "Concurrent modification; session is closed";
+ log.error(msg, e);
+ context.getSessionImpl().logout();
+ throw e;
+ }
+ if (dirty.size() == 0) {
+ // no transient items, nothing to do here
+ return this;
+ }
+
+ /**
+ * build list of transient descendants in the attic
+ * (i.e. those marked as 'removed')
+ */
+ Collection removed =
+ getRemovedStates(context.getItemStateManager());
+
+ // All affected item states. The keys are used to look up whether
+ // an item is affected, and the values are iterated through below
+ Map affected =
+ new HashMap(dirty.size() + removed.size());
+ for (ItemState state : dirty) {
+ affected.put(state.getId(), state);
+ }
+ for (ItemState state : removed) {
+ affected.put(state.getId(), state);
+ }
+
+ /**
+ * make sure that this save operation is totally 'self-contained'
+ * and independent; items within the scope of this save operation
+ * must not have 'external' dependencies;
+ * (e.g. moving a node requires that the target node including both
+ * old and new parents are saved)
+ */
+ for (ItemState transientState : affected.values()) {
+ if (transientState.isNode()) {
+ NodeState nodeState = (NodeState) transientState;
+ Set dependentIDs = new HashSet();
+ if (nodeState.hasOverlayedState()) {
+ NodeState overlayedState =
+ (NodeState) nodeState.getOverlayedState();
+ NodeId oldParentId = overlayedState.getParentId();
+ NodeId newParentId = nodeState.getParentId();
+ if (oldParentId != null) {
+ if (newParentId == null) {
+ // node has been removed, add old parents
+ // to dependencies
+ if (overlayedState.isShareable()) {
+ dependentIDs.addAll(overlayedState.getSharedSet());
+ } else {
+ dependentIDs.add(oldParentId);
+ }
+ } else {
+ if (!oldParentId.equals(newParentId)) {
+ // node has been moved to a new location,
+ // add old and new parent to dependencies
+ dependentIDs.add(oldParentId);
+ dependentIDs.add(newParentId);
+ } else {
+ // parent id hasn't changed, check whether
+ // the node has been renamed (JCR-1034)
+ if (!affected.containsKey(newParentId)
+ && stateMgr.hasTransientItemState(newParentId)) {
+ try {
+ NodeState parent = (NodeState) stateMgr.getTransientItemState(newParentId);
+ // check parent's renamed child node entries
+ for (ChildNodeEntry cne : parent.getRenamedChildNodeEntries()) {
+ if (cne.getId().equals(nodeState.getId())) {
+ // node has been renamed,
+ // add parent to dependencies
+ dependentIDs.add(newParentId);
+ }
+ }
+ } catch (ItemStateException ise) {
+ // should never get here
+ log.warn("failed to retrieve transient state: " + newParentId, ise);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // removed child node entries
+ for (ChildNodeEntry cne : nodeState.getRemovedChildNodeEntries()) {
+ dependentIDs.add(cne.getId());
+ }
+ // added child node entries
+ for (ChildNodeEntry cne : nodeState.getAddedChildNodeEntries()) {
+ dependentIDs.add(cne.getId());
+ }
+
+ // now walk through dependencies and check whether they
+ // are within the scope of this save operation
+ for (NodeId id : dependentIDs) {
+ if (!affected.containsKey(id)) {
+ // JCR-1359 workaround: check whether unresolved
+ // dependencies originate from 'this' session;
+ // otherwise ignore them
+ if (stateMgr.hasTransientItemState(id)
+ || stateMgr.hasTransientItemStateInAttic(id)) {
+ // need to save dependency as well
+ String msg =
+ context.getItemManager().safeGetJCRPath(id)
+ + " needs to be saved as well.";
+ log.debug(msg);
+ throw new ConstraintViolationException(msg);
+ }
+ }
+ }
+ }
+ }
+
+ // validate access and node type constraints
+ // (this will also validate child removals)
+ validateTransientItems(context, dirty, removed);
+
+ // start the update operation
+ try {
+ stateMgr.edit();
+ } catch (IllegalStateException e) {
+ throw new RepositoryException("Unable to start edit operation", e);
+ }
+
+ boolean succeeded = false;
+ try {
+ // process transient items marked as 'removed'
+ removeTransientItems(context.getItemStateManager(), removed);
+
+ // process transient items that have change in mixins
+ processShareableNodes(
+ context.getRepositoryContext().getNodeTypeRegistry(),
+ dirty);
+
+ // initialize version histories for new nodes (might generate new transient state)
+ if (initVersionHistories(context, dirty)) {
+ // re-build the list of transient states because the previous call
+ // generated new transient state
+ dirty = getTransientStates(context.getItemStateManager());
+ }
+
+ // process 'new' or 'modified' transient states
+ persistTransientItems(context.getItemManager(), dirty);
+
+ // dispose the transient states marked 'new' or 'modified'
+ // at this point item state data is pushed down one level,
+ // node instances are disconnected from the transient
+ // item state and connected to the 'overlayed' item state.
+ // transient item states must be removed now. otherwise
+ // the session item state provider will return an orphaned
+ // item state which is not referenced by any node instance.
+ for (ItemState transientState : dirty) {
+ // dispose the transient state, it is no longer used
+ stateMgr.disposeTransientItemState(transientState);
+ }
+
+ // end update operation
+ stateMgr.update();
+ // update operation succeeded
+ succeeded = true;
+ } catch (StaleItemStateException e) {
+ throw new InvalidItemStateException(
+ "Unable to update a stale item: " + this, e);
+ } catch (ItemStateException e) {
+ throw new RepositoryException(
+ "Unable to update item: " + this, e);
+ } finally {
+ if (!succeeded) {
+ // update operation failed, cancel all modifications
+ stateMgr.cancel();
+
+ // JCR-288: if an exception has been thrown during
+ // update() the transient changes have already been
+ // applied by persistTransientItems() and we need to
+ // restore transient state, i.e. undo the effect of
+ // persistTransientItems()
+ restoreTransientItems(context, dirty);
+ }
+ }
+
+ // now it is safe to dispose the transient states:
+ // dispose the transient states marked 'removed'.
+ // item states in attic are removed after store, because
+ // the observation mechanism needs to build paths of removed
+ // items in store().
+ for (ItemState transientState : removed) {
+ // dispose the transient state, it is no longer used
+ stateMgr.disposeTransientItemStateInAttic(transientState);
+ }
+
+ return this;
+ }
+
+ /**
+ * Builds a list of transient (i.e. new or modified) item states that are
+ * within the scope of this.{@link #perform(SessionContext)}. The collection
+ * returned is ordered depth-first, i.e. the item itself (if transient)
+ * comes last.
+ *
+ * @return list of transient item states
+ * @throws InvalidItemStateException
+ * @throws RepositoryException
+ */
+ private Collection getTransientStates(
+ SessionItemStateManager sism)
+ throws InvalidItemStateException, RepositoryException {
+ // list of transient states that should be persisted
+ ArrayList dirty = new ArrayList();
+
+ if (state.isNode()) {
+ // build list of 'new' or 'modified' descendants
+ for (ItemState transientState
+ : sism.getDescendantTransientItemStates(state.getId())) {
+ // fail-fast test: check status of transient state
+ switch (transientState.getStatus()) {
+ case ItemState.STATUS_NEW:
+ case ItemState.STATUS_EXISTING_MODIFIED:
+ // add modified state to the list
+ dirty.add(transientState);
+ break;
+
+ case ItemState.STATUS_STALE_DESTROYED:
+ throw new InvalidItemStateException(
+ "Item cannot be saved because it has been "
+ + "deleted externally: " + this);
+
+ case ItemState.STATUS_UNDEFINED:
+ throw new InvalidItemStateException(
+ "Item cannot be saved; it seems to have been "
+ + "removed externally: " + this);
+
+ default:
+ log.warn("Unexpected item state status: "
+ + transientState.getStatus() + " of " + this);
+ // ignore
+ break;
+ }
+ }
+ }
+ // fail-fast test: check status of this item's state
+ if (state.isTransient()) {
+ switch (state.getStatus()) {
+ case ItemState.STATUS_EXISTING_MODIFIED:
+ // add this item's state to the list
+ dirty.add(state);
+ break;
+
+ case ItemState.STATUS_NEW:
+ throw new RepositoryException(
+ "Cannot save a new item: " + this);
+
+ case ItemState.STATUS_STALE_DESTROYED:
+ throw new InvalidItemStateException(
+ "Item cannot be saved because it has been"
+ + " deleted externally:" + this);
+
+ case ItemState.STATUS_UNDEFINED:
+ throw new InvalidItemStateException(
+ "Item cannot be saved; it seems to have been"
+ + " removed externally: " + this);
+
+ default:
+ log.warn("Unexpected item state status:"
+ + state.getStatus() + " of " + this);
+ // ignore
+ break;
+ }
+ }
+
+ return dirty;
+ }
+
+ /**
+ * Builds a list of transient descendant item states in the attic
+ * (i.e. those marked as 'removed') that are within the scope of
+ * this.{@link #perform(SessionContext)}.
+ *
+ * @return list of transient item states
+ * @throws InvalidItemStateException
+ * @throws RepositoryException
+ */
+ private Collection getRemovedStates(
+ SessionItemStateManager sism)
+ throws InvalidItemStateException, RepositoryException {
+ if (state.isNode()) {
+ ArrayList removed = new ArrayList();
+ for (ItemState transientState
+ : sism.getDescendantTransientItemStatesInAttic(state.getId())) {
+ // check if stale
+ if (transientState.getStatus() == ItemState.STATUS_STALE_DESTROYED) {
+ throw new InvalidItemStateException(
+ "Item can't be removed because it has already"
+ + " been deleted externally: "
+ + transientState.getId());
+ }
+ removed.add(transientState);
+ }
+ return removed;
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ /**
+ * the following validations/checks are performed on transient items:
+ *
+ * for every transient item:
+ * - if it is 'modified' or 'new' check the corresponding write permission.
+ * - if it is 'removed' check the REMOVE permission
+ *
+ * for every transient node:
+ * - if it is 'new' check that its node type satisfies the
+ * 'required node type' constraint specified in its definition
+ * - check if 'mandatory' child items exist
+ *
+ * for every transient property:
+ * - check if the property value satisfies the value constraints
+ * specified in the property's definition
+ *
+ * note that the protected flag is checked in Node.addNode/Node.remove
+ * (for adding/removing child entries of a node), in
+ * Node.addMixin/removeMixin/setPrimaryType (for type changes on nodes)
+ * and in Property.setValue (for properties to be modified).
+ */
+ private void validateTransientItems(
+ SessionContext context,
+ Iterable dirty, Iterable removed)
+ throws RepositoryException {
+ SessionImpl session = context.getSessionImpl();
+ ItemManager itemMgr = context.getItemManager();
+ SessionItemStateManager stateMgr = context.getItemStateManager();
+
+ AccessManager accessMgr = context.getAccessManager();
+ NodeTypeManagerImpl ntMgr = context.getNodeTypeManager();
+ // walk through list of dirty transient items and validate each
+ for (ItemState itemState : dirty) {
+ ItemDefinition def;
+ if (itemState.isNode()) {
+ def = itemMgr.getDefinition((NodeState) itemState);
+ } else {
+ def = itemMgr.getDefinition((PropertyState) itemState);
+ }
+ /* check permissions for non-protected items. protected items are
+ only added through API methods which need to assert that
+ permissions are not violated.
+ */
+ if (!def.isProtected()) {
+ /* detect the effective set of modification:
+ - new added node -> add_node perm on the child
+ - new property added -> set_property permission
+ - property modified -> set_property permission
+ - modified nodes can be ignored for changes only included
+ child-item addition or removal or changes of protected
+ properties such as mixin-types which are covered separately
+ note: removed items are checked later on.
+ note: reordering of child nodes has been covered upfront as
+ this information isn't available here.
+ */
+ Path path = stateMgr.getHierarchyMgr().getPath(itemState.getId());
+ boolean isGranted = true;
+ if (itemState.isNode()) {
+ if (itemState.getStatus() == ItemState.STATUS_NEW) {
+ isGranted = accessMgr.isGranted(path, Permission.ADD_NODE);
+ } // else: modified node (see comment above)
+ } else {
+ // modified or new property: set_property permission
+ isGranted = accessMgr.isGranted(path, Permission.SET_PROPERTY);
+ }
+
+ if (!isGranted) {
+ String msg = itemMgr.safeGetJCRPath(path) + ": not allowed to add or modify item";
+ log.debug(msg);
+ throw new AccessDeniedException(msg);
+ }
+ }
+
+ if (itemState.isNode()) {
+ // the transient item is a node
+ NodeState nodeState = (NodeState) itemState;
+ ItemId id = nodeState.getNodeId();
+ NodeDefinition nodeDef = (NodeDefinition) def;
+ // primary type
+ NodeTypeImpl pnt = ntMgr.getNodeType(nodeState.getNodeTypeName());
+ // effective node type (primary type incl. mixins)
+ EffectiveNodeType ent = getEffectiveNodeType(
+ context.getRepositoryContext().getNodeTypeRegistry(),
+ nodeState);
+ /**
+ * if the transient node was added (i.e. if it is 'new') or if
+ * its primary type has changed, check its node type against the
+ * required node type in its definition
+ */
+ boolean primaryTypeChanged =
+ nodeState.getStatus() == ItemState.STATUS_NEW;
+ if (!primaryTypeChanged) {
+ NodeState overlaid =
+ (NodeState) nodeState.getOverlayedState();
+ if (overlaid != null) {
+ Name newName = nodeState.getNodeTypeName();
+ Name oldName = overlaid.getNodeTypeName();
+ primaryTypeChanged = !newName.equals(oldName);
+ }
+ }
+ if (primaryTypeChanged) {
+ for (NodeType ntReq : nodeDef.getRequiredPrimaryTypes()) {
+ Name ntName = ((NodeTypeImpl) ntReq).getQName();
+ if (!(pnt.getQName().equals(ntName)
+ || pnt.isDerivedFrom(ntName))) {
+ /**
+ * the transient node's primary node type does not
+ * satisfy the 'required primary types' constraint
+ */
+ String msg = itemMgr.safeGetJCRPath(id)
+ + " must be of node type " + ntReq.getName();
+ log.debug(msg);
+ throw new ConstraintViolationException(msg);
+ }
+ }
+ }
+
+ // mandatory child properties
+ for (QPropertyDefinition pd : ent.getMandatoryPropDefs()) {
+ if (pd.getDeclaringNodeType().equals(NameConstants.MIX_VERSIONABLE)
+ || pd.getDeclaringNodeType().equals(NameConstants.MIX_SIMPLE_VERSIONABLE)) {
+ /**
+ * todo FIXME workaround for mix:versionable:
+ * the mandatory properties are initialized at a
+ * later stage and might not exist yet
+ */
+ continue;
+ }
+ String msg = itemMgr.safeGetJCRPath(id)
+ + ": mandatory property " + pd.getName()
+ + " does not exist";
+ if (!nodeState.hasPropertyName(pd.getName())) {
+ log.debug(msg);
+ throw new ConstraintViolationException(msg);
+ } else {
+ /*
+ there exists a property with the mandatory-name.
+ make sure the property really has the expected mandatory
+ property definition (and not another non-mandatory def,
+ such as e.g. multivalued residual instead of single-value
+ mandatory, named def).
+ */
+ PropertyId pi = new PropertyId(nodeState.getNodeId(), pd.getName());
+ ItemData childData = itemMgr.getItemData(pi, null, false);
+ if (!childData.getDefinition().isMandatory()) {
+ throw new ConstraintViolationException(msg);
+ }
+ }
+ }
+ // mandatory child nodes
+ for (QItemDefinition cnd : ent.getMandatoryNodeDefs()) {
+ String msg = itemMgr.safeGetJCRPath(id)
+ + ": mandatory child node " + cnd.getName()
+ + " does not exist";
+ if (!nodeState.hasChildNodeEntry(cnd.getName())) {
+ log.debug(msg);
+ throw new ConstraintViolationException(msg);
+ } else {
+ /*
+ there exists a child node with the mandatory-name.
+ make sure the node really has the expected mandatory
+ node definition.
+ */
+ boolean hasMandatoryChild = false;
+ for (ChildNodeEntry cne : nodeState.getChildNodeEntries(cnd.getName())) {
+ ItemData childData = itemMgr.getItemData(cne.getId(), null, false);
+ if (childData.getDefinition().isMandatory()) {
+ hasMandatoryChild = true;
+ break;
+ }
+ }
+ if (!hasMandatoryChild) {
+ throw new ConstraintViolationException(msg);
+ }
+ }
+ }
+ } else {
+ // the transient item is a property
+ PropertyState propState = (PropertyState) itemState;
+ ItemId propId = propState.getPropertyId();
+ org.apache.jackrabbit.spi.commons.nodetype.PropertyDefinitionImpl propDef = (org.apache.jackrabbit.spi.commons.nodetype.PropertyDefinitionImpl) def;
+
+ /**
+ * check value constraints
+ * (no need to check value constraints of protected properties
+ * as those are set by the implementation only, i.e. they
+ * cannot be set by the user through the api)
+ */
+ if (!def.isProtected()) {
+ String[] constraints = propDef.getValueConstraints();
+ if (constraints != null) {
+ InternalValue[] values = propState.getValues();
+ try {
+ EffectiveNodeType.checkSetPropertyValueConstraints(
+ propDef.unwrap(), values);
+ } catch (RepositoryException e) {
+ // repack exception for providing more verbose error message
+ String msg = itemMgr.safeGetJCRPath(propId) + ": " + e.getMessage();
+ log.debug(msg);
+ throw new ConstraintViolationException(msg);
+ }
+
+ /**
+ * need to manually check REFERENCE value constraints
+ * as this requires a session (target node needs to
+ * be checked)
+ */
+ if (constraints.length > 0
+ && (propDef.getRequiredType() == PropertyType.REFERENCE
+ || propDef.getRequiredType() == PropertyType.WEAKREFERENCE)) {
+ for (InternalValue internalV : values) {
+ boolean satisfied = false;
+ String constraintViolationMsg = null;
+ try {
+ NodeId targetId = internalV.getNodeId();
+ if (propDef.getRequiredType() == PropertyType.WEAKREFERENCE
+ && !itemMgr.itemExists(targetId)) {
+ // target of weakref doesn;t exist, skip
+ continue;
+ }
+ Node targetNode = session.getNodeById(targetId);
+ /**
+ * constraints are OR-ed, i.e. at least one
+ * has to be satisfied
+ */
+ for (String constrNtName : constraints) {
+ /**
+ * a [WEAK]REFERENCE value constraint specifies
+ * the name of the required node type of
+ * the target node
+ */
+ if (targetNode.isNodeType(constrNtName)) {
+ satisfied = true;
+ break;
+ }
+ }
+ if (!satisfied) {
+ NodeType[] mixinNodeTypes = targetNode.getMixinNodeTypes();
+ String[] targetMixins = new String[mixinNodeTypes.length];
+ for (int j = 0; j < mixinNodeTypes.length; j++) {
+ targetMixins[j] = mixinNodeTypes[j].getName();
+ }
+ String targetMixinsString = Text.implode(targetMixins, ", ");
+ String constraintsString = Text.implode(constraints, ", ");
+ constraintViolationMsg = itemMgr.safeGetJCRPath(propId)
+ + ": is constraint to ["
+ + constraintsString
+ + "] but references [primaryType="
+ + targetNode.getPrimaryNodeType().getName()
+ + ", mixins="
+ + targetMixinsString + "]";
+ }
+ } catch (RepositoryException re) {
+ String msg = itemMgr.safeGetJCRPath(propId)
+ + ": failed to check "
+ + ((propDef.getRequiredType() == PropertyType.REFERENCE) ? "REFERENCE" : "WEAKREFERENCE")
+ + " value constraint";
+ log.debug(msg);
+ throw new ConstraintViolationException(msg, re);
+ }
+ if (!satisfied) {
+ log.debug(constraintViolationMsg);
+ throw new ConstraintViolationException(constraintViolationMsg);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * no need to check the protected flag as this is checked
+ * in PropertyImpl.setValue(Value)
+ */
+ }
+ }
+
+ // walk through list of removed transient items and check REMOVE permission
+ for (ItemState itemState : removed) {
+ QItemDefinition def;
+ try {
+ if (itemState.isNode()) {
+ def = itemMgr.getDefinition((NodeState) itemState).unwrap();
+ } else {
+ def = itemMgr.getDefinition((PropertyState) itemState).unwrap();
+ }
+ } catch (ConstraintViolationException e) {
+ // since identifier of assigned definition is not stored anymore
+ // with item state (see JCR-2170), correct definition cannot be
+ // determined for items which have been removed due to removal
+ // of a mixin (see also JCR-2130 & JCR-2408)
+ continue;
+ }
+ if (!def.isProtected()) {
+ Path path = stateMgr.getAtticAwareHierarchyMgr().getPath(itemState.getId());
+ // check REMOVE permission
+ int permission = (itemState.isNode()) ? Permission.REMOVE_NODE : Permission.REMOVE_PROPERTY;
+ if (!accessMgr.isGranted(path, permission)) {
+ String msg = itemMgr.safeGetJCRPath(path)
+ + ": not allowed to remove item";
+ log.debug(msg);
+ throw new AccessDeniedException(msg);
+ }
+ }
+ }
+ }
+
+ /**
+ * walk through list of transient items marked 'removed' and
+ * definitively remove each one
+ */
+ private void removeTransientItems(
+ SessionItemStateManager sism, Iterable states) throws StaleItemStateException {
+ for (ItemState transientState : states) {
+ ItemState persistentState = transientState.getOverlayedState();
+ // remove persistent state
+ // this will indirectly (through stateDestroyed listener method)
+ // permanently invalidate all Item instances wrapping it
+ assert persistentState != null;
+ if (transientState.getModCount() != persistentState.getModCount()) {
+ throw new StaleItemStateException(transientState.getId() + " has been modified externally");
+ }
+ sism.destroy(persistentState);
+ }
+ }
+
+ /**
+ * Process all items given in iterator and check whether mix:shareable
+ * or (some derived node type) has been added or removed:
+ *
+ *
If the mixin mix:shareable (or some derived node type),
+ * then initialize the shared set inside the state.
+ *
If the mixin mix:shareable (or some derived node type)
+ * has been removed, throw.
+ *
+ */
+ private void processShareableNodes(
+ NodeTypeRegistry registry, Iterable states)
+ throws RepositoryException {
+ for (ItemState is : states) {
+ if (is.isNode()) {
+ NodeState ns = (NodeState) is;
+ boolean wasShareable = false;
+ if (ns.hasOverlayedState()) {
+ NodeState old = (NodeState) ns.getOverlayedState();
+ EffectiveNodeType ntOld = getEffectiveNodeType(registry, old);
+ wasShareable = ntOld.includesNodeType(NameConstants.MIX_SHAREABLE);
+ }
+ EffectiveNodeType ntNew = getEffectiveNodeType(registry, ns);
+ boolean isShareable = ntNew.includesNodeType(NameConstants.MIX_SHAREABLE);
+
+ if (!wasShareable && isShareable) {
+ // mix:shareable has been added
+ ns.addShare(ns.getParentId());
+
+ } else if (wasShareable && !isShareable) {
+ // mix:shareable has been removed: not supported
+ String msg = "Removing mix:shareable is not supported.";
+ log.debug(msg);
+ throw new UnsupportedRepositoryOperationException(msg);
+ }
+ }
+ }
+ }
+
+ /**
+ * Initialises the version history of all new nodes of node type
+ * mix:versionable.
+ *
+ * @param states
+ * @return true if this call generated new transient state; otherwise false
+ * @throws RepositoryException
+ */
+ private boolean initVersionHistories(
+ SessionContext context, Iterable states)
+ throws RepositoryException {
+ SessionImpl session = context.getSessionImpl();
+ ItemManager itemMgr = context.getItemManager();
+
+ // walk through list of transient items and search for new versionable nodes
+ boolean createdTransientState = false;
+ for (ItemState itemState : states) {
+ if (itemState.isNode()) {
+ NodeState nodeState = (NodeState) itemState;
+ EffectiveNodeType nt = getEffectiveNodeType(
+ context.getRepositoryContext().getNodeTypeRegistry(),
+ nodeState);
+ if (nt.includesNodeType(NameConstants.MIX_VERSIONABLE)) {
+ if (!nodeState.hasPropertyName(NameConstants.JCR_VERSIONHISTORY)) {
+ NodeImpl node = (NodeImpl) itemMgr.getItem(itemState.getId(), false);
+ InternalVersionManager vMgr = session.getInternalVersionManager();
+ /**
+ * check if there's already a version history for that
+ * node; this would e.g. be the case if a versionable
+ * node had been exported, removed and re-imported with
+ * either IMPORT_UUID_COLLISION_REMOVE_EXISTING or
+ * IMPORT_UUID_COLLISION_REPLACE_EXISTING;
+ * otherwise create a new version history
+ */
+ VersionHistoryInfo history =
+ vMgr.getVersionHistory(session, nodeState, null);
+ InternalValue historyId = InternalValue.create(
+ history.getVersionHistoryId());
+ InternalValue versionId = InternalValue.create(
+ history.getRootVersionId());
+ node.internalSetProperty(
+ NameConstants.JCR_VERSIONHISTORY, historyId);
+ node.internalSetProperty(
+ NameConstants.JCR_BASEVERSION, versionId);
+ node.internalSetProperty(
+ NameConstants.JCR_ISCHECKEDOUT,
+ InternalValue.create(true));
+ node.internalSetProperty(
+ NameConstants.JCR_PREDECESSORS,
+ new InternalValue[] { versionId });
+ createdTransientState = true;
+ }
+ } else if (nt.includesNodeType(NameConstants.MIX_SIMPLE_VERSIONABLE)) {
+ // we need to check the version manager for an existing
+ // version history, since simple versioning does not
+ // expose it's reference in a property
+ InternalVersionManager vMgr = session.getInternalVersionManager();
+ vMgr.getVersionHistory(session, nodeState, null);
+
+ // create isCheckedOutProperty if not already exists
+ NodeImpl node = (NodeImpl) itemMgr.getItem(itemState.getId(), false);
+ if (!nodeState.hasPropertyName(NameConstants.JCR_ISCHECKEDOUT)) {
+ node.internalSetProperty(
+ NameConstants.JCR_ISCHECKEDOUT,
+ InternalValue.create(true));
+ createdTransientState = true;
+ }
+ }
+ }
+ }
+ return createdTransientState;
+ }
+
+ /**
+ * walk through list of transient items and persist each one
+ */
+ private void persistTransientItems(
+ ItemManager itemMgr, Iterable states)
+ throws RepositoryException {
+ for (ItemState state : states) {
+ // persist state of transient item
+ itemMgr.getItem(state.getId(), false).makePersistent();
+ }
+ }
+
+ /**
+ * walk through list of transient states and re-apply transient changes
+ */
+ private void restoreTransientItems(
+ SessionContext context, Iterable items) {
+ ItemManager itemMgr = context.getItemManager();
+ SessionItemStateManager stateMgr = context.getItemStateManager();
+
+ for (ItemState itemState : items) {
+ ItemId id = itemState.getId();
+ ItemImpl item;
+
+ try {
+ if (stateMgr.isItemStateInAttic(id)) {
+ // If an item has been removed and then again created, the
+ // item is lost after persistTransientItems() and the
+ // TransientItemStateManager will bark because of a deleted
+ // state in its attic. We therefore have to forge a new item
+ // instance ourself.
+ item = itemMgr.createItemInstance(itemState);
+ itemState.setStatus(ItemState.STATUS_NEW);
+ } else {
+ try {
+ item = itemMgr.getItem(id, false);
+ } catch (ItemNotFoundException infe) {
+ // itemState probably represents a 'new' item and the
+ // ItemImpl instance wrapping it has already been gc'ed;
+ // we have to re-create the ItemImpl instance
+ item = itemMgr.createItemInstance(itemState);
+ itemState.setStatus(ItemState.STATUS_NEW);
+ }
+ }
+ // re-apply transient changes
+ // for persistent nodes undo effect of item.makePersistent()
+ if (item.isNode()) {
+ NodeImpl node = (NodeImpl) item;
+ node.restoreTransient((NodeState) itemState);
+ } else {
+ PropertyImpl prop = (PropertyImpl) item;
+ prop.restoreTransient((PropertyState) itemState);
+ }
+ } catch (RepositoryException re) {
+ // something went wrong, log exception and carry on
+ String msg = itemMgr.safeGetJCRPath(id)
+ + ": failed to restore transient state";
+ if (log.isDebugEnabled()) {
+ log.warn(msg, re);
+ } else {
+ log.warn(msg);
+ }
+ }
+ }
+ }
+
+ /**
+ * Helper method that builds the effective (i.e. merged and resolved)
+ * node type representation of the specified node's primary and mixin
+ * node types.
+ *
+ * @param state
+ * @return the effective node type
+ * @throws RepositoryException
+ */
+ private EffectiveNodeType getEffectiveNodeType(
+ NodeTypeRegistry registry, NodeState state)
+ throws RepositoryException {
+ try {
+ return registry.getEffectiveNodeType(
+ state.getNodeTypeName(), state.getMixinTypeNames());
+ } catch (NodeTypeConflictException e) {
+ throw new RepositoryException(
+ "Failed to build effective node type of node state "
+ + state.getId(), e);
+ }
+ }
+
+
+ //--------------------------------------------------------------< Object >
+
+ /**
+ * Returns a string representation of this operation.
+ */
+ public String toString() {
+ return "item.save()";
+ }
+
+}
\ No newline at end of file
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemValidator.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemValidator.java
new file mode 100644
index 00000000000..eb08c56812c
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ItemValidator.java
@@ -0,0 +1,547 @@
+/*
+ * 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.jackrabbit.core;
+
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.NamespaceException;
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.lock.LockException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.ItemDefinition;
+import javax.jcr.version.VersionException;
+
+import org.apache.jackrabbit.core.id.ItemId;
+import org.apache.jackrabbit.core.nodetype.EffectiveNodeType;
+import org.apache.jackrabbit.core.nodetype.NodeTypeConflictException;
+import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.core.security.authorization.Permission;
+import org.apache.jackrabbit.core.session.SessionContext;
+import org.apache.jackrabbit.core.session.SessionOperation;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.PropertyState;
+import org.apache.jackrabbit.core.value.InternalValue;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.QPropertyDefinition;
+import org.apache.jackrabbit.spi.QItemDefinition;
+import org.apache.jackrabbit.spi.QNodeDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class for validating an item against constraints
+ * specified by its definition.
+ */
+public class ItemValidator {
+
+ /**
+ * check access permissions
+ */
+ public static final int CHECK_ACCESS = 1;
+
+ /**
+ * option to check lock status
+ */
+ public static final int CHECK_LOCK = 2;
+
+ /**
+ * option to check checked-out status
+ */
+ public static final int CHECK_CHECKED_OUT = 4;
+
+ /**
+ * check for referential integrity upon removal
+ */
+ public static final int CHECK_REFERENCES = 8;
+
+ /**
+ * option to check if the item is protected by it's nt definition
+ */
+ public static final int CHECK_CONSTRAINTS = 16;
+
+ /**
+ * option to check for pending changes on the session
+ */
+ public static final int CHECK_PENDING_CHANGES = 32;
+
+ /**
+ * option to check for pending changes on the specified node
+ */
+ public static final int CHECK_PENDING_CHANGES_ON_NODE = 64;
+
+ /**
+ * option to check for effective holds
+ */
+ public static final int CHECK_HOLD = 128;
+
+ /**
+ * option to check for effective retention policies
+ */
+ public static final int CHECK_RETENTION = 256;
+
+ /**
+ * Logger instance for this class
+ */
+ private static Logger log = LoggerFactory.getLogger(ItemValidator.class);
+
+ /**
+ * Component context of the associated session.
+ */
+ protected final SessionContext context;
+
+ /**
+ * A bit mask of the checks that are currently enabled. All access to
+ * this mask must be synchronized to ensure that only the thread that
+ * uses the {@link #performRelaxed(SessionOperation, int)} method will
+ * experience the effect of the relaxed set of checks.
+ */
+ private int enabledChecks = ~0;
+
+ /**
+ * Creates a new ItemValidator instance.
+ *
+ * @param context component context of this session
+ */
+ public ItemValidator(SessionContext context) {
+ this.context = context;
+ }
+
+ /**
+ * Performs the given session operation with the specified checks disabled.
+ *
+ * @param operation the session operation to be performed
+ * @param checksToDisable bit mask of checks to be disabled
+ * @return return value of the session operation
+ * @throws RepositoryException if the operation could not be performed
+ */
+ public synchronized T performRelaxed(
+ SessionOperation operation, int checksToDisable)
+ throws RepositoryException {
+ int previousChecks = enabledChecks;
+ try {
+ enabledChecks &= ~checksToDisable;
+ log.debug("Performing {} with checks [{}] disabled",
+ operation, Integer.toBinaryString(~enabledChecks));
+ return operation.perform(context);
+ } finally {
+ enabledChecks = previousChecks;
+ }
+ }
+
+ /**
+ * Checks whether the given node state satisfies the constraints specified
+ * by its primary and mixin node types. The following validations/checks are
+ * performed:
+ *
+ *
check if its node type satisfies the 'required node types' constraint
+ * specified in its definition
+ *
check if all 'mandatory' child items exist
+ *
for every property: check if the property value satisfies the
+ * value constraints specified in the property's definition
+ *
+ *
+ * @param nodeState state of node to be validated
+ * @throws ConstraintViolationException if any of the validations fail
+ * @throws RepositoryException if another error occurs
+ */
+ public void validate(NodeState nodeState)
+ throws ConstraintViolationException, RepositoryException {
+ // effective primary node type
+ NodeTypeRegistry registry = context.getNodeTypeRegistry();
+ EffectiveNodeType entPrimary =
+ registry.getEffectiveNodeType(nodeState.getNodeTypeName());
+ // effective node type (primary type incl. mixins)
+ EffectiveNodeType entPrimaryAndMixins = getEffectiveNodeType(nodeState);
+ QNodeDefinition def =
+ context.getItemManager().getDefinition(nodeState).unwrap();
+
+ // check if primary type satisfies the 'required node types' constraint
+ for (Name requiredPrimaryType : def.getRequiredPrimaryTypes()) {
+ if (!entPrimary.includesNodeType(requiredPrimaryType)) {
+ String msg = safeGetJCRPath(nodeState.getNodeId())
+ + ": missing required primary type "
+ + requiredPrimaryType;
+ log.debug(msg);
+ throw new ConstraintViolationException(msg);
+ }
+ }
+ // mandatory properties
+ for (QPropertyDefinition pd : entPrimaryAndMixins.getMandatoryPropDefs()) {
+ if (!nodeState.hasPropertyName(pd.getName())) {
+ String msg = safeGetJCRPath(nodeState.getNodeId())
+ + ": mandatory property " + pd.getName()
+ + " does not exist";
+ log.debug(msg);
+ throw new ConstraintViolationException(msg);
+ }
+ }
+ // mandatory child nodes
+ for (QItemDefinition cnd : entPrimaryAndMixins.getMandatoryNodeDefs()) {
+ if (!nodeState.hasChildNodeEntry(cnd.getName())) {
+ String msg = safeGetJCRPath(nodeState.getNodeId())
+ + ": mandatory child node " + cnd.getName()
+ + " does not exist";
+ log.debug(msg);
+ throw new ConstraintViolationException(msg);
+ }
+ }
+ }
+
+ /**
+ * Checks whether the given property state satisfies the constraints
+ * specified by its definition. The following validations/checks are
+ * performed:
+ *
+ *
check if the type of the property values does comply with the
+ * requiredType specified in the property's definition
+ *
check if the property values satisfy the value constraints
+ * specified in the property's definition
+ *
+ *
+ * @param propState state of property to be validated
+ * @throws ConstraintViolationException if any of the validations fail
+ * @throws RepositoryException if another error occurs
+ */
+ public void validate(PropertyState propState)
+ throws ConstraintViolationException, RepositoryException {
+ QPropertyDefinition def =
+ context.getItemManager().getDefinition(propState).unwrap();
+ InternalValue[] values = propState.getValues();
+ int type = PropertyType.UNDEFINED;
+ for (InternalValue value : values) {
+ if (type == PropertyType.UNDEFINED) {
+ type = value.getType();
+ } else if (type != value.getType()) {
+ throw new ConstraintViolationException(safeGetJCRPath(propState.getPropertyId())
+ + ": inconsistent value types");
+ }
+ if (def.getRequiredType() != PropertyType.UNDEFINED
+ && def.getRequiredType() != type) {
+ throw new ConstraintViolationException(safeGetJCRPath(propState.getPropertyId())
+ + ": requiredType constraint is not satisfied");
+ }
+ }
+ EffectiveNodeType.checkSetPropertyValueConstraints(def, values);
+ }
+
+ public synchronized void checkModify(
+ ItemImpl item, int options, int permissions)
+ throws RepositoryException {
+ checkCondition(item, options & enabledChecks, permissions, false);
+ }
+
+ public synchronized void checkRemove(
+ ItemImpl item, int options, int permissions)
+ throws RepositoryException {
+ checkCondition(item, options & enabledChecks, permissions, true);
+ }
+
+ private void checkCondition(ItemImpl item, int options, int permissions, boolean isRemoval) throws RepositoryException {
+ if ((options & CHECK_PENDING_CHANGES) == CHECK_PENDING_CHANGES) {
+ if (item.getSession().hasPendingChanges()) {
+ String msg = "Unable to perform operation. Session has pending changes.";
+ log.debug(msg);
+ throw new InvalidItemStateException(msg);
+ }
+ }
+ if ((options & CHECK_PENDING_CHANGES_ON_NODE) == CHECK_PENDING_CHANGES_ON_NODE) {
+ if (item.isNode() && ((NodeImpl) item).hasPendingChanges()) {
+ String msg = "Unable to perform operation. Session has pending changes.";
+ log.debug(msg);
+ throw new InvalidItemStateException(msg);
+ }
+ }
+ if ((options & CHECK_CONSTRAINTS) == CHECK_CONSTRAINTS) {
+ if (isProtected(item)) {
+ String msg = "Unable to perform operation. Node is protected.";
+ log.debug(msg);
+ throw new ConstraintViolationException(msg);
+ }
+ }
+ if ((options & CHECK_CHECKED_OUT) == CHECK_CHECKED_OUT) {
+ NodeImpl node = (item.isNode()) ? (NodeImpl) item : (NodeImpl) item.getParent();
+ if (!node.isCheckedOut()) {
+ String msg = "Unable to perform operation. Node is checked-in.";
+ log.debug(msg);
+ throw new VersionException(msg);
+ }
+ }
+ if ((options & CHECK_LOCK) == CHECK_LOCK) {
+ checkLock(item);
+ }
+
+ if (permissions > Permission.NONE) {
+ Path path = item.getPrimaryPath();
+ context.getAccessManager().checkPermission(path, permissions);
+ }
+ if ((options & CHECK_HOLD) == CHECK_HOLD) {
+ if (hasHold(item, isRemoval)) {
+ throw new RepositoryException("Unable to perform operation. Node is affected by a hold.");
+ }
+ }
+ if ((options & CHECK_RETENTION) == CHECK_RETENTION) {
+ if (hasRetention(item, isRemoval)) {
+ throw new RepositoryException("Unable to perform operation. Node is affected by a retention.");
+ }
+ }
+ }
+
+ public synchronized boolean canModify(
+ ItemImpl item, int options, int permissions)
+ throws RepositoryException {
+ return hasCondition(item, options & enabledChecks, permissions, false);
+ }
+
+ private boolean hasCondition(ItemImpl item, int options, int permissions, boolean isRemoval) throws RepositoryException {
+ if ((options & CHECK_PENDING_CHANGES) == CHECK_PENDING_CHANGES) {
+ if (item.getSession().hasPendingChanges()) {
+ return false;
+ }
+ }
+ if ((options & CHECK_PENDING_CHANGES_ON_NODE) == CHECK_PENDING_CHANGES_ON_NODE) {
+ if (item.isNode() && ((NodeImpl) item).hasPendingChanges()) {
+ return false;
+ }
+ }
+ if ((options & CHECK_CONSTRAINTS) == CHECK_CONSTRAINTS) {
+ if (isProtected(item)) {
+ return false;
+ }
+ }
+ if ((options & CHECK_CHECKED_OUT) == CHECK_CHECKED_OUT) {
+ NodeImpl node = (item.isNode()) ? (NodeImpl) item : (NodeImpl) item.getParent();
+ if (!node.isCheckedOut()) {
+ return false;
+ }
+ }
+ if ((options & CHECK_LOCK) == CHECK_LOCK) {
+ try {
+ checkLock(item);
+ } catch (LockException e) {
+ return false;
+ }
+ }
+ if (permissions > Permission.NONE) {
+ Path path = item.getPrimaryPath();
+ if (!context.getAccessManager().isGranted(path, permissions)) {
+ return false;
+ }
+ }
+ if ((options & CHECK_HOLD) == CHECK_HOLD) {
+ if (hasHold(item, isRemoval)) {
+ return false;
+ }
+ }
+ if ((options & CHECK_RETENTION) == CHECK_RETENTION) {
+ if (hasRetention(item, isRemoval)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private void checkLock(ItemImpl item) throws LockException, RepositoryException {
+ if (item.isNew()) {
+ // a new item needs no check
+ return;
+ }
+ NodeImpl node = (item.isNode()) ? (NodeImpl) item : (NodeImpl) item.getParent();
+ context.getWorkspace().getInternalLockManager().checkLock(node);
+ }
+
+ private boolean isProtected(ItemImpl item) throws RepositoryException {
+ ItemDefinition def;
+ if (item.isNode()) {
+ def = ((Node) item).getDefinition();
+ } else {
+ def = ((Property) item).getDefinition();
+ }
+ return def.isProtected();
+ }
+
+ private boolean hasHold(ItemImpl item, boolean isRemoval) throws RepositoryException {
+ if (item.isNew()) {
+ return false;
+ }
+ Path path = item.getPrimaryPath();
+ if (!item.isNode()) {
+ path = path.getAncestor(1);
+ }
+ boolean checkParent = (item.isNode() && isRemoval);
+ return context.getSessionImpl().getRetentionRegistry().hasEffectiveHold(path, checkParent);
+ }
+
+ private boolean hasRetention(ItemImpl item, boolean isRemoval) throws RepositoryException {
+ if (item.isNew()) {
+ return false;
+ }
+ Path path = item.getPrimaryPath();
+ if (!item.isNode()) {
+ path = path.getAncestor(1);
+ }
+ boolean checkParent = (item.isNode() && isRemoval);
+ return context.getSessionImpl().getRetentionRegistry().hasEffectiveRetention(path, checkParent);
+ }
+
+
+
+ //-------------------------------------------------< misc. helper methods >
+ /**
+ * Helper method that builds the effective (i.e. merged and resolved)
+ * node type representation of the specified node's primary and mixin
+ * node types.
+ *
+ * @param state
+ * @return the effective node type
+ * @throws RepositoryException
+ */
+ public EffectiveNodeType getEffectiveNodeType(NodeState state)
+ throws RepositoryException {
+ try {
+ return context.getNodeTypeRegistry().getEffectiveNodeType(
+ state.getNodeTypeName(), state.getMixinTypeNames());
+ } catch (NodeTypeConflictException ntce) {
+ String msg = "internal error: failed to build effective node type for node "
+ + safeGetJCRPath(state.getNodeId());
+ log.debug(msg);
+ throw new RepositoryException(msg, ntce);
+ }
+ }
+
+ /**
+ * Helper method that finds the applicable definition for a child node with
+ * the given name and node type in the parent node's node type and
+ * mixin types.
+ *
+ * @param name
+ * @param nodeTypeName
+ * @param parentState
+ * @return a QNodeDefinition
+ * @throws ConstraintViolationException if no applicable child node definition
+ * could be found
+ * @throws RepositoryException if another error occurs
+ */
+ public QNodeDefinition findApplicableNodeDefinition(Name name,
+ Name nodeTypeName,
+ NodeState parentState)
+ throws RepositoryException, ConstraintViolationException {
+ EffectiveNodeType entParent = getEffectiveNodeType(parentState);
+ return entParent.getApplicableChildNodeDef(
+ name, nodeTypeName, context.getNodeTypeRegistry());
+ }
+
+ /**
+ * Helper method that finds the applicable definition for a property with
+ * the given name, type and multiValued characteristic in the parent node's
+ * node type and mixin types. If there more than one applicable definitions
+ * then the following rules are applied:
+ *
+ *
named definitions are preferred to residual definitions
+ *
definitions with specific required type are preferred to definitions
+ * with required type UNDEFINED
+ *
+ *
+ * @param name
+ * @param type
+ * @param multiValued
+ * @param parentState
+ * @return a QPropertyDefinition
+ * @throws ConstraintViolationException if no applicable property definition
+ * could be found
+ * @throws RepositoryException if another error occurs
+ */
+ public QPropertyDefinition findApplicablePropertyDefinition(Name name,
+ int type,
+ boolean multiValued,
+ NodeState parentState)
+ throws RepositoryException, ConstraintViolationException {
+ EffectiveNodeType entParent = getEffectiveNodeType(parentState);
+ return entParent.getApplicablePropertyDef(name, type, multiValued);
+ }
+
+ /**
+ * Helper method that finds the applicable definition for a property with
+ * the given name, type in the parent node's node type and mixin types.
+ * Other than {@link #findApplicablePropertyDefinition(Name, int, boolean, NodeState)}
+ * this method does not take the multiValued flag into account in the
+ * selection algorithm. If there more than one applicable definitions then
+ * the following rules are applied:
+ *
+ *
named definitions are preferred to residual definitions
+ *
definitions with specific required type are preferred to definitions
+ * with required type UNDEFINED
+ *
single-value definitions are preferred to multiple-value definitions
+ *
+ *
+ * @param name
+ * @param type
+ * @param parentState
+ * @return a QPropertyDefinition
+ * @throws ConstraintViolationException if no applicable property definition
+ * could be found
+ * @throws RepositoryException if another error occurs
+ */
+ public QPropertyDefinition findApplicablePropertyDefinition(Name name,
+ int type,
+ NodeState parentState)
+ throws RepositoryException, ConstraintViolationException {
+ EffectiveNodeType entParent = getEffectiveNodeType(parentState);
+ return entParent.getApplicablePropertyDef(name, type);
+ }
+
+ /**
+ * Failsafe conversion of internal Path to JCR path for use in
+ * error messages etc.
+ *
+ * @param path path to convert
+ * @return JCR path
+ */
+ public String safeGetJCRPath(Path path) {
+ try {
+ return context.getJCRPath(path);
+ } catch (NamespaceException e) {
+ log.error("failed to convert {} to a JCR path", path);
+ // return string representation of internal path as a fallback
+ return path.toString();
+ }
+ }
+
+ /**
+ * Failsafe translation of internal ItemId to JCR path for use
+ * in error messages etc.
+ *
+ * @param id id to translate
+ * @return JCR path
+ */
+ public String safeGetJCRPath(ItemId id) {
+ try {
+ return safeGetJCRPath(
+ context.getHierarchyManager().getPath(id));
+ } catch (ItemNotFoundException e) {
+ // return string representation of id as a fallback
+ return id.toString();
+ } catch (RepositoryException e) {
+ log.error(id + ": failed to build path");
+ // return string representation of id as a fallback
+ return id.toString();
+ }
+ }
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/JackrabbitRepositoryStub.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/JackrabbitRepositoryStub.java
new file mode 100644
index 00000000000..32bf2f05449
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/JackrabbitRepositoryStub.java
@@ -0,0 +1,236 @@
+/*
+ * 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.jackrabbit.core;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.Principal;
+import java.security.acl.Group;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.core.config.RepositoryConfig;
+import org.apache.jackrabbit.test.NotExecutableException;
+import org.apache.jackrabbit.test.RepositoryStub;
+import org.apache.jackrabbit.test.RepositoryStubException;
+
+/**
+ * RepositoryStub implementation for Apache Jackrabbit.
+ *
+ * @since Apache Jackrabbit 1.6
+ */
+public class JackrabbitRepositoryStub extends RepositoryStub {
+
+ /**
+ * Property for the repository configuration file. Defaults to
+ * <repository home>/repository.xml if not specified.
+ */
+ public static final String PROP_REPOSITORY_CONFIG =
+ "org.apache.jackrabbit.repository.config";
+
+ /**
+ * Property for the repository home directory. Defaults to
+ * target/repository for convenience in Maven builds.
+ */
+ public static final String PROP_REPOSITORY_HOME =
+ "org.apache.jackrabbit.repository.home";
+
+ /**
+ * Repository settings.
+ */
+ private final Properties settings;
+
+ /**
+ * Map of repository instances. Key = repository home, value = repository
+ * instance.
+ */
+ private static final Map REPOSITORY_INSTANCES = new HashMap();
+
+ static {
+ Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
+ public void run() {
+ synchronized (REPOSITORY_INSTANCES) {
+ for (Repository repo : REPOSITORY_INSTANCES.values()) {
+ if (repo instanceof RepositoryImpl) {
+ ((RepositoryImpl) repo).shutdown();
+ }
+ }
+ }
+ }
+ }));
+ }
+
+ public static RepositoryContext getRepositoryContext(
+ Repository repository) {
+ synchronized (REPOSITORY_INSTANCES) {
+ for (Repository r : REPOSITORY_INSTANCES.values()) {
+ if (r == repository) {
+ return ((RepositoryImpl) r).context;
+ }
+ }
+ }
+ throw new RuntimeException("Not a test repository: " + repository);
+ }
+
+ private static Properties getStaticProperties() {
+ Properties properties = new Properties();
+ try {
+ InputStream stream =
+ getResource("JackrabbitRepositoryStub.properties");
+ try {
+ properties.load(stream);
+ } finally {
+ stream.close();
+ }
+ } catch (IOException e) {
+ // TODO: Log warning
+ }
+ return properties;
+ }
+
+ private static InputStream getResource(String name) {
+ return JackrabbitRepositoryStub.class.getResourceAsStream(name);
+ }
+
+ /**
+ * Constructor as required by the JCR TCK.
+ *
+ * @param settings repository settings
+ */
+ public JackrabbitRepositoryStub(Properties settings) {
+ super(getStaticProperties());
+ // set some attributes on the sessions
+ superuser.setAttribute("jackrabbit", "jackrabbit");
+ readwrite.setAttribute("jackrabbit", "jackrabbit");
+ readonly.setAttribute("jackrabbit", "jackrabbit");
+
+ // Repository settings
+ this.settings = settings;
+ }
+
+ /**
+ * Returns the configured repository instance.
+ *
+ * @return the configured repository instance.
+ * @throws RepositoryStubException if an error occurs while
+ * obtaining the repository instance.
+ */
+ public synchronized Repository getRepository()
+ throws RepositoryStubException {
+ try {
+ String dir = settings.getProperty(PROP_REPOSITORY_HOME);
+ if (dir == null) {
+ dir = new File("target", "repository").getAbsolutePath();
+ } else {
+ dir = new File(dir).getAbsolutePath();
+ }
+
+ String xml = settings.getProperty(PROP_REPOSITORY_CONFIG);
+ if (xml == null) {
+ xml = new File(dir, "repository.xml").getPath();
+ }
+
+ return getOrCreateRepository(dir, xml);
+ } catch (Exception e) {
+ throw new RepositoryStubException("Failed to start repository", e);
+ }
+ }
+
+ protected Repository createRepository(String dir, String xml)
+ throws Exception {
+ new File(dir).mkdirs();
+
+ if (!new File(xml).exists()) {
+ InputStream input = getResource("repository.xml");
+ try {
+ OutputStream output = new FileOutputStream(xml);
+ try {
+ IOUtils.copy(input, output);
+ } finally {
+ output.close();
+ }
+ } finally {
+ input.close();
+ }
+ }
+
+ RepositoryConfig config = RepositoryConfig.create(xml, dir);
+ return RepositoryImpl.create(config);
+ }
+
+ protected Repository getOrCreateRepository(String dir, String xml)
+ throws Exception {
+ synchronized (REPOSITORY_INSTANCES) {
+ Repository repo = REPOSITORY_INSTANCES.get(dir);
+ if (repo == null) {
+ repo = createRepository(dir, xml);
+ Session session = repo.login(superuser);
+ try {
+ TestContentLoader loader = new TestContentLoader();
+ loader.loadTestContent(session);
+ } finally {
+ session.logout();
+ }
+
+ REPOSITORY_INSTANCES.put(dir, repo);
+ }
+ return repo;
+ }
+ }
+
+ @Override
+ public Principal getKnownPrincipal(Session session) throws RepositoryException {
+
+ Principal knownPrincipal = null;
+
+ if (session instanceof SessionImpl) {
+ for (Principal p : ((SessionImpl)session).getSubject().getPrincipals()) {
+ if (! (p instanceof Group)) {
+ knownPrincipal = p;
+ }
+ }
+ }
+
+ if (knownPrincipal != null) {
+ return knownPrincipal;
+ }
+ else {
+ throw new RepositoryException("no applicable principal found");
+ }
+ }
+
+ private static Principal UNKNOWN_PRINCIPAL = new Principal() {
+ public String getName() {
+ return "an_unknown_user";
+ }
+ };
+
+ @Override
+ public Principal getUnknownPrincipal(Session session) throws RepositoryException, NotExecutableException {
+ return UNKNOWN_PRINCIPAL;
+ }
+
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/JackrabbitThreadPool.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/JackrabbitThreadPool.java
new file mode 100644
index 00000000000..77e491374db
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/JackrabbitThreadPool.java
@@ -0,0 +1,220 @@
+/*
+ * 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.jackrabbit.core;
+
+import java.util.concurrent.RejectedExecutionHandler;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Thread pool used by the repository.
+ */
+class JackrabbitThreadPool extends ScheduledThreadPoolExecutor {
+
+ /**
+ * The logger instance for this class.
+ */
+ private static final Logger log = LoggerFactory
+ .getLogger(JackrabbitThreadPool.class);
+
+ /**
+ * Size of the per-repository thread pool.
+ */
+ private static final int size =
+ Runtime.getRuntime().availableProcessors() * 2;
+
+ /**
+ * The classloader used as the context classloader of threads in the pool.
+ */
+ private static final ClassLoader loader =
+ JackrabbitThreadPool.class.getClassLoader();
+
+ /**
+ * Thread counter for generating unique names for the threads in the pool.
+ */
+ private static final AtomicInteger counter = new AtomicInteger(1);
+
+ /**
+ * Thread factory for creating the threads in the pool
+ */
+ private static final ThreadFactory factory = new ThreadFactory() {
+ public Thread newThread(Runnable runnable) {
+ int count = counter.getAndIncrement();
+ String name = "jackrabbit-pool-" + count;
+ Thread thread = new Thread(runnable, name);
+ thread.setDaemon(true);
+ if (thread.getPriority() != Thread.NORM_PRIORITY) {
+ thread.setPriority(Thread.NORM_PRIORITY);
+ }
+ thread.setContextClassLoader(loader);
+ return thread;
+ }
+ };
+
+ /**
+ * Handler for tasks for which no free thread is found within the pool.
+ */
+ private static final RejectedExecutionHandler handler = new CallerRunsPolicy();
+
+ /**
+ * Property to control the value at which the thread pool starts to schedule
+ * the {@link LowPriorityTask} tasks for later execution.
+ *
+ * Set to 0 to disable the check
+ *
+ * Default value is 0 (check is disabled).
+ *
+ */
+ public static final String MAX_LOAD_FOR_LOW_PRIORITY_TASKS_PROPERTY = "org.apache.jackrabbit.core.JackrabbitThreadPool.maxLoadForLowPriorityTasks";
+
+ /**
+ * @see #MAX_LOAD_FOR_LOW_PRIORITY_TASKS_PROPERTY
+ */
+ private final static Integer maxLoadForLowPriorityTasks = getMaxLoadForLowPriorityTasks();
+
+ private static int getMaxLoadForLowPriorityTasks() {
+ final int defaultMaxLoad = 75;
+ int max = Integer.getInteger(MAX_LOAD_FOR_LOW_PRIORITY_TASKS_PROPERTY,
+ defaultMaxLoad);
+ if (max < 0 || max > 100) {
+ return defaultMaxLoad;
+ }
+ return max;
+ }
+
+ /**
+ * Queue where all the {@link LowPriorityTask} tasks go for later execution
+ */
+ private final BlockingQueue lowPriorityTasksQueue = new LinkedBlockingQueue();
+
+ /**
+ * Tasks that handles the scheduling and the execution of
+ * {@link LowPriorityTask} tasks
+ */
+ private final RetryLowPriorityTask retryTask;
+
+ /**
+ * Creates a new thread pool.
+ */
+ public JackrabbitThreadPool() {
+ super(size, factory, handler);
+ retryTask = new RetryLowPriorityTask(this, lowPriorityTasksQueue);
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ if (command instanceof LowPriorityTask) {
+ scheduleLowPriority(command);
+ return;
+ }
+ super.execute(command);
+ }
+
+ private void scheduleLowPriority(Runnable command) {
+ if (isOverDefinedMaxLoad()) {
+ lowPriorityTasksQueue.add(command);
+ retryTask.retryLater();
+ return;
+ }
+ super.execute(command);
+ }
+
+ /**
+ * compares the current load of the executor with the defined
+ * {@link #maxLoadForLowPriorityTasks} parameter.
+ *
+ * Used to determine if the executor can handle additional
+ * {@link LowPriorityTask} tasks.
+ *
+ * @return true if the load is under the
+ * {@link #maxLoadForLowPriorityTasks} parameter
+ */
+ private boolean isOverDefinedMaxLoad() {
+ if (maxLoadForLowPriorityTasks == 0) {
+ return false;
+ }
+ double currentLoad = ((double) getActiveCount()) / getPoolSize() * 100;
+ return currentLoad > maxLoadForLowPriorityTasks;
+ }
+
+ /**
+ * TEST ONLY
+ *
+ * @return the number of low priority tasks that are waiting in the queue
+ */
+ int getPendingLowPriorityTaskCount() {
+ return lowPriorityTasksQueue.size();
+ }
+
+ private static final class RetryLowPriorityTask implements Runnable {
+
+ /**
+ * schedule interval in ms for delayed tasks
+ */
+ private static final int LATER_MS = 50;
+
+ private final JackrabbitThreadPool executor;
+ private final BlockingQueue lowPriorityTasksQueue;
+
+ /**
+ * flag to indicate that another execute has been scheduled or is
+ * currently running.
+ */
+ private final AtomicBoolean retryPending;
+
+ public RetryLowPriorityTask(JackrabbitThreadPool executor,
+ BlockingQueue lowPriorityTasksQueue) {
+ this.executor = executor;
+ this.lowPriorityTasksQueue = lowPriorityTasksQueue;
+ this.retryPending = new AtomicBoolean(false);
+ }
+
+ public void retryLater() {
+ if (!retryPending.getAndSet(true)) {
+ executor.schedule(this, LATER_MS, TimeUnit.MILLISECONDS);
+ }
+ }
+
+ public void run() {
+ int count = 0;
+ while (!executor.isOverDefinedMaxLoad()) {
+ Runnable r = lowPriorityTasksQueue.poll();
+ if (r == null) {
+ log.debug("Executed {} low priority tasks.", count);
+ break;
+ }
+ count++;
+ executor.execute(r);
+ }
+ retryPending.set(false);
+ if (!lowPriorityTasksQueue.isEmpty()) {
+ log.debug(
+ "Executor is under load, will schedule {} remaining tasks for {} ms later",
+ lowPriorityTasksQueue.size(), LATER_MS);
+ retryLater();
+ }
+ }
+ }
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/LazyItemIterator.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/LazyItemIterator.java
new file mode 100644
index 00000000000..21b584380dd
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/LazyItemIterator.java
@@ -0,0 +1,269 @@
+/*
+ * 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.jackrabbit.core;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.Item;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.id.ItemId;
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.session.SessionContext;
+import org.apache.jackrabbit.core.state.ItemStateManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * LazyItemIterator is an id-based iterator that instantiates
+ * the Items only when they are requested.
+ *
+ * Important:Items that appear to be nonexistent
+ * for some reason (e.g. because of insufficient access rights or because they
+ * have been removed since the iterator has been retrieved) are silently
+ * skipped. As a result the size of the iterator as reported by
+ * {@link #getSize()} might appear to be shrinking while iterating over the
+ * items.
+ * todo should getSize() better always return -1?
+ *
+ * @see #getSize()
+ */
+public class LazyItemIterator implements NodeIterator, PropertyIterator {
+
+ /** Logger instance for this class */
+ private static Logger log = LoggerFactory.getLogger(LazyItemIterator.class);
+
+ /**
+ * The session context used to access the repository.
+ */
+ private final SessionContext sessionContext;
+
+ /** the item manager that is used to lazily fetch the items */
+ private final ItemManager itemMgr;
+
+ /** the list of item ids */
+ private final List idList;
+
+ /** parent node id (when returning children nodes) or null */
+ private final NodeId parentId;
+
+ /** the position of the next item */
+ private int pos;
+
+ /** prefetched item to be returned on {@link #next()} */
+ private Item next;
+
+ /**
+ * Creates a new LazyItemIterator instance.
+ *
+ * @param sessionContext session context
+ * @param idList list of item id's
+ */
+ public LazyItemIterator(SessionContext sessionContext, List< ? extends ItemId> idList) {
+ this(sessionContext, idList, null);
+ }
+
+ /**
+ * Creates a new LazyItemIterator instance, additionally taking
+ * a parent id as parameter. This version should be invoked to strictly return
+ * children nodes of a node.
+ *
+ * @param sessionContext session context
+ * @param idList list of item id's
+ * @param parentId parent id.
+ */
+ public LazyItemIterator(SessionContext sessionContext, List< ? extends ItemId> idList, NodeId parentId) {
+ this.sessionContext = sessionContext;
+ this.itemMgr = sessionContext.getSessionImpl().getItemManager();
+ this.idList = new ArrayList(idList);
+ this.parentId = parentId;
+ // prefetch first item
+ pos = 0;
+ prefetchNext();
+ }
+
+ /**
+ * Prefetches next item.
+ *
+ * {@link #next} is set to the next available item in this iterator or to
+ * null in case there are no more items.
+ */
+ private void prefetchNext() {
+ // reset
+ next = null;
+ while (next == null && pos < idList.size()) {
+ ItemId id = idList.get(pos);
+ try {
+ if (parentId != null) {
+ next = itemMgr.getNode((NodeId) id, parentId);
+ } else {
+ next = itemMgr.getItem(id);
+ }
+ } catch (ItemNotFoundException e) {
+ log.debug("ignoring nonexistent item " + id);
+ // remove invalid id
+ idList.remove(pos);
+
+ // maybe fix the root cause
+ if (parentId != null && sessionContext.getSessionImpl().autoFixCorruptions()) {
+ try {
+ // it might be an access right problem
+ // we need to check if the item doesn't exist in the ism
+ ItemStateManager ism = sessionContext.getItemStateManager();
+ if (!ism.hasItemState(id)) {
+ NodeImpl p = (NodeImpl) itemMgr.getItem(parentId);
+ p.removeChildNode((NodeId) id);
+ p.save();
+ }
+ } catch (RepositoryException e2) {
+ log.error("could not fix repository inconsistency", e);
+ // ignore
+ }
+ }
+
+ // try next
+ } catch (AccessDeniedException e) {
+ log.debug("ignoring nonexistent item " + id);
+ // remove invalid id
+ idList.remove(pos);
+ // try next
+ } catch (RepositoryException e) {
+ log.error("failed to fetch item " + id + ", skipping...", e);
+ // remove invalid id
+ idList.remove(pos);
+ // try next
+ }
+ }
+ }
+
+ //---------------------------------------------------------< NodeIterator >
+ /**
+ * {@inheritDoc}
+ */
+ public Node nextNode() {
+ return (Node) next();
+ }
+
+ //-----------------------------------------------------< PropertyIterator >
+ /**
+ * {@inheritDoc}
+ */
+ public Property nextProperty() {
+ return (Property) next();
+ }
+
+ //--------------------------------------------------------< RangeIterator >
+ /**
+ * {@inheritDoc}
+ */
+ public long getPosition() {
+ return pos;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Note that the size of the iterator as reported by {@link #getSize()}
+ * might appear to be shrinking while iterating because items that for
+ * some reason cannot be retrieved through this iterator are silently
+ * skipped, thus reducing the size of this iterator.
+ *
+ * todo better to always return -1?
+ */
+ public long getSize() {
+ return idList.size();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void skip(long skipNum) {
+ if (skipNum < 0) {
+ throw new IllegalArgumentException("skipNum must not be negative");
+ }
+ if (skipNum == 0) {
+ return;
+ }
+ if (next == null) {
+ throw new NoSuchElementException();
+ }
+
+ // reset
+ next = null;
+ // skip the first (skipNum - 1) items without actually retrieving them
+ while (--skipNum > 0) {
+ pos++;
+ if (pos >= idList.size()) {
+ // skipped past last item
+ throw new NoSuchElementException();
+ }
+ ItemId id = idList.get(pos);
+ // eliminate invalid items from this iterator
+ while (!itemMgr.itemExists(id)) {
+ log.debug("ignoring nonexistent item " + id);
+ // remove invalid id
+ idList.remove(pos);
+ if (pos >= idList.size()) {
+ // skipped past last item
+ throw new NoSuchElementException();
+ }
+ id = idList.get(pos);
+ }
+ }
+ // prefetch final item (the one to be returned on next())
+ pos++;
+ prefetchNext();
+ }
+
+ //-------------------------------------------------------------< Iterator >
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasNext() {
+ return next != null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object next() {
+ if (next == null) {
+ throw new NoSuchElementException();
+ }
+ Item item = next;
+ pos++;
+ prefetchNext();
+ return item;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws UnsupportedOperationException always since not implemented
+ */
+ public void remove() {
+ throw new UnsupportedOperationException("remove");
+ }
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/LowPriorityTask.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/LowPriorityTask.java
new file mode 100644
index 00000000000..caf0c7ab219
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/LowPriorityTask.java
@@ -0,0 +1,26 @@
+/*
+ * 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.jackrabbit.core;
+
+/**
+ * Interface for low priority tasks (like text extraction) that can be scheduled
+ * later based on the extractor's load
+ *
+ * @see JCR-3146.
+ */
+public interface LowPriorityTask extends Runnable {
+}
\ No newline at end of file
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NamespaceRegistryImpl.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NamespaceRegistryImpl.java
new file mode 100644
index 00000000000..f76fcbd482d
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NamespaceRegistryImpl.java
@@ -0,0 +1,526 @@
+/*
+ * 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.jackrabbit.core;
+
+import org.apache.jackrabbit.core.cluster.NamespaceEventChannel;
+import org.apache.jackrabbit.core.cluster.NamespaceEventListener;
+import org.apache.jackrabbit.core.fs.BasedFileSystem;
+import org.apache.jackrabbit.core.fs.FileSystem;
+import org.apache.jackrabbit.core.fs.FileSystemResource;
+import org.apache.jackrabbit.core.util.StringIndex;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.util.XMLChar;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Properties;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.NamespaceException;
+import javax.jcr.NamespaceRegistry;
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+
+/**
+ * A NamespaceRegistryImpl ...
+ */
+public class NamespaceRegistryImpl implements
+ NamespaceRegistry, NamespaceEventListener, StringIndex {
+
+ private static Logger log = LoggerFactory.getLogger(NamespaceRegistryImpl.class);
+
+ /**
+ * Special property key string to be used instead of an empty key to
+ * avoid problems with Java implementations that have problems with
+ * empty keys in property files. The selected value ({@value}) would be
+ * invalid as either a namespace prefix or a URI, so there's little fear
+ * of accidental collisions.
+ *
+ * @see JCR-888
+ */
+ private static final String EMPTY_KEY = ".empty.key";
+
+ private static final String NS_REG_RESOURCE = "ns_reg.properties";
+ private static final String NS_IDX_RESOURCE = "ns_idx.properties";
+
+ private static final HashSet reservedPrefixes = new HashSet();
+ private static final HashSet reservedURIs = new HashSet();
+
+ static {
+ // reserved prefixes
+ reservedPrefixes.add(Name.NS_XML_PREFIX);
+ reservedPrefixes.add(Name.NS_XMLNS_PREFIX);
+ // predefined (e.g. built-in) prefixes
+ reservedPrefixes.add(Name.NS_REP_PREFIX);
+ reservedPrefixes.add(Name.NS_JCR_PREFIX);
+ reservedPrefixes.add(Name.NS_NT_PREFIX);
+ reservedPrefixes.add(Name.NS_MIX_PREFIX);
+ reservedPrefixes.add(Name.NS_SV_PREFIX);
+ // reserved namespace URI's
+ reservedURIs.add(Name.NS_XML_URI);
+ reservedURIs.add(Name.NS_XMLNS_URI);
+ // predefined (e.g. built-in) namespace URI's
+ reservedURIs.add(Name.NS_REP_URI);
+ reservedURIs.add(Name.NS_JCR_URI);
+ reservedURIs.add(Name.NS_NT_URI);
+ reservedURIs.add(Name.NS_MIX_URI);
+ reservedURIs.add(Name.NS_SV_URI);
+ }
+
+ private HashMap prefixToURI = new HashMap();
+ private HashMap uriToPrefix = new HashMap();
+
+ private HashMap indexToURI = new HashMap();
+ private HashMap uriToIndex = new HashMap();
+
+ private final FileSystem nsRegStore;
+
+ /**
+ * Namespace event channel.
+ */
+ private NamespaceEventChannel eventChannel;
+
+ /**
+ * Protected constructor: Constructs a new instance of this class.
+ *
+ * @param fs repository file system
+ * @throws RepositoryException
+ */
+ public NamespaceRegistryImpl(FileSystem fs) throws RepositoryException {
+ this.nsRegStore = new BasedFileSystem(fs, "/namespaces");
+ load();
+ }
+
+ /**
+ * Clears all mappings.
+ */
+ private void clear() {
+ prefixToURI.clear();
+ uriToPrefix.clear();
+ indexToURI.clear();
+ uriToIndex.clear();
+ }
+
+ /**
+ * Adds a new mapping and automatically assigns a new index.
+ *
+ * @param prefix the namespace prefix
+ * @param uri the namespace uri
+ */
+ private void map(String prefix, String uri) {
+ map(prefix, uri, null);
+ }
+
+ /**
+ * Adds a new mapping and uses the given index if specified.
+ *
+ * @param prefix the namespace prefix
+ * @param uri the namespace uri
+ * @param idx the index or null.
+ */
+ private void map(String prefix, String uri, Integer idx) {
+ prefixToURI.put(prefix, uri);
+ uriToPrefix.put(uri, prefix);
+ if (!uriToIndex.containsKey(uri)) {
+ if (idx == null) {
+ // Need to use only 24 bits, since that's what
+ // the BundleBinding class stores in bundles
+ idx = uri.hashCode() & 0x00ffffff;
+ while (indexToURI.containsKey(idx)) {
+ idx = (idx + 1) & 0x00ffffff;
+ }
+ }
+ indexToURI.put(idx, uri);
+ uriToIndex.put(uri, idx);
+ }
+ }
+
+ private void load() throws RepositoryException {
+ FileSystemResource propFile =
+ new FileSystemResource(nsRegStore, NS_REG_RESOURCE);
+ FileSystemResource idxFile =
+ new FileSystemResource(nsRegStore, NS_IDX_RESOURCE);
+ try {
+ if (!propFile.exists()) {
+ // clear existing mappings
+ clear();
+
+ // default namespace (if no prefix is specified)
+ map(Name.NS_EMPTY_PREFIX, Name.NS_DEFAULT_URI);
+
+ // declare the predefined mappings
+ // rep:
+ map(Name.NS_REP_PREFIX, Name.NS_REP_URI);
+ // jcr:
+ map(Name.NS_JCR_PREFIX, Name.NS_JCR_URI);
+ // nt:
+ map(Name.NS_NT_PREFIX, Name.NS_NT_URI);
+ // mix:
+ map(Name.NS_MIX_PREFIX, Name.NS_MIX_URI);
+ // sv:
+ map(Name.NS_SV_PREFIX, Name.NS_SV_URI);
+ // xml:
+ map(Name.NS_XML_PREFIX, Name.NS_XML_URI);
+
+ // persist mappings
+ store();
+ return;
+ }
+
+ // check if index file exists
+ Properties indexes = new Properties();
+ if (idxFile.exists()) {
+ InputStream in = idxFile.getInputStream();
+ try {
+ indexes.load(in);
+ } finally {
+ in.close();
+ }
+ }
+
+ InputStream in = propFile.getInputStream();
+ try {
+ Properties props = new Properties();
+ props.load(in);
+
+ // clear existing mappings
+ clear();
+
+ // read mappings from properties
+ for (Object p : props.keySet()) {
+ String prefix = (String) p;
+ String uri = props.getProperty(prefix);
+ String idx = indexes.getProperty(escapePropertyKey(uri));
+ // JCR-888: Backwards compatibility check
+ if (idx == null && uri.equals("")) {
+ idx = indexes.getProperty(uri);
+ }
+ if (idx != null) {
+ map(unescapePropertyKey(prefix), uri, Integer.decode(idx));
+ } else {
+ map(unescapePropertyKey(prefix), uri);
+ }
+ }
+ } finally {
+ in.close();
+ }
+ if (!idxFile.exists()) {
+ store();
+ }
+ } catch (Exception e) {
+ String msg = "failed to load namespace registry";
+ log.debug(msg);
+ throw new RepositoryException(msg, e);
+ }
+ }
+
+ private void store() throws RepositoryException {
+ FileSystemResource propFile =
+ new FileSystemResource(nsRegStore, NS_REG_RESOURCE);
+ try {
+ propFile.makeParentDirs();
+ OutputStream os = propFile.getOutputStream();
+ Properties props = new Properties();
+
+ // store mappings in properties
+ for (String prefix : prefixToURI.keySet()) {
+ String uri = prefixToURI.get(prefix);
+ props.setProperty(escapePropertyKey(prefix), uri);
+ }
+
+ try {
+ props.store(os, null);
+ } finally {
+ // make sure stream is closed
+ os.close();
+ }
+ } catch (Exception e) {
+ String msg = "failed to persist namespace registry";
+ log.debug(msg);
+ throw new RepositoryException(msg, e);
+ }
+
+ FileSystemResource indexFile =
+ new FileSystemResource(nsRegStore, NS_IDX_RESOURCE);
+ try {
+ indexFile.makeParentDirs();
+ OutputStream os = indexFile.getOutputStream();
+ Properties props = new Properties();
+
+ // store mappings in properties
+ for (String uri : uriToIndex.keySet()) {
+ String index = uriToIndex.get(uri).toString();
+ props.setProperty(escapePropertyKey(uri), index);
+ }
+
+ try {
+ props.store(os, null);
+ } finally {
+ // make sure stream is closed
+ os.close();
+ }
+ } catch (Exception e) {
+ String msg = "failed to persist namespace registry index.";
+ log.debug(msg);
+ throw new RepositoryException(msg, e);
+ }
+ }
+
+ /**
+ * Replaces an empty string with the special {@link #EMPTY_KEY} value.
+ *
+ * @see #unescapePropertyKey(String)
+ * @param key property key
+ * @return escaped property key
+ */
+ private String escapePropertyKey(String key) {
+ if (key.equals("")) {
+ return EMPTY_KEY;
+ } else {
+ return key;
+ }
+ }
+
+ /**
+ * Converts the special {@link #EMPTY_KEY} value back to an empty string.
+ *
+ * @see #escapePropertyKey(String)
+ * @param key property key
+ * @return escaped property key
+ */
+ private String unescapePropertyKey(String key) {
+ if (key.equals(EMPTY_KEY)) {
+ return "";
+ } else {
+ return key;
+ }
+ }
+
+ /**
+ * Set an event channel to inform about changes.
+ *
+ * @param eventChannel event channel
+ */
+ public void setEventChannel(NamespaceEventChannel eventChannel) {
+ this.eventChannel = eventChannel;
+ eventChannel.setListener(this);
+ }
+
+ /**
+ * Returns true if the specified uri is one of the reserved
+ * URIs defined in this registry.
+ *
+ * @param uri The URI to test.
+ * @return true if the specified uri is reserved;
+ * false otherwise.
+ */
+ public boolean isReservedURI(String uri) {
+ return reservedURIs.contains(uri);
+ }
+
+ //-------------------------------------------------------< StringIndex >--
+
+ /**
+ * Returns the index (i.e. stable prefix) for the given namespace URI.
+ *
+ * @param uri namespace URI
+ * @return namespace index
+ * @throws IllegalArgumentException if the namespace is not registered
+ */
+ public int stringToIndex(String uri) {
+ Integer idx = uriToIndex.get(uri);
+ if (idx == null) {
+ throw new IllegalArgumentException("Namespace not registered: " + uri);
+ }
+ return idx;
+ }
+
+ /**
+ * Returns the namespace URI for a given index (i.e. stable prefix).
+ *
+ * @param idx namespace index
+ * @return namespace URI
+ * @throws IllegalArgumentException if the given index is invalid
+ */
+ public String indexToString(int idx) {
+ String uri = indexToURI.get(idx);
+ if (uri == null) {
+ throw new IllegalArgumentException("Invalid namespace index: " + idx);
+ }
+ return uri;
+ }
+
+ //----------------------------------------------------< NamespaceRegistry >
+ /**
+ * {@inheritDoc}
+ */
+ public synchronized void registerNamespace(String prefix, String uri)
+ throws NamespaceException, UnsupportedRepositoryOperationException,
+ AccessDeniedException, RepositoryException {
+ if (prefix == null || uri == null) {
+ throw new IllegalArgumentException("prefix/uri can not be null");
+ }
+ if (Name.NS_EMPTY_PREFIX.equals(prefix) || Name.NS_DEFAULT_URI.equals(uri)) {
+ throw new NamespaceException("default namespace is reserved and can not be changed");
+ }
+ if (reservedURIs.contains(uri)) {
+ throw new NamespaceException("failed to register namespace "
+ + prefix + " -> " + uri + ": reserved URI");
+ }
+ if (reservedPrefixes.contains(prefix)) {
+ throw new NamespaceException("failed to register namespace "
+ + prefix + " -> " + uri + ": reserved prefix");
+ }
+ // special case: prefixes xml*
+ if (prefix.toLowerCase().startsWith(Name.NS_XML_PREFIX)) {
+ throw new NamespaceException("failed to register namespace "
+ + prefix + " -> " + uri + ": reserved prefix");
+ }
+ // check if the prefix is a valid XML prefix
+ if (!XMLChar.isValidNCName(prefix)) {
+ throw new NamespaceException("failed to register namespace "
+ + prefix + " -> " + uri + ": invalid prefix");
+ }
+
+ // check existing mappings
+ String oldPrefix = uriToPrefix.get(uri);
+ if (prefix.equals(oldPrefix)) {
+ throw new NamespaceException("failed to register namespace "
+ + prefix + " -> " + uri + ": mapping already exists");
+ }
+ if (prefixToURI.containsKey(prefix)) {
+ /**
+ * prevent remapping of existing prefixes because this would in effect
+ * remove the previously assigned namespace;
+ * as we can't guarantee that there are no references to this namespace
+ * (in names of nodes/properties/node types etc.) we simply don't allow it.
+ */
+ throw new NamespaceException("failed to register namespace "
+ + prefix + " -> " + uri
+ + ": remapping existing prefixes is not supported.");
+ }
+
+ if (oldPrefix != null) {
+ // remove old prefix mapping
+ prefixToURI.remove(oldPrefix);
+ uriToPrefix.remove(uri);
+ }
+
+ // add new prefix mapping
+ map(prefix, uri);
+
+ if (eventChannel != null) {
+ eventChannel.remapped(oldPrefix, prefix, uri);
+ }
+
+ // persist mappings
+ store();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void unregisterNamespace(String prefix)
+ throws NamespaceException, UnsupportedRepositoryOperationException,
+ AccessDeniedException, RepositoryException {
+ if (reservedPrefixes.contains(prefix)) {
+ throw new NamespaceException("reserved prefix: " + prefix);
+ }
+ if (!prefixToURI.containsKey(prefix)) {
+ throw new NamespaceException("unknown prefix: " + prefix);
+ }
+ /**
+ * as we can't guarantee that there are no references to the specified
+ * namespace (in names of nodes/properties/node types etc.) we simply
+ * don't allow it.
+ */
+ throw new NamespaceException("unregistering namespaces is not supported.");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String[] getPrefixes() throws RepositoryException {
+ return prefixToURI.keySet().toArray(new String[prefixToURI.keySet().size()]);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String[] getURIs() throws RepositoryException {
+ return uriToPrefix.keySet().toArray(new String[uriToPrefix.keySet().size()]);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getURI(String prefix) throws NamespaceException {
+ String uri = prefixToURI.get(prefix);
+ if (uri == null) {
+ throw new NamespaceException(prefix
+ + ": is not a registered namespace prefix.");
+ }
+ return uri;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getPrefix(String uri) throws NamespaceException {
+ String prefix = uriToPrefix.get(uri);
+ if (prefix == null) {
+ throw new NamespaceException(uri
+ + ": is not a registered namespace uri.");
+ }
+ return prefix;
+ }
+
+ //-----------------------------------------------< NamespaceEventListener >
+
+ /**
+ * {@inheritDoc}
+ */
+ public void externalRemap(String oldPrefix, String newPrefix, String uri)
+ throws RepositoryException {
+
+ if (newPrefix == null) {
+ /**
+ * as we can't guarantee that there are no references to the specified
+ * namespace (in names of nodes/properties/node types etc.) we simply
+ * don't allow it.
+ */
+ throw new NamespaceException("unregistering namespaces is not supported.");
+ }
+
+ if (oldPrefix != null) {
+ // remove old prefix mapping
+ prefixToURI.remove(oldPrefix);
+ uriToPrefix.remove(uri);
+ }
+
+ // add new prefix mapping
+ map(newPrefix, uri);
+
+ // persist mappings
+ store();
+ }
+
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeData.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeData.java
new file mode 100644
index 00000000000..f5fa9f85c41
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeData.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.jackrabbit.core;
+
+import org.apache.jackrabbit.core.state.NodeState;
+
+/**
+ * Data object representing a node. Used for non-shareable nodes or for the
+ * first node in a shared set. For every share-sibling, NodeDataRef
+ * is used instead.
+ */
+class NodeData extends AbstractNodeData {
+
+ /**
+ * Create a new instance of this class.
+ *
+ * @param state node state
+ * @param itemMgr item manager
+ */
+ NodeData(NodeState state, ItemManager itemMgr) {
+ super(state, itemMgr);
+ }
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeDataRef.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeDataRef.java
new file mode 100644
index 00000000000..e87fb7f28e6
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeDataRef.java
@@ -0,0 +1,84 @@
+/*
+ * 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.jackrabbit.core;
+
+import javax.jcr.nodetype.ItemDefinition;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.state.ItemState;
+
+/**
+ * Data object representing a node. Used for share-siblings of a shareable node
+ * that is already loaded.
+ */
+class NodeDataRef extends AbstractNodeData {
+
+ /** Referenced data object */
+ private final AbstractNodeData data;
+
+ /**
+ * Create a new instance of this class.
+ *
+ * @param data data to reference
+ * @param primaryParentId primary parent id
+ */
+ protected NodeDataRef(AbstractNodeData data, NodeId primaryParentId) {
+ super(data.getId());
+
+ this.data = data;
+
+ setPrimaryParentId(primaryParentId);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * This implementation returns the state of the referenced data object.
+ */
+ public ItemState getState() {
+ return data.getState();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * This implementation sets the state of the referenced data object.
+ */
+ protected void setState(ItemState state) {
+ data.setState(state);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * This implementation returns the definition of the referenced data object.
+ * @throws RepositoryException if the definition cannot be retrieved.
+ */
+ public ItemDefinition getDefinition() throws RepositoryException {
+ return data.getDefinition();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * This implementation sets the definition of the referenced data object.
+ */
+ protected void setDefinition(ItemDefinition definition) {
+ data.setDefinition(definition);
+ }
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java
new file mode 100644
index 00000000000..5046ce43e50
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeImpl.java
@@ -0,0 +1,3917 @@
+/*
+ * 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.jackrabbit.core;
+
+import static javax.jcr.PropertyType.STRING;
+import static org.apache.jackrabbit.spi.commons.name.NameConstants.JCR_CURRENT_LIFECYCLE_STATE;
+import static org.apache.jackrabbit.spi.commons.name.NameConstants.JCR_ISCHECKEDOUT;
+import static org.apache.jackrabbit.spi.commons.name.NameConstants.JCR_LIFECYCLE_POLICY;
+import static org.apache.jackrabbit.spi.commons.name.NameConstants.MIX_LIFECYCLE;
+import static org.apache.jackrabbit.spi.commons.name.NameConstants.MIX_REFERENCEABLE;
+import static org.apache.jackrabbit.spi.commons.name.NameConstants.MIX_SIMPLE_VERSIONABLE;
+import static org.apache.jackrabbit.spi.commons.name.NameConstants.MIX_VERSIONABLE;
+
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.Binary;
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.InvalidLifecycleTransitionException;
+import javax.jcr.Item;
+import javax.jcr.ItemExistsException;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.ItemVisitor;
+import javax.jcr.NamespaceException;
+import javax.jcr.NoSuchWorkspaceException;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+import javax.jcr.lock.Lock;
+import javax.jcr.lock.LockException;
+import javax.jcr.lock.LockManager;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.ItemDefinition;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.PropertyDefinition;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryResult;
+import javax.jcr.version.Version;
+import javax.jcr.version.VersionException;
+import javax.jcr.version.VersionHistory;
+import javax.jcr.version.VersionManager;
+
+import org.apache.jackrabbit.api.JackrabbitNode;
+import org.apache.jackrabbit.commons.JcrUtils;
+import org.apache.jackrabbit.commons.iterator.NodeIteratorAdapter;
+import org.apache.jackrabbit.commons.iterator.PropertyIteratorAdapter;
+import org.apache.jackrabbit.core.id.ItemId;
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.id.PropertyId;
+import org.apache.jackrabbit.core.nodetype.EffectiveNodeType;
+import org.apache.jackrabbit.core.nodetype.NodeTypeConflictException;
+import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
+import org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl;
+import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.core.query.QueryManagerImpl;
+import org.apache.jackrabbit.core.security.AccessManager;
+import org.apache.jackrabbit.core.security.authorization.Permission;
+import org.apache.jackrabbit.core.session.AddNodeOperation;
+import org.apache.jackrabbit.core.session.NodeNameNormalizer;
+import org.apache.jackrabbit.core.session.SessionContext;
+import org.apache.jackrabbit.core.session.SessionOperation;
+import org.apache.jackrabbit.core.session.SessionWriteOperation;
+import org.apache.jackrabbit.core.state.ChildNodeEntry;
+import org.apache.jackrabbit.core.state.ItemState;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.ItemStateManager;
+import org.apache.jackrabbit.core.state.NodeReferences;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.PropertyState;
+import org.apache.jackrabbit.core.value.InternalValue;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.QItemDefinition;
+import org.apache.jackrabbit.spi.QNodeDefinition;
+import org.apache.jackrabbit.spi.QPropertyDefinition;
+import org.apache.jackrabbit.spi.commons.conversion.MalformedPathException;
+import org.apache.jackrabbit.spi.commons.conversion.NameException;
+import org.apache.jackrabbit.spi.commons.name.NameConstants;
+import org.apache.jackrabbit.spi.commons.name.PathBuilder;
+import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl;
+import org.apache.jackrabbit.spi.commons.nodetype.NodeDefinitionImpl;
+import org.apache.jackrabbit.spi.commons.nodetype.PropertyDefinitionImpl;
+import org.apache.jackrabbit.util.ChildrenCollectorFilter;
+import org.apache.jackrabbit.util.ISO9075;
+import org.apache.jackrabbit.value.ValueHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * NodeImpl implements the Node interface.
+ */
+public class NodeImpl extends ItemImpl implements Node, JackrabbitNode {
+
+ private static Logger log = LoggerFactory.getLogger(NodeImpl.class);
+
+ // flag set in status passed to getOrCreateProperty if property was created
+ protected static final short CREATED = 0;
+
+ /** node data (avoids casting ItemImpl.data) */
+ private final AbstractNodeData data;
+
+ /**
+ * Protected constructor.
+ *
+ * @param itemMgr the ItemManager that created this Node instance
+ * @param sessionContext the component context of the associated session
+ * @param data the node data
+ */
+ protected NodeImpl(
+ ItemManager itemMgr, SessionContext sessionContext,
+ AbstractNodeData data) {
+ super(itemMgr, sessionContext, data);
+ this.data = data;
+ // paranoid sanity check
+ NodeTypeRegistry ntReg = sessionContext.getNodeTypeRegistry();
+ final NodeState state = data.getNodeState();
+ if (!ntReg.isRegistered(state.getNodeTypeName())) {
+ /**
+ * todo need proper way of handling inconsistent/corrupt node type references
+ * e.g. 'flag' nodes that refer to non-registered node types
+ */
+ log.warn("Fallback to nt:unstructured due to unknown node type '"
+ + state.getNodeTypeName() + "' of " + this);
+ data.getNodeState().setNodeTypeName(NameConstants.NT_UNSTRUCTURED);
+ }
+ List unknown = null;
+ for (Name mixinName : state.getMixinTypeNames()) {
+ if (!ntReg.isRegistered(mixinName)) {
+ if (unknown == null) {
+ unknown = new ArrayList();
+ }
+ unknown.add(mixinName);
+ log.warn("Ignoring unknown mixin type '" + mixinName +
+ "' of " + this);
+ }
+ }
+ if (unknown != null) {
+ // ignore unknown mixin type names
+ Set known = new HashSet(state.getMixinTypeNames());
+ known.removeAll(unknown);
+ state.setMixinTypeNames(known);
+ }
+ }
+
+ /**
+ * Returns the node-state associated with this node.
+ *
+ * @return state associated with this node
+ */
+ NodeState getNodeState() {
+ return data.getNodeState();
+ }
+
+ /**
+ * Returns the id of the property at relPath or null
+ * if no property exists at relPath.
+ *
+ * Note that access rights are not checked.
+ *
+ * @param relPath relative path of a (possible) property
+ * @return the id of the property at relPath or
+ * null if no property exists at relPath
+ * @throws RepositoryException if relPath is not a valid
+ * relative path
+ */
+ protected PropertyId resolveRelativePropertyPath(String relPath)
+ throws RepositoryException {
+ Path p = resolveRelativePath(relPath);
+ return getPropertyId(p);
+ }
+
+ /**
+ * Returns the id of the node at relPath or null
+ * if no node exists at relPath.
+ *
+ * Note that access rights are not checked.
+ *
+ * @param relPath relative path of a (possible) node
+ * @return the id of the node at relPath or
+ * null if no node exists at relPath
+ * @throws RepositoryException if relPath is not a valid
+ * relative path
+ */
+ protected NodeId resolveRelativeNodePath(String relPath)
+ throws RepositoryException {
+
+ Path p = resolveRelativePath(relPath);
+ return getNodeId(p);
+ }
+
+ /**
+ * Resolve a relative path given as string into a Path. If
+ * a NameException occurs, it will be rethrown embedded
+ * into a RepositoryException
+ *
+ * @param relPath relative path
+ * @return Path object
+ * @throws RepositoryException if an error occurs
+ */
+ private Path resolveRelativePath(String relPath) throws RepositoryException {
+ try {
+ return sessionContext.getQPath(relPath);
+ } catch (NameException e) {
+ throw new RepositoryException(
+ "Failed to resolve path " + relPath
+ + " relative to " + this, e);
+ }
+ }
+
+ /**
+ * Returns the id of the node at p or null
+ * if no node exists at p.
+ *
+ * Note that access rights are not checked.
+ *
+ * @param p relative path of a (possible) node
+ * @return the id of the node at p or
+ * null if no node exists at p
+ * @throws RepositoryException if relPath is not a valid
+ * relative path
+ */
+ private NodeId getNodeId(Path p) throws RepositoryException {
+ if (p.getLength() == 1 && p.denotesName()) {
+ // check if node entry exists
+ ChildNodeEntry cne = data.getNodeState().getChildNodeEntry(
+ p.getName(), p.getNormalizedIndex());
+ if (cne != null) {
+ return cne.getId();
+ } else {
+ return null; // there's no child node with that name
+ }
+ } else {
+ // build and resolve absolute path
+ try {
+ p = PathFactoryImpl.getInstance().create(
+ getPrimaryPath(), p, true);
+ } catch (RepositoryException re) {
+ // failed to build canonical path
+ return null;
+ }
+ return sessionContext.getHierarchyManager().resolveNodePath(p);
+ }
+ }
+
+ /**
+ * Returns the id of the property at p or null
+ * if no node exists at p.
+ *
+ * Note that access rights are not checked.
+ *
+ * @param p relative path of a (possible) node
+ * @return the id of the node at p or
+ * null if no node exists at p
+ * @throws RepositoryException if relPath is not a valid
+ * relative path
+ */
+ private PropertyId getPropertyId(Path p) throws RepositoryException {
+ if (p.getLength() == 1 && p.denotesName()) {
+ // check if property entry exists
+ NodeState thisState = data.getNodeState();
+ if (p.getIndex() == Path.INDEX_UNDEFINED
+ && thisState.hasPropertyName(p.getName())) {
+ return new PropertyId(thisState.getNodeId(), p.getName());
+ } else {
+ return null; // there's no property with that name
+ }
+ } else {
+ // build and resolve absolute path
+ try {
+ p = PathFactoryImpl.getInstance().create(
+ getPrimaryPath(), p, true);
+ } catch (RepositoryException re) {
+ // failed to build canonical path
+ return null;
+ }
+ return sessionContext.getHierarchyManager().resolvePropertyPath(p);
+ }
+ }
+
+ /**
+ * Determines if there are pending unsaved changes either on this
+ * node or on any node or property in the subtree below it.
+ *
+ * @return true if there are pending unsaved changes,
+ * false otherwise.
+ * @throws RepositoryException if an error occurred
+ */
+ protected boolean hasPendingChanges() throws RepositoryException {
+ if (isTransient()) {
+ return true;
+ }
+ return !stateMgr.getDescendantTransientItemStates(id).isEmpty();
+ }
+
+ @Override
+ protected synchronized ItemState getOrCreateTransientItemState()
+ throws RepositoryException {
+
+ synchronized (data) {
+ if (!isTransient()) {
+ try {
+ // make transient (copy-on-write)
+ NodeState transientState =
+ stateMgr.createTransientNodeState(
+ (NodeState) stateMgr.getItemState(getId()), ItemState.STATUS_EXISTING_MODIFIED);
+ // replace persistent with transient state
+ data.setState(transientState);
+ } catch (ItemStateException ise) {
+ String msg = "failed to create transient state";
+ log.debug(msg);
+ throw new RepositoryException(msg, ise);
+ }
+ }
+ return getItemState();
+ }
+ }
+
+ /**
+ * @param name
+ * @param type
+ * @param multiValued
+ * @param exactTypeMatch
+ * @param status
+ * @return
+ * @throws ConstraintViolationException if no applicable property definition
+ * could be found
+ * @throws RepositoryException if another error occurs
+ */
+ protected PropertyImpl getOrCreateProperty(String name, int type,
+ boolean multiValued,
+ boolean exactTypeMatch,
+ BitSet status)
+ throws ConstraintViolationException, RepositoryException {
+ try {
+ return getOrCreateProperty(
+ sessionContext.getQName(name), type,
+ multiValued, exactTypeMatch, status);
+ } catch (NameException e) {
+ throw new RepositoryException("invalid property name: " + name, e);
+ }
+ }
+
+ /**
+ * @param name
+ * @param type
+ * @param multiValued
+ * @param exactTypeMatch
+ * @param status
+ * @return
+ * @throws ConstraintViolationException if no applicable property definition
+ * could be found
+ * @throws RepositoryException if another error occurs
+ */
+ protected synchronized PropertyImpl getOrCreateProperty(Name name, int type,
+ boolean multiValued,
+ boolean exactTypeMatch,
+ BitSet status)
+ throws ConstraintViolationException, RepositoryException {
+ status.clear();
+
+ if (isNew() && !hasProperty(name)) {
+ // this is a new node and the property does not exist yet
+ // -> no need to check item manager
+ PropertyDefinitionImpl def = getApplicablePropertyDefinition(
+ name, type, multiValued, exactTypeMatch);
+ PropertyImpl prop = createChildProperty(name, type, def);
+ status.set(CREATED);
+ return prop;
+ }
+
+
+ /*
+ * Please note, that this implementation does not win a price for beauty
+ * or speed. It's never a good idea to use exceptions for semantical
+ * control flow.
+ * However, compared to the previous version, this one is thread save
+ * and makes the test/get block atomic in respect to transactional
+ * commits. the test/set can still fail.
+ *
+ * Old Version:
+
+ NodeState thisState = (NodeState) state;
+ if (thisState.hasPropertyName(name)) {
+ /**
+ * the following call will throw ItemNotFoundException if the
+ * current session doesn't have read access
+ /
+ return getProperty(name);
+ }
+ [...create block...]
+
+ */
+ PropertyId propId = new PropertyId(getNodeId(), name);
+ try {
+ return (PropertyImpl) itemMgr.getItem(propId);
+ } catch (AccessDeniedException ade) {
+ throw new ItemNotFoundException(name.toString());
+ } catch (ItemNotFoundException e) {
+ // does not exist yet or has been removed transiently:
+ // find definition for the specified property and (re-)create property
+ PropertyDefinitionImpl def = getApplicablePropertyDefinition(
+ name, type, multiValued, exactTypeMatch);
+ PropertyImpl prop;
+ if (stateMgr.hasTransientItemStateInAttic(propId)) {
+ // remove from attic
+ try {
+ stateMgr.disposeTransientItemStateInAttic(stateMgr.getAttic().getItemState(propId));
+ } catch (ItemStateException ise) {
+ // shouldn't happen because we checked if it is in the attic
+ throw new RepositoryException(ise);
+ }
+ prop = (PropertyImpl) itemMgr.getItem(propId);
+ PropertyState state = (PropertyState) prop.getOrCreateTransientItemState();
+ state.setMultiValued(multiValued);
+ state.setType(type);
+ getNodeState().addPropertyName(name);
+ } else {
+ prop = createChildProperty(name, type, def);
+ }
+ status.set(CREATED);
+ return prop;
+ }
+ }
+
+ /**
+ * Creates a new property with the given name and type hint and
+ * property definition. If the given property definition is not of type
+ * UNDEFINED, then it takes precedence over the
+ * type hint.
+ *
+ * @param name the name of the property to create.
+ * @param type the type hint.
+ * @param def the associated property definition.
+ * @return the property instance.
+ * @throws RepositoryException if the property cannot be created.
+ */
+ protected synchronized PropertyImpl createChildProperty(Name name, int type,
+ PropertyDefinitionImpl def)
+ throws RepositoryException {
+
+ // create a new property state
+ PropertyState propState;
+ try {
+ QPropertyDefinition propDef = def.unwrap();
+ if (def.getRequiredType() != PropertyType.UNDEFINED) {
+ type = def.getRequiredType();
+ }
+ propState =
+ stateMgr.createTransientPropertyState(getNodeId(), name,
+ ItemState.STATUS_NEW);
+ propState.setType(type);
+ propState.setMultiValued(propDef.isMultiple());
+ // compute system generated values if necessary
+ String userId = sessionContext.getSessionImpl().getUserID();
+ new NodeTypeInstanceHandler(userId).setDefaultValues(
+ propState, data.getNodeState(), propDef);
+ } catch (ItemStateException ise) {
+ String msg = "failed to add property " + name + " to " + this;
+ log.debug(msg);
+ throw new RepositoryException(msg, ise);
+ }
+
+ // create Property instance wrapping new property state
+ // NOTE: since the property is not yet connected to its parent, avoid
+ // calling ItemManager#getItem(ItemId) which may include a permission
+ // check (with subsequent usage of the hierarachy-mgr -> error).
+ // just let the mgr create the new property that is known to exist and
+ // which has not been accessed before.
+ PropertyImpl prop = (PropertyImpl) itemMgr.createItemInstance(propState);
+
+ // modify the state of 'this', i.e. the parent node
+ NodeState thisState = (NodeState) getOrCreateTransientItemState();
+ // add new property entry
+ thisState.addPropertyName(name);
+
+ return prop;
+ }
+
+ protected synchronized NodeImpl createChildNode(Name name,
+ NodeTypeImpl nodeType,
+ NodeId id)
+ throws RepositoryException {
+ // create a new node state
+ NodeState nodeState = stateMgr.createTransientNodeState(
+ id, nodeType.getQName(), getNodeId(), ItemState.STATUS_NEW);
+
+ // create Node instance wrapping new node state
+ NodeImpl node;
+ try {
+ // NOTE: since the node is not yet connected to its parent, avoid
+ // calling ItemManager#getItem(ItemId) which may include a permission
+ // check (with subsequent usage of the hierarachy-mgr -> error).
+ // just let the mgr create the new node that is known to exist and
+ // which has not been accessed before.
+ node = (NodeImpl) itemMgr.createItemInstance(nodeState);
+ } catch (RepositoryException re) {
+ // something went wrong
+ stateMgr.disposeTransientItemState(nodeState);
+ // re-throw
+ throw re;
+ }
+
+ // modify the state of 'this', i.e. the parent node
+ NodeState thisState = (NodeState) getOrCreateTransientItemState();
+ // add new child node entry
+ thisState.addChildNodeEntry(name, nodeState.getNodeId());
+
+ // add 'auto-create' properties defined in node type
+ for (PropertyDefinition aPda : nodeType.getAutoCreatedPropertyDefinitions()) {
+ PropertyDefinitionImpl pd = (PropertyDefinitionImpl) aPda;
+ node.createChildProperty(pd.unwrap().getName(), pd.getRequiredType(), pd);
+ }
+
+ // recursively add 'auto-create' child nodes defined in node type
+ for (NodeDefinition aNda : nodeType.getAutoCreatedNodeDefinitions()) {
+ NodeDefinitionImpl nd = (NodeDefinitionImpl) aNda;
+ node.createChildNode(nd.unwrap().getName(), (NodeTypeImpl) nd.getDefaultPrimaryType(), null);
+ }
+
+ return node;
+ }
+
+ /**
+ *
+ * @param oldName
+ * @param index
+ * @param id
+ * @param newName
+ * @throws RepositoryException
+ * @deprecated use #renameChildNode(NodeId, Name, boolean)
+ */
+ protected void renameChildNode(Name oldName, int index, NodeId id,
+ Name newName)
+ throws RepositoryException {
+ renameChildNode(id, newName, false);
+ }
+
+ /**
+ *
+ * @param id
+ * @param newName
+ * @param replace
+ * @throws RepositoryException
+ */
+ protected void renameChildNode(NodeId id, Name newName, boolean replace)
+ throws RepositoryException {
+ // modify the state of 'this', i.e. the parent node
+ NodeState thisState = (NodeState) getOrCreateTransientItemState();
+ if (replace) {
+ // rename the specified child node by replacing the old
+ // child node entry with a new one at the same relative position
+ thisState.replaceChildNodeEntry(id, newName, id);
+ } else {
+ // rename the specified child node by removing the old and adding
+ // a new child node entry.
+ thisState.renameChildNodeEntry(id, newName);
+ }
+ }
+
+ protected void removeChildProperty(Name propName) throws RepositoryException {
+ // modify the state of 'this', i.e. the parent node
+ NodeState thisState = (NodeState) getOrCreateTransientItemState();
+
+ // remove the property entry
+ if (!thisState.removePropertyName(propName)) {
+ String msg = "failed to remove property " + propName + " of " + this;
+ log.debug(msg);
+ throw new RepositoryException(msg);
+ }
+
+ // remove property
+ PropertyId propId = new PropertyId(thisState.getNodeId(), propName);
+ itemMgr.getItem(propId).setRemoved();
+ }
+
+ protected void removeChildNode(NodeId childId) throws RepositoryException {
+ // modify the state of 'this', i.e. the parent node
+ NodeState thisState = (NodeState) getOrCreateTransientItemState();
+ ChildNodeEntry entry = thisState.getChildNodeEntry(childId);
+ if (entry == null) {
+ String msg = "failed to remove child " + childId + " of " + this;
+ log.debug(msg);
+ throw new RepositoryException(msg);
+ }
+
+ // notify target of removal
+ try {
+ NodeImpl childNode = itemMgr.getNode(childId, getNodeId());
+ childNode.onRemove(getNodeId());
+ } catch (ItemNotFoundException e) {
+ boolean ignoreError = false;
+ if (sessionContext.getSessionImpl().autoFixCorruptions()) {
+ // it might be an access right problem
+ // we need to check if the item doesn't exist in the ism
+ ItemStateManager ism = sessionContext.getItemStateManager();
+ if (!ism.hasItemState(childId)) {
+ log.warn("Node " + childId + " not found, ignore", e);
+ ignoreError = true;
+ }
+ }
+ if (!ignoreError) {
+ throw e;
+ }
+ }
+
+ // remove the child node entry
+ if (!thisState.removeChildNodeEntry(childId)) {
+ String msg = "failed to remove child " + childId + " of " + this;
+ log.debug(msg);
+ throw new RepositoryException(msg);
+ }
+ }
+
+ protected void onRedefine(QNodeDefinition def) throws RepositoryException {
+ NodeDefinitionImpl newDef =
+ sessionContext.getNodeTypeManager().getNodeDefinition(def);
+ // modify the state of 'this', i.e. the target node
+ getOrCreateTransientItemState();
+ // set new definition
+ data.setDefinition(newDef);
+ }
+
+ protected void onRemove(NodeId parentId) throws RepositoryException {
+ // modify the state of 'this', i.e. the target node
+ NodeState thisState = (NodeState) getOrCreateTransientItemState();
+
+ // remove this node from its shared set
+ if (thisState.isShareable()) {
+ if (thisState.removeShare(parentId) > 0) {
+ // this state is still connected to some parents, so
+ // leave the child node entries and properties
+
+ // set state of this instance to 'invalid'
+ data.setStatus(STATUS_INVALIDATED);
+ // notify the item manager that this instance has been
+ // temporarily invalidated
+ itemMgr.itemInvalidated(id, data);
+ return;
+ }
+ }
+
+ if (thisState.hasChildNodeEntries()) {
+ // remove child nodes
+ // use temp array to avoid ConcurrentModificationException
+ ArrayList tmp = new ArrayList(thisState.getChildNodeEntries());
+ // remove from tail to avoid problems with same-name siblings
+ for (int i = tmp.size() - 1; i >= 0; i--) {
+ ChildNodeEntry entry =
+ tmp.get(i);
+ // recursively remove child node
+ NodeId childId = entry.getId();
+ //NodeImpl childNode = (NodeImpl) itemMgr.getItem(childId);
+ try {
+ /* omit the read-permission check upon retrieving the
+ child item as this is an internal call to remove the
+ subtree which may contain (protected) child items which
+ are not visible to the caller of the removal. the actual
+ validation of the remove permission however is only
+ executed during Item.save().
+ */
+ NodeImpl childNode = itemMgr.getNode(childId, getNodeId(), false);
+ childNode.onRemove(thisState.getNodeId());
+ // remove the child node entry
+ } catch (ItemNotFoundException e) {
+ boolean ignoreError = false;
+ if (parentId != null && sessionContext.getSessionImpl().autoFixCorruptions()) {
+ // it might be an access right problem
+ // we need to check if the item doesn't exist in the ism
+ ItemStateManager ism = sessionContext.getItemStateManager();
+ if (!ism.hasItemState(childId)) {
+ log.warn("Child named " + entry.getName() + " (index " + entry.getIndex() + ", " +
+ "node id " + childId + ") " +
+ "not found when trying to remove " + getPath() + " " +
+ "(node id " + getNodeId() + ") - ignored", e);
+ ignoreError = true;
+ }
+ }
+ if (!ignoreError) {
+ throw e;
+ }
+ }
+ thisState.removeChildNodeEntry(childId);
+ }
+ }
+
+ // remove properties
+ // use temp set to avoid ConcurrentModificationException
+ HashSet tmp = new HashSet(thisState.getPropertyNames());
+ for (Name propName : tmp) {
+ // remove the property entry
+ thisState.removePropertyName(propName);
+ // remove property
+ PropertyId propId = new PropertyId(thisState.getNodeId(), propName);
+ /* omit the read-permission check upon retrieving the
+ child item as this is an internal call to remove the
+ subtree which may contain (protected) child items which
+ are not visible to the caller of the removal. the actual
+ validation of the remove permission however is only
+ executed during Item.save().
+ */
+ itemMgr.getItem(propId, false).setRemoved();
+ }
+
+ // finally remove this node
+ thisState.setParentId(null);
+ setRemoved();
+ }
+
+ void setMixinTypesProperty(Set mixinNames) throws RepositoryException {
+ NodeState thisState = data.getNodeState();
+ // get or create jcr:mixinTypes property
+ PropertyImpl prop;
+ if (thisState.hasPropertyName(NameConstants.JCR_MIXINTYPES)) {
+ prop = (PropertyImpl) itemMgr.getItem(new PropertyId(thisState.getNodeId(), NameConstants.JCR_MIXINTYPES));
+ } else {
+ // find definition for the jcr:mixinTypes property and create property
+ PropertyDefinitionImpl def = getApplicablePropertyDefinition(
+ NameConstants.JCR_MIXINTYPES, PropertyType.NAME, true, true);
+ prop = createChildProperty(NameConstants.JCR_MIXINTYPES, PropertyType.NAME, def);
+ }
+
+ if (mixinNames.isEmpty()) {
+ // purge empty jcr:mixinTypes property
+ removeChildProperty(NameConstants.JCR_MIXINTYPES);
+ return;
+ }
+
+ // call internalSetValue for setting the jcr:mixinTypes property
+ // to avoid checking of the 'protected' flag
+ InternalValue[] vals = new InternalValue[mixinNames.size()];
+ Iterator iter = mixinNames.iterator();
+ int cnt = 0;
+ while (iter.hasNext()) {
+ vals[cnt++] = InternalValue.create(iter.next());
+ }
+ prop.internalSetValue(vals, PropertyType.NAME);
+ }
+
+ /**
+ * Returns the Names of this node's mixin types.
+ *
+ * @return a set of the Names of this node's mixin types.
+ */
+ public Set getMixinTypeNames() {
+ return data.getNodeState().getMixinTypeNames();
+ }
+
+ /**
+ * Returns the effective (i.e. merged and resolved) node type representation
+ * of this node's primary and mixin node types.
+ *
+ * @return the effective node type
+ * @throws RepositoryException if an error occurs
+ */
+ public EffectiveNodeType getEffectiveNodeType() throws RepositoryException {
+ try {
+ return sessionContext.getNodeTypeRegistry().getEffectiveNodeType(
+ data.getNodeState().getNodeTypeName(),
+ data.getNodeState().getMixinTypeNames());
+ } catch (NodeTypeConflictException ntce) {
+ String msg = "Failed to build effective node type for " + this;
+ log.debug(msg);
+ throw new RepositoryException(msg, ntce);
+ }
+ }
+
+ /**
+ * Returns the applicable child node definition for a child node with the
+ * specified name and node type.
+ *
+ * @param nodeName
+ * @param nodeTypeName
+ * @return
+ * @throws ConstraintViolationException if no applicable child node definition
+ * could be found
+ * @throws RepositoryException if another error occurs
+ */
+ protected NodeDefinitionImpl getApplicableChildNodeDefinition(Name nodeName,
+ Name nodeTypeName)
+ throws ConstraintViolationException, RepositoryException {
+ NodeTypeManagerImpl ntMgr = sessionContext.getNodeTypeManager();
+ QNodeDefinition cnd = getEffectiveNodeType().getApplicableChildNodeDef(
+ nodeName, nodeTypeName, sessionContext.getNodeTypeRegistry());
+ return ntMgr.getNodeDefinition(cnd);
+ }
+
+ /**
+ * Returns the applicable property definition for a property with the
+ * specified name and type.
+ *
+ * @param propertyName
+ * @param type
+ * @param multiValued
+ * @param exactTypeMatch
+ * @return
+ * @throws ConstraintViolationException if no applicable property definition
+ * could be found
+ * @throws RepositoryException if another error occurs
+ */
+ protected PropertyDefinitionImpl getApplicablePropertyDefinition(Name propertyName,
+ int type,
+ boolean multiValued,
+ boolean exactTypeMatch)
+ throws ConstraintViolationException, RepositoryException {
+ QPropertyDefinition pd;
+ if (exactTypeMatch || type == PropertyType.UNDEFINED) {
+ pd = getEffectiveNodeType().getApplicablePropertyDef(
+ propertyName, type, multiValued);
+ } else {
+ try {
+ // try to find a definition with matching type first
+ pd = getEffectiveNodeType().getApplicablePropertyDef(
+ propertyName, type, multiValued);
+ } catch (ConstraintViolationException cve) {
+ // none found, now try by ignoring the type
+ pd = getEffectiveNodeType().getApplicablePropertyDef(
+ propertyName, PropertyType.UNDEFINED, multiValued);
+ }
+ }
+ return sessionContext.getNodeTypeManager().getPropertyDefinition(pd);
+ }
+
+ @Override
+ protected void makePersistent() throws RepositoryException {
+ if (!isTransient()) {
+ log.debug(this + " (" + id + "): there's no transient state to persist");
+ return;
+ }
+
+ NodeState transientState = data.getNodeState();
+ NodeState localState = stateMgr.makePersistent(transientState);
+
+ // swap transient state with local state
+ data.setState(localState);
+ // reset status
+ data.setStatus(STATUS_NORMAL);
+
+ if (isShareable() && data.getPrimaryParentId() == null) {
+ data.setPrimaryParentId(localState.getParentId());
+ }
+ }
+
+ protected void restoreTransient(NodeState transientState)
+ throws RepositoryException {
+ NodeState thisState = null;
+
+ if (!isTransient()) {
+ thisState = (NodeState) getOrCreateTransientItemState();
+ if (transientState.getStatus() == ItemState.STATUS_NEW
+ && thisState.getStatus() != ItemState.STATUS_NEW) {
+ thisState.setStatus(ItemState.STATUS_NEW);
+ stateMgr.disconnectTransientItemState(thisState);
+ }
+ thisState.setParentId(transientState.getParentId());
+ thisState.setNodeTypeName(transientState.getNodeTypeName());
+ } else {
+ // JCR-2503: Re-create transient state in the state manager,
+ // because it was removed
+ synchronized (data) {
+ thisState = stateMgr.createTransientNodeState(
+ (NodeId) transientState.getId(),
+ transientState.getNodeTypeName(),
+ transientState.getParentId(),
+ NodeState.STATUS_NEW);
+ data.setState(thisState);
+ }
+ }
+
+ // re-apply transient changes
+ thisState.setMixinTypeNames(transientState.getMixinTypeNames());
+ thisState.setChildNodeEntries(transientState.getChildNodeEntries());
+ thisState.setPropertyNames(transientState.getPropertyNames());
+ thisState.setSharedSet(transientState.getSharedSet());
+ thisState.setModCount(transientState.getModCount());
+ }
+
+ /**
+ * Same as {@link Node#addMixin(String)} except that it takes a
+ * Name instead of a String.
+ *
+ * @see Node#addMixin(String)
+ */
+ public void addMixin(Name mixinName) throws RepositoryException {
+ perform(new AddMixinOperation(this, mixinName));
+ }
+
+ /**
+ * Same as {@link Node#removeMixin(String)} except that it takes a
+ * Name instead of a String.
+ *
+ * @see Node#removeMixin(String)
+ */
+ public void removeMixin(Name mixinName) throws RepositoryException {
+ perform(new RemoveMixinOperation(this, mixinName));
+ }
+
+ /**
+ * Same as {@link Node#isNodeType(String)} except that it takes a
+ * Name instead of a String.
+ *
+ * @param ntName name of node type
+ * @return true if this node is of the specified node type;
+ * otherwise false
+ */
+ public boolean isNodeType(Name ntName) throws RepositoryException {
+ // first do trivial checks without using type hierarchy
+ Name primary = data.getNodeState().getNodeTypeName();
+ if (ntName.equals(primary)) {
+ return true;
+ }
+ Set mixins = data.getNodeState().getMixinTypeNames();
+ if (mixins.contains(ntName)) {
+ return true;
+ }
+
+ // check effective node type
+ try {
+ NodeTypeRegistry registry = sessionContext.getNodeTypeRegistry();
+ EffectiveNodeType type =
+ registry.getEffectiveNodeType(primary, mixins);
+ return type.includesNodeType(ntName);
+ } catch (NodeTypeConflictException e) {
+ String msg = "Failed to build effective node type for " + this;
+ log.debug(msg);
+ throw new RepositoryException(msg, e);
+ }
+ }
+
+ /**
+ * Checks various pre-conditions that are common to all
+ * setProperty() methods. The checks performed are:
+ *
+ *
this node must be checked-out
+ *
this node must not be locked by somebody else
+ *
+ * Note that certain checks are performed by the respective
+ * Property.setValue() methods.
+ *
+ * @throws VersionException if this node is not checked-out
+ * @throws LockException if this node is locked by somebody else
+ * @throws RepositoryException if another error occurs
+ * @see javax.jcr.Node#setProperty
+ */
+ protected void checkSetProperty()
+ throws VersionException, LockException, RepositoryException {
+ // make sure this node is checked-out and is not locked
+ int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_CHECKED_OUT;
+ sessionContext.getItemValidator().checkModify(this, options, Permission.NONE);
+ }
+
+ /**
+ * Sets the internal value of a property without checking any constraints.
+ *
+ * Note that no type conversion is being performed, i.e. it's the caller's
+ * responsibility to make sure that the type of the given value is compatible
+ * with the specified property's definition.
+ * @param name
+ * @param value
+ * @return
+ * @throws ValueFormatException
+ * @throws RepositoryException
+ */
+ protected Property internalSetProperty(Name name, InternalValue value)
+ throws ValueFormatException, RepositoryException {
+ int type;
+ if (value == null) {
+ type = PropertyType.UNDEFINED;
+ } else {
+ type = value.getType();
+ }
+
+ BitSet status = new BitSet();
+ PropertyImpl prop = getOrCreateProperty(name, type, false, true, status);
+ try {
+ if (value == null) {
+ prop.internalSetValue(null, type);
+ } else {
+ prop.internalSetValue(new InternalValue[]{value}, type);
+ }
+ } catch (RepositoryException re) {
+ if (status.get(CREATED)) {
+ // setting value failed, get rid of newly created property
+ removeChildProperty(name);
+ }
+ // rethrow
+ throw re;
+ }
+ return prop;
+ }
+
+ /**
+ * Sets the internal value of a property without checking any constraints.
+ *
+ * Note that no type conversion is being performed, i.e. it's the caller's
+ * responsibility to make sure that the type of the given values is compatible
+ * with the specified property's definition.
+ *
+ * @param name
+ * @param values
+ * @return
+ * @throws ValueFormatException
+ * @throws RepositoryException
+ */
+ protected Property internalSetProperty(Name name, InternalValue[] values)
+ throws ValueFormatException, RepositoryException {
+ int type;
+ if (values == null || values.length == 0
+ || values[0] == null) {
+ type = PropertyType.UNDEFINED;
+ } else {
+ type = values[0].getType();
+ }
+ return internalSetProperty(name, values, type);
+ }
+
+ /**
+ * Sets the internal value of a property without checking any constraints.
+ *
+ * Note that no type conversion is being performed, i.e. it's the caller's
+ * responsibility to make sure that the type of the given values is compatible
+ * with the specified property's definition.
+ *
+ * @param name
+ * @param values
+ * @param type
+ * @return
+ * @throws ValueFormatException
+ * @throws RepositoryException
+ */
+ protected Property internalSetProperty(Name name, InternalValue[] values,
+ int type)
+ throws ValueFormatException, RepositoryException {
+ BitSet status = new BitSet();
+ PropertyImpl prop = getOrCreateProperty(name, type, true, true, status);
+ try {
+ prop.internalSetValue(values, type);
+ } catch (RepositoryException re) {
+ if (status.get(CREATED)) {
+ // setting value failed, get rid of newly created property
+ removeChildProperty(name);
+ }
+ // rethrow
+ throw re;
+ }
+ return prop;
+ }
+
+ /**
+ * Returns the child node of this node with the specified
+ * name.
+ *
+ * @param name The name of the child node to retrieve.
+ * @return The child node with the specified name.
+ * @throws ItemNotFoundException If no child node exists with the
+ * specified name.
+ * @throws RepositoryException If another error occurs.
+ */
+ public NodeImpl getNode(Name name) throws ItemNotFoundException, RepositoryException {
+ return getNode(name, 1);
+ }
+
+ /**
+ * Returns the child node of this node with the specified
+ * name.
+ *
+ * @param name The name of the child node to retrieve.
+ * @param index The index of the child node to retrieve (in the case of same-name siblings).
+ * @return The child node with the specified name.
+ * @throws ItemNotFoundException If no child node exists with the
+ * specified name.
+ * @throws RepositoryException If another error occurs.
+ */
+ public NodeImpl getNode(final Name name, final int index)
+ throws ItemNotFoundException, RepositoryException {
+ return perform(new SessionOperation() {
+ public NodeImpl perform(SessionContext context)
+ throws RepositoryException {
+ ChildNodeEntry cne = data.getNodeState().getChildNodeEntry(
+ name, index != 0 ? index : 1);
+ if (cne != null) {
+ try {
+ return context.getItemManager().getNode(
+ cne.getId(), getNodeId());
+ } catch (AccessDeniedException e) {
+ throw new ItemNotFoundException();
+ }
+ } else {
+ throw new ItemNotFoundException();
+ }
+ }
+ public String toString() {
+ return "node.getNode(" + name + "[" + index + "])";
+ }
+ });
+ }
+
+ /**
+ * Indicates whether a child node with the specified name exists.
+ * Returns true if the child node exists and false
+ * otherwise.
+ *
+ * @param name The name of the child node.
+ * @return true if the child node exists; false otherwise.
+ * @throws RepositoryException If an unspecified error occurs.
+ */
+ public boolean hasNode(Name name) throws RepositoryException {
+ return hasNode(name, 1);
+ }
+
+ /**
+ * Indicates whether a child node with the specified name exists.
+ * Returns true if the child node exists and false
+ * otherwise.
+ *
+ * @param name The name of the child node.
+ * @param index The index of the child node (in the case of same-name siblings).
+ * @return true if the child node exists; false otherwise.
+ * @throws RepositoryException If an unspecified error occurs.
+ */
+ public boolean hasNode(final Name name, final int index)
+ throws RepositoryException {
+ return perform(new SessionOperation() {
+ public Boolean perform(SessionContext context)
+ throws RepositoryException {
+ ChildNodeEntry cne = data.getNodeState().getChildNodeEntry(
+ name, index != 0 ? index : 1);
+ return cne != null
+ && context.getItemManager().itemExists(cne.getId());
+ }
+ public String toString() {
+ return "node.hasNode(" + name + "[" + index + "])";
+ }
+ });
+ }
+
+ /**
+ * Returns the property of this node with the specified
+ * name.
+ *
+ * @param name The name of the property to retrieve.
+ * @return The property with the specified name.
+ * @throws ItemNotFoundException If no property exists with the
+ * specified name.
+ * @throws RepositoryException If another error occurs.
+ */
+ public PropertyImpl getProperty(final Name name)
+ throws ItemNotFoundException, RepositoryException {
+ return perform(new SessionOperation() {
+ public PropertyImpl perform(SessionContext context)
+ throws RepositoryException {
+ try {
+ return (PropertyImpl) context.getItemManager().getItem(
+ new PropertyId(getNodeId(), name));
+ } catch (AccessDeniedException ade) {
+ String n = context.getJCRName(name);
+ throw new ItemNotFoundException(
+ "Property " + n + " not found");
+ }
+ }
+ public String toString() {
+ return "node.getProperty(" + name + ")";
+ }
+ });
+ }
+
+ /**
+ * Indicates whether a property with the specified name exists.
+ * Returns true if the property exists and false
+ * otherwise.
+ *
+ * @param name The name of the property.
+ * @return true if the property exists; false otherwise.
+ * @throws RepositoryException If an unspecified error occurs.
+ */
+ public boolean hasProperty(final Name name) throws RepositoryException {
+ return perform(new SessionOperation() {
+ public Boolean perform(SessionContext context)
+ throws RepositoryException {
+ return data.getNodeState().hasPropertyName(name)
+ && context.getItemManager().itemExists(
+ new PropertyId(getNodeId(), name));
+ }
+ public String toString() {
+ return "node.hasProperty(" + name + ")";
+ }
+ });
+ }
+
+ /**
+ * Same as {@link Node#addNode(String, String)} except that
+ * this method takes Name arguments instead of
+ * Strings and has an additional uuid argument.
+ *
+ * Important Notice: This method is for internal use only! Passing
+ * already assigned uuid's might lead to unexpected results and
+ * data corruption in the worst case.
+ *
+ * @param nodeName name of the new node
+ * @param nodeTypeName name of the new node's node type or null
+ * if it should be determined automatically
+ * @param id id of the new node or null if a new
+ * id should be assigned
+ * @return the newly added node
+ * @throws RepositoryException if the node can not added
+ */
+ // FIXME: This method should not be public
+ public synchronized NodeImpl addNode(
+ Name nodeName, Name nodeTypeName, NodeId id)
+ throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ Path nodePath = PathFactoryImpl.getInstance().create(
+ getPrimaryPath(), nodeName, true);
+
+ // Check the explicitly specified node type (if any)
+ NodeTypeImpl nt = null;
+ if (nodeTypeName != null) {
+ nt = sessionContext.getNodeTypeManager().getNodeType(nodeTypeName);
+ if (nt.isMixin()) {
+ throw new ConstraintViolationException(
+ "Unable to add a node with a mixin node type: "
+ + sessionContext.getJCRName(nodeTypeName));
+ } else if (nt.isAbstract()) {
+ throw new ConstraintViolationException(
+ "Unable to add a node with an abstract node type: "
+ + sessionContext.getJCRName(nodeTypeName));
+ } else {
+ // adding a node with explicit specifying the node type name
+ // requires the editing session to have nt_management privilege.
+ sessionContext.getAccessManager().checkPermission(
+ nodePath, Permission.NODE_TYPE_MNGMT);
+ }
+ }
+
+ // Get the applicable child node definition for this node.
+ NodeDefinitionImpl def;
+ try {
+ def = getApplicableChildNodeDefinition(nodeName, nodeTypeName);
+ } catch (RepositoryException e) {
+ throw new ConstraintViolationException(
+ "No child node definition for "
+ + sessionContext.getJCRName(nodeName) + " found in " + this, e);
+ }
+
+ // Use default node type from child node definition if needed
+ if (nt == null) {
+ nt = (NodeTypeImpl) def.getDefaultPrimaryType();
+ }
+
+ // check the new name
+ NodeNameNormalizer.check(nodeName);
+
+ // check for name collisions
+ NodeState thisState = data.getNodeState();
+ ChildNodeEntry cne = thisState.getChildNodeEntry(nodeName, 1);
+ if (cne != null) {
+ // there's already a child node entry with that name;
+ // check same-name sibling setting of new node
+ if (!def.allowsSameNameSiblings()) {
+ throw new ItemExistsException(
+ "This node already exists: "
+ + itemMgr.safeGetJCRPath(nodePath));
+ }
+ // check same-name sibling setting of existing node
+ NodeImpl existing = itemMgr.getNode(cne.getId(), getNodeId());
+ if (!existing.getDefinition().allowsSameNameSiblings()) {
+ throw new ItemExistsException(
+ "Same-name siblings not allowed for " + existing);
+ }
+ }
+
+ // check protected flag of parent (i.e. this) node and retention/hold
+ // make sure this node is checked-out and not locked by another session.
+ int options =
+ ItemValidator.CHECK_LOCK | ItemValidator.CHECK_CHECKED_OUT
+ | ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD
+ | ItemValidator.CHECK_RETENTION;
+ sessionContext.getItemValidator().checkModify(this, options, Permission.NONE);
+
+ // now do create the child node
+ return createChildNode(nodeName, nt, id);
+ }
+
+ /**
+ * Same as {@link Node#setProperty(String, Value[], int)} except
+ * that this method takes a Name name argument instead of a
+ * String.
+ *
+ * @param name
+ * @param values
+ * @param type
+ * @return
+ * @throws ValueFormatException
+ * @throws VersionException
+ * @throws LockException
+ * @throws ConstraintViolationException
+ * @throws RepositoryException
+ */
+ public PropertyImpl setProperty(Name name, Value[] values, int type)
+ throws ValueFormatException, VersionException, LockException,
+ ConstraintViolationException, RepositoryException {
+ return setProperty(name, values, type, true);
+ }
+
+ /**
+ * Same as {@link Node#setProperty(String, Value)} except that
+ * this method takes a Name name argument instead of a
+ * String.
+ */
+ public PropertyImpl setProperty(Name name, Value value)
+ throws RepositoryException {
+ return sessionContext.getSessionState().perform(
+ new SetPropertyOperation(name, value, false));
+ }
+
+ /**
+ * @see ItemImpl#getQName()
+ */
+ @Override
+ public Name getQName() throws RepositoryException {
+ HierarchyManager hierMgr = sessionContext.getHierarchyManager();
+ Name name;
+
+ if (!isShareable()) {
+ name = hierMgr.getName(id);
+ } else {
+ name = hierMgr.getName(getNodeId(), getParentId());
+ }
+ return name;
+ }
+
+ /**
+ * Returns the identifier of this Node.
+ *
+ * @return the id of this Node
+ */
+ public NodeId getNodeId() {
+ return (NodeId) id;
+ }
+
+ /**
+ * Returns the name of the primary node type as exposed on the node state
+ * without retrieving the node type.
+ *
+ * @return the name of the primary node type.
+ */
+ public Name getPrimaryNodeTypeName() {
+ return data.getNodeState().getNodeTypeName();
+ }
+
+ /**
+ * Test if this node is access controlled. The node is access controlled if
+ * it is of node type
+ * {@link org.apache.jackrabbit.core.security.authorization.AccessControlConstants#NT_REP_ACCESS_CONTROLLABLE "rep:AccessControllable"}
+ * and if it has a child node named
+ * {@link org.apache.jackrabbit.core.security.authorization.AccessControlConstants#N_POLICY}.
+ *
+ * @return true if this node is access controlled and has a
+ * rep:policy child; false otherwise.
+ * @throws RepositoryException if an error occurs
+ */
+ public boolean isAccessControllable() throws RepositoryException {
+ return data.getNodeState().hasChildNodeEntry(NameConstants.REP_POLICY, 1)
+ && isNodeType(NameConstants.REP_ACCESS_CONTROLLABLE);
+ }
+
+ /**
+ * Same as {@link Node#orderBefore(String, String)} except that
+ * this method takes a Path.Element arguments instead of
+ * Strings.
+ *
+ * @param srcName
+ * @param dstName
+ * @throws UnsupportedRepositoryOperationException
+ * @throws VersionException
+ * @throws ConstraintViolationException
+ * @throws ItemNotFoundException
+ * @throws LockException
+ * @throws RepositoryException
+ */
+ public synchronized void orderBefore(Path.Element srcName,
+ Path.Element dstName)
+ throws UnsupportedRepositoryOperationException, VersionException,
+ ConstraintViolationException, ItemNotFoundException, LockException,
+ RepositoryException {
+
+ // check state of this instance
+ sanityCheck();
+
+ if (!getPrimaryNodeType().hasOrderableChildNodes()) {
+ throw new UnsupportedRepositoryOperationException(
+ "child node ordering not supported on " + this);
+ }
+
+ // check arguments
+ if (srcName.equals(dstName)) {
+ // there's nothing to do
+ return;
+ }
+
+ // check existence
+ if (!hasNode(srcName.getName(), srcName.getIndex())) {
+ String name;
+ try {
+ Path.Element[] path = new Path.Element[] { srcName };
+ name = sessionContext.getJCRPath(new PathBuilder(path).getPath());
+ } catch (NameException e) {
+ name = srcName.toString();
+ } catch (NamespaceException e) {
+ name = srcName.toString();
+ }
+ throw new ItemNotFoundException(
+ this + " has no child node with name " + name);
+ }
+
+ if (dstName != null && !hasNode(dstName.getName(), dstName.getIndex())) {
+ String name;
+ try {
+ Path.Element[] path = new Path.Element[] { dstName };
+ name = sessionContext.getJCRPath(new PathBuilder(path).getPath());
+ } catch (NameException e) {
+ name = dstName.toString();
+ } catch (NamespaceException e) {
+ name = dstName.toString();
+ }
+ throw new ItemNotFoundException(
+ this + " has no child node with name " + name);
+ }
+
+ // make sure this node is checked-out and neither protected nor locked
+ int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_CHECKED_OUT
+ | ItemValidator.CHECK_CONSTRAINTS;
+ sessionContext.getItemValidator().checkModify(this, options, Permission.NONE);
+
+ /*
+ make sure the session is allowed to reorder child nodes.
+ since there is no specific privilege for reordering child nodes,
+ test if the the node to be reordered can be removed and added,
+ i.e. treating reorder similar to a move.
+ TODO: properly deal with sns in which case the index would change upon reorder.
+ */
+ AccessManager acMgr = sessionContext.getAccessManager();
+ PathBuilder pb = new PathBuilder(getPrimaryPath());
+ pb.addLast(srcName.getName(), srcName.getIndex());
+ Path childPath = pb.getPath();
+ if (!acMgr.isGranted(childPath, Permission.MODIFY_CHILD_NODE_COLLECTION)) {
+ String msg = "Not allowed to reorder child node " + sessionContext.getJCRPath(childPath) + ".";
+ log.debug(msg);
+ throw new AccessDeniedException(msg);
+ }
+
+ ArrayList list = new ArrayList(data.getNodeState().getChildNodeEntries());
+ int srcInd = -1, destInd = -1;
+ for (int i = 0; i < list.size(); i++) {
+ ChildNodeEntry entry = list.get(i);
+ if (srcInd == -1) {
+ if (entry.getName().equals(srcName.getName())
+ && (entry.getIndex() == srcName.getIndex()
+ || srcName.getIndex() == 0 && entry.getIndex() == 1)) {
+ srcInd = i;
+ }
+ }
+ if (destInd == -1 && dstName != null) {
+ if (entry.getName().equals(dstName.getName())
+ && (entry.getIndex() == dstName.getIndex()
+ || dstName.getIndex() == 0 && entry.getIndex() == 1)) {
+ destInd = i;
+ if (srcInd != -1) {
+ break;
+ }
+ }
+ } else {
+ if (srcInd != -1) {
+ break;
+ }
+ }
+ }
+
+ // check if resulting order would be different to current order
+ if (destInd == -1) {
+ if (srcInd == list.size() - 1) {
+ // no change, we're done
+ return;
+ }
+ } else {
+ if ((destInd - srcInd) == 1) {
+ // no change, we're done
+ return;
+ }
+ }
+
+ // reorder list
+ if (destInd == -1) {
+ list.add(list.remove(srcInd));
+ } else {
+ if (srcInd < destInd) {
+ list.add(destInd, list.get(srcInd));
+ list.remove(srcInd);
+ } else {
+ list.add(destInd, list.remove(srcInd));
+ }
+ }
+
+ // modify the state of 'this', i.e. the parent node
+ NodeState thisState = (NodeState) getOrCreateTransientItemState();
+ thisState.setChildNodeEntries(list);
+ }
+
+ /**
+ * Replaces the child node with the specified id
+ * by a new child node with the same id and specified nodeName,
+ * nodeTypeName and mixinNames.
+ *
+ * @param id id of the child node to be replaced
+ * @param nodeName name of the new node
+ * @param nodeTypeName name of the new node's node type
+ * @param mixinNames name of the new node's mixin types
+ *
+ * @return the new child node replacing the existing child
+ * @throws ItemNotFoundException
+ * @throws NoSuchNodeTypeException
+ * @throws VersionException
+ * @throws ConstraintViolationException
+ * @throws LockException
+ * @throws RepositoryException
+ */
+ public synchronized NodeImpl replaceChildNode(NodeId id, Name nodeName,
+ Name nodeTypeName,
+ Name[] mixinNames)
+ throws ItemNotFoundException, NoSuchNodeTypeException, VersionException,
+ ConstraintViolationException, LockException, RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ Node existing = (Node) itemMgr.getItem(id);
+
+ // 'replace' is actually a 'remove existing/add new' operation;
+ // this unfortunately changes the order of this node's
+ // child node entries (JCR-1055);
+ // => backup list of child node entries beforehand in order
+ // to restore it afterwards
+ NodeState state = data.getNodeState();
+ ChildNodeEntry cneExisting = state.getChildNodeEntry(id);
+ if (cneExisting == null) {
+ throw new ItemNotFoundException(
+ this + ": no child node entry with id " + id);
+ }
+ List cneList = new ArrayList(state.getChildNodeEntries());
+
+ // remove existing
+ existing.remove();
+
+ // create new child node
+ NodeImpl node = addNode(nodeName, nodeTypeName, id);
+ if (mixinNames != null) {
+ for (Name mixinName : mixinNames) {
+ node.addMixin(mixinName);
+ }
+ }
+
+ // fetch state again, as it changed while removing child
+ state = data.getNodeState();
+
+ // restore list of child node entries (JCR-1055)
+ if (cneExisting.getName().equals(nodeName)) {
+ // restore original child node list
+ state.setChildNodeEntries(cneList);
+ } else {
+ // replace child node entry with different name
+ // but preserving original position
+ state.removeAllChildNodeEntries();
+ for (ChildNodeEntry cne : cneList) {
+ if (cne.getId().equals(id)) {
+ // replace entry with different name
+ state.addChildNodeEntry(nodeName, id);
+ } else {
+ state.addChildNodeEntry(cne.getName(), cne.getId());
+ }
+ }
+ }
+
+ return node;
+ }
+
+ /**
+ * Create a child node that is a clone of a shareable node.
+ *
+ * @param src shareable source node
+ * @param name name of new node
+ * @return child node
+ * @throws ItemExistsException if there already is a child node with the
+ * name given and the definition does not allow creating another one
+ * @throws VersionException if this node is not checked out
+ * @throws ConstraintViolationException if no definition is found in this
+ * node that would allow creating the child node
+ * @throws LockException if this node is locked
+ * @throws RepositoryException if some other error occurs
+ */
+ public synchronized NodeImpl clone(NodeImpl src, Name name)
+ throws ItemExistsException, VersionException,
+ ConstraintViolationException, LockException,
+ RepositoryException {
+
+ Path nodePath;
+ try {
+ nodePath = PathFactoryImpl.getInstance().create(getPrimaryPath(), name, true);
+ } catch (MalformedPathException e) {
+ // should never happen
+ String msg = "internal error: invalid path " + this;
+ log.debug(msg);
+ throw new RepositoryException(msg, e);
+ }
+
+ // (1) make sure that parent node is checked-out
+ // (2) check lock status
+ // (3) check protected flag of parent (i.e. this) node
+ int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_CHECKED_OUT | ItemValidator.CHECK_CONSTRAINTS;
+ sessionContext.getItemValidator().checkModify(this, options, Permission.NONE);
+
+ // (4) check for name collisions
+ NodeDefinitionImpl def;
+ try {
+ def = getApplicableChildNodeDefinition(name, null);
+ } catch (RepositoryException re) {
+ String msg = "no definition found in parent node's node type for new node";
+ log.debug(msg);
+ throw new ConstraintViolationException(msg, re);
+ }
+ NodeState thisState = data.getNodeState();
+ ChildNodeEntry cne = thisState.getChildNodeEntry(name, 1);
+ if (cne != null) {
+ // there's already a child node entry with that name;
+ // check same-name sibling setting of new node
+ if (!def.allowsSameNameSiblings()) {
+ throw new ItemExistsException(itemMgr.safeGetJCRPath(nodePath));
+ }
+ // check same-name sibling setting of existing node
+ NodeId newId = cne.getId();
+ if (!((NodeImpl) itemMgr.getItem(newId)).getDefinition().allowsSameNameSiblings()) {
+ throw new ItemExistsException(itemMgr.safeGetJCRPath(nodePath));
+ }
+ }
+
+ // (5) do clone operation
+ NodeId parentId = getNodeId();
+ src.addShareParent(parentId);
+
+ // (6) modify the state of 'this', i.e. the parent node
+ NodeId srcId = src.getNodeId();
+ thisState = (NodeState) getOrCreateTransientItemState();
+ // add new child node entry
+ thisState.addChildNodeEntry(name, srcId);
+
+ return itemMgr.getNode(srcId, parentId);
+ }
+
+ // -----------------------------------------------------------------< Item >
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isNode() {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getName() throws RepositoryException {
+ return perform(new SessionOperation() {
+ public String perform(SessionContext context)
+ throws RepositoryException {
+ NodeId parentId = data.getNodeState().getParentId();
+ if (parentId == null) {
+ return ""; // this is the root node
+ }
+
+ Name name;
+ if (!isShareable()) {
+ name = context.getHierarchyManager().getName(id);
+ } else {
+ name = context.getHierarchyManager().getName(
+ getNodeId(), parentId);
+ }
+ return context.getJCRName(name);
+ }
+ public String toString() {
+ return "node.getName()";
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void accept(ItemVisitor visitor) throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ visitor.visit(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Node getParent() throws RepositoryException {
+ return perform(new SessionOperation() {
+ public Node perform(SessionContext context)
+ throws RepositoryException {
+ NodeId parentId = getParentId();
+ if (parentId != null) {
+ return (Node) context.getItemManager().getItem(parentId);
+ } else {
+ throw new ItemNotFoundException(
+ "Root node doesn't have a parent");
+ }
+ }
+ public String toString() {
+ return "node.getParent()";
+ }
+ });
+ }
+
+ //----------------------------------------------------------------< Node >
+
+ /**
+ * {@inheritDoc}
+ */
+ public Node addNode(String relPath) throws RepositoryException {
+ return addNodeWithUuid(relPath, null, null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Node addNode(String relPath, String nodeTypeName)
+ throws RepositoryException {
+ return addNodeWithUuid(relPath, nodeTypeName, null);
+ }
+
+ /**
+ * Adds a node with the given UUID. You can only add a node with a UUID
+ * that is not already assigned to another node in this workspace.
+ *
+ * @since Apache Jackrabbit 1.6
+ * @see JCR-1972
+ * @see Node#addNode(String)
+ * @param relPath path of the new node
+ * @param uuid UUID of the new node,
+ * or null for a random new UUID
+ * @return the newly added node
+ * @throws RepositoryException if the node can not be added
+ */
+ public Node addNodeWithUuid(String relPath, String uuid)
+ throws RepositoryException {
+ return addNodeWithUuid(relPath, null, uuid);
+ }
+
+ /**
+ * Adds a node with the given node type and UUID. You can only add a node
+ * with a UUID that is not already assigned to another node in this
+ * workspace.
+ *
+ * @since Apache Jackrabbit 1.6
+ * @see JCR-1972
+ * @see Node#addNode(String, String)
+ * @param relPath path of the new node
+ * @param nodeTypeName name of the new node's node type,
+ * or null for automatic type assignment
+ * @param uuid UUID of the new node,
+ * or null for a random new UUID
+ * @return the newly added node
+ * @throws RepositoryException if the node can not be added
+ */
+ public Node addNodeWithUuid(
+ String relPath, String nodeTypeName, String uuid)
+ throws RepositoryException {
+ return perform(new AddNodeOperation(this, relPath, nodeTypeName, uuid));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void orderBefore(String srcName, String destName)
+ throws UnsupportedRepositoryOperationException, VersionException,
+ ConstraintViolationException, ItemNotFoundException, LockException,
+ RepositoryException {
+
+ Path.Element insertName;
+ try {
+ Path p = sessionContext.getQPath(srcName);
+ // p must be a relative path of length==depth==1 (to eliminate e.g. "..")
+ if (p.isAbsolute() || p.getLength() != 1 || p.getDepth() != 1) {
+ throw new RepositoryException("invalid name: " + srcName);
+ }
+ insertName = p.getNameElement();
+ } catch (NameException e) {
+ String msg = "invalid name: " + srcName;
+ log.debug(msg);
+ throw new RepositoryException(msg, e);
+ }
+
+ Path.Element beforeName;
+ if (destName != null) {
+ try {
+ Path p = sessionContext.getQPath(destName);
+ // p must be a relative path of length==depth==1 (to eliminate e.g. "..")
+ if (p.isAbsolute() || p.getLength() != 1 || p.getDepth() != 1) {
+ throw new RepositoryException("invalid name: " + destName);
+ }
+ beforeName = p.getNameElement();
+ } catch (NameException e) {
+ String msg = "invalid name: " + destName;
+ log.debug(msg);
+ throw new RepositoryException(msg, e);
+ }
+ } else {
+ beforeName = null;
+ }
+
+ orderBefore(insertName, beforeName);
+ }
+
+ /** Wrapper around {@link #setProperty(Name, Value[], int boolean)} */
+ public Property setProperty(String name, Value[] values)
+ throws RepositoryException {
+ return setProperty(getQName(name), values, getType(values), false);
+ }
+
+ /** Wrapper around {@link #setProperty(Name, Value[], int boolean)} */
+ public Property setProperty(String name, Value[] values, int type)
+ throws RepositoryException {
+ return setProperty(getQName(name), values, type, true);
+ }
+
+ /** Wrapper around {@link #setProperty(Name, Value[], int boolean)} */
+ public Property setProperty(String name, String[] strings)
+ throws RepositoryException {
+ Value[] values = getValues(strings, STRING);
+ return setProperty(getQName(name), values, STRING, false);
+ }
+
+ /** Wrapper around {@link #setProperty(Name, Value[], int, boolean)} */
+ public Property setProperty(String name, String[] values, int type)
+ throws RepositoryException {
+ Value[] converted = getValues(values, type);
+ return setProperty(sessionContext.getQName(name), converted, type, true);
+ }
+
+ /** Wrapper around {@link #setProperty(String, Value)} */
+ public Property setProperty(String name, String value)
+ throws RepositoryException {
+ if (value != null) {
+ return setProperty(name, getValueFactory().createValue(value));
+ } else {
+ return setProperty(name, (Value) null);
+ }
+ }
+
+ /** Wrapper around {@link #setProperty(String, Value, int)} */
+ public Property setProperty(String name, String value, int type)
+ throws RepositoryException {
+ if (value != null) {
+ return setProperty(
+ name, getValueFactory().createValue(value, type), type);
+ } else {
+ return setProperty(name, (Value) null, type);
+ }
+ }
+
+ /** Wrapper around {@link SetPropertyOperation} */
+ public Property setProperty(String name, Value value, int type)
+ throws RepositoryException {
+ if (value != null && value.getType() != type) {
+ value = ValueHelper.convert(value, type, getValueFactory());
+ }
+ return sessionContext.getSessionState().perform(
+ new SetPropertyOperation(sessionContext.getQName(name), value, true));
+ }
+
+ /** Wrapper around {@link SetPropertyOperation} */
+ public Property setProperty(String name, Value value)
+ throws RepositoryException {
+ return sessionContext.getSessionState().perform(
+ new SetPropertyOperation(sessionContext.getQName(name), value, false));
+ }
+
+ /** Wrapper around {@link #setProperty(String, Value)} */
+ public Property setProperty(String name, InputStream value)
+ throws RepositoryException {
+ if (value != null) {
+ Binary binary = getValueFactory().createBinary(value);
+ try {
+ return setProperty(name, getValueFactory().createValue(binary));
+ } finally {
+ binary.dispose();
+ }
+ } else {
+ return setProperty(name, (Value) null);
+ }
+ }
+
+ /** Wrapper around {@link #setProperty(String, Value)} */
+ public Property setProperty(String name, boolean value)
+ throws RepositoryException {
+ return setProperty(name, getValueFactory().createValue(value));
+ }
+
+ /** Wrapper around {@link #setProperty(String, Value)} */
+ public Property setProperty(String name, double value)
+ throws RepositoryException {
+ return setProperty(name, getValueFactory().createValue(value));
+ }
+
+ /** Wrapper around {@link #setProperty(String, Value)} */
+ public Property setProperty(String name, long value)
+ throws RepositoryException {
+ return setProperty(name, getValueFactory().createValue(value));
+ }
+
+ /** Wrapper around {@link #setProperty(String, Value)} */
+ public Property setProperty(String name, Calendar value)
+ throws RepositoryException {
+ if (value != null) {
+ try {
+ return setProperty(name, getValueFactory().createValue(value));
+ } catch (IllegalArgumentException e) {
+ throw new ValueFormatException(
+ "Value is not an ISO8601 date: " + value, e);
+ }
+ } else {
+ return setProperty(name, (Value) null);
+ }
+ }
+
+ /** Wrapper around {@link #setProperty(String, Value)} */
+ public Property setProperty(String name, Node value)
+ throws RepositoryException {
+ if (value != null) {
+ try {
+ return setProperty(name, getValueFactory().createValue(value));
+ } catch (UnsupportedRepositoryOperationException e) {
+ throw new ValueFormatException(
+ "Node is not referenceable: " + value, e);
+ }
+ } else {
+ return setProperty(name, (Value) null);
+ }
+ }
+
+ /**
+ * Implementation for setProperty() using a single {@link
+ * Value}. The type of the returned property is enforced based on the
+ * enforceType flag. If set to true, the returned
+ * property is of the passed type if it didn't exist before. If set to
+ * false, then the returned property may be of some other type,
+ * but still must be based on an existing property definition for the given
+ * name and single-valued flag. The resulting type is taken from that
+ * definition and the implementation tries to convert the passed value to
+ * that type. If that fails, then a {@link ValueFormatException} is thrown.
+ */
+ private class SetPropertyOperation implements SessionWriteOperation {
+
+ private final Name name;
+
+ private final Value value;
+
+ private final boolean enforceType;
+
+ /**
+ * @param name property name
+ * @param value new value of the property,
+ * or null to remove the property
+ * @param enforceType true to enforce the value type
+ */
+ public SetPropertyOperation(
+ Name name, Value value, boolean enforceType) {
+ this.name = name;
+ this.value = value;
+ this.enforceType = enforceType;
+ }
+
+ /**
+ * @return the Property object set,
+ * or null if this operation was used to remove
+ * a property (by setting its value to null)
+ * @throws ValueFormatException if value cannot be
+ * converted to the specified type or
+ * if the property already exists and
+ * is multi-valued.
+ * @throws VersionException if this node is read-only due to a
+ * checked-in node and this implementation
+ * performs this validation immediately.
+ * @throws LockException if a lock prevents the setting of
+ * the property and this implementation
+ * performs this validation immediately.
+ * @throws ConstraintViolationException if the change would violate a
+ * node-type or other constraint and
+ * this implementation performs this
+ * validation immediately.
+ * @throws RepositoryException if another error occurs.
+ */
+ public PropertyImpl perform(SessionContext context)
+ throws RepositoryException {
+ itemSanityCheck();
+ // check pre-conditions for setting property
+ checkSetProperty();
+
+ int type = PropertyType.UNDEFINED;
+ if (value != null) {
+ type = value.getType();
+ }
+
+ BitSet status = new BitSet();
+ PropertyImpl property =
+ getOrCreateProperty(name, type, false, enforceType, status);
+ try {
+ property.setValue(value);
+ } catch (RepositoryException e) {
+ if (status.get(CREATED)) {
+ // setting value failed, get rid of newly created property
+ removeChildProperty(name);
+ }
+ throw e; // rethrow
+ } catch (RuntimeException e) {
+ if (status.get(CREATED)) {
+ // setting value failed, get rid of newly created property
+ removeChildProperty(name);
+ }
+ throw e; // rethrow
+ } catch (Error e) {
+ if (status.get(CREATED)) {
+ // setting value failed, get rid of newly created property
+ removeChildProperty(name);
+ }
+ throw e; // rethrow
+ }
+ return property;
+ }
+
+ //--------------------------------------------------------------< Object >
+
+ /**
+ * Returns a string representation of this operation.
+ */
+ public String toString() {
+ return "node.setProperty(" + name + ", " + value + ")";
+ }
+
+ }
+
+ /**
+ * Implementation for setProperty() using a {@link Value}
+ * array. The type of the returned property is enforced based on the
+ * enforceType flag. If set to true, the returned
+ * property is of the passed type if it didn't exist before. If set to
+ * false, then the returned property may be of some other type,
+ * but still must be based on an existing property definition for the given
+ * name and multi-valued flag. The resulting type is taken from that
+ * definition and the implementation tries to convert the passed values to
+ * that type. If that fails, then a {@link ValueFormatException} is thrown.
+ *
+ * @param name the name of the property to set.
+ * @param values the values to set. If null the property
+ * is removed.
+ * @param type the target type of the values to set.
+ * @param enforceType if the target type is enforced.
+ * @return the Property object set, or null if
+ * this method was used to remove a property (by setting its value
+ * to null).
+ * @throws ValueFormatException if a value cannot be converted to
+ * the specified type or if the
+ * property already exists and is not
+ * multi-valued.
+ * @throws VersionException if this node is read-only due to a
+ * checked-in node and this implementation
+ * performs this validation immediately.
+ * @throws LockException if a lock prevents the setting of
+ * the property and this implementation
+ * performs this validation immediately.
+ * @throws ConstraintViolationException if the change would violate a
+ * node-type or other constraint and
+ * this implementation performs this
+ * validation immediately.
+ * @throws RepositoryException if another error occurs.
+ */
+ protected PropertyImpl setProperty(
+ final Name name, final Value[] values, final int type,
+ final boolean enforceType) throws RepositoryException {
+ return perform(new SessionOperation() {
+ public PropertyImpl perform(SessionContext context)
+ throws RepositoryException {
+ // check pre-conditions for setting property
+ checkSetProperty();
+
+ BitSet status = new BitSet();
+ PropertyImpl prop = getOrCreateProperty(
+ name, type, true, enforceType, status);
+ try {
+ prop.setValue(values, type);
+ } catch (RepositoryException re) {
+ if (status.get(CREATED)) {
+ // setting value failed, get rid of newly created property
+ removeChildProperty(name);
+ }
+ // rethrow
+ throw re;
+ }
+ return prop;
+ }
+ public String toString() {
+ return "node.setProperty(...)";
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Node getNode(final String relPath) throws RepositoryException {
+ return perform(new SessionOperation() {
+ public Node perform(SessionContext context)
+ throws RepositoryException {
+ Path p = resolveRelativePath(relPath);
+ NodeId id = getNodeId(p);
+ if (id == null) {
+ throw new PathNotFoundException(relPath);
+ }
+
+ // determine parent as mandated by path
+ NodeId parentId = null;
+ if (!p.denotesRoot()) {
+ parentId = getNodeId(p.getAncestor(1));
+ }
+ try {
+ // if the node is shareable, it now returns the node
+ // with the right parent
+ if (parentId != null) {
+ return itemMgr.getNode(id, parentId);
+ } else {
+ return (NodeImpl) itemMgr.getItem(id);
+ }
+ } catch (AccessDeniedException e) {
+ throw new PathNotFoundException(relPath);
+ } catch (ItemNotFoundException e) {
+ throw new PathNotFoundException(relPath);
+ }
+ }
+ public String toString() {
+ return "node.getNode(" + relPath + ")";
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public NodeIterator getNodes() throws RepositoryException {
+ // IMPORTANT: an implementation of Node.getNodes() must not use
+ // a class derived from TraversingElementVisitor to traverse the
+ // hierarchy because this would lead to an infinite recursion!
+ return perform(new SessionOperation() {
+ public NodeIterator perform(SessionContext context)
+ throws RepositoryException {
+ try {
+ return itemMgr.getChildNodes((NodeId) id);
+ } catch (ItemNotFoundException e) {
+ throw new RepositoryException(
+ "Failed to list child nodes of " + NodeImpl.this, e);
+ } catch (AccessDeniedException e) {
+ throw new RepositoryException(
+ "Failed to list child nodes of " + NodeImpl.this, e);
+ }
+ }
+ public String toString() {
+ return "node.getNodes()";
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public PropertyIterator getProperties() throws RepositoryException {
+ // IMPORTANT: an implementation of Node.getProperties() must not use
+ // a class derived from TraversingElementVisitor to traverse the
+ // hierarchy because this would lead to an infinite recursion!
+ return perform(new SessionOperation() {
+ public PropertyIterator perform(SessionContext context)
+ throws RepositoryException {
+ try {
+ return itemMgr.getChildProperties((NodeId) id);
+ } catch (ItemNotFoundException e) {
+ throw new RepositoryException(
+ "Failed to list properties of " + NodeImpl.this, e);
+ } catch (AccessDeniedException e) {
+ throw new RepositoryException(
+ "Failed to list properties of " + NodeImpl.this, e);
+ }
+ }
+ public String toString() {
+ return "node.getProperties()";
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Property getProperty(final String relPath)
+ throws PathNotFoundException, RepositoryException {
+ return perform(new SessionOperation() {
+ public Property perform(SessionContext context)
+ throws RepositoryException {
+ PropertyId id = resolveRelativePropertyPath(relPath);
+ if (id != null) {
+ try {
+ return (Property) itemMgr.getItem(id);
+ } catch (ItemNotFoundException e) {
+ throw new PathNotFoundException(relPath);
+ } catch (AccessDeniedException e) {
+ throw new PathNotFoundException(relPath);
+ }
+ } else {
+ throw new PathNotFoundException(relPath);
+ }
+ }
+ public String toString() {
+ return "node.getProperty(" + relPath + ")";
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasNode(String relPath) throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ NodeId id = resolveRelativeNodePath(relPath);
+ if (id != null) {
+ return itemMgr.itemExists(id);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasNodes() throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ /**
+ * hasNodes respects the access rights
+ * of this node's session, i.e. it will
+ * return false if child nodes exist
+ * but the session is not granted read-access
+ */
+ return itemMgr.hasChildNodes((NodeId) id);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasProperties() throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ /**
+ * hasProperties respects the access rights
+ * of this node's session, i.e. it will
+ * return false if properties exist
+ * but the session is not granted read-access
+ */
+ return itemMgr.hasChildProperties((NodeId) id);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isNodeType(String nodeTypeName) throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ try {
+ return isNodeType(sessionContext.getQName(nodeTypeName));
+ } catch (NameException e) {
+ throw new RepositoryException(
+ "invalid node type name: " + nodeTypeName, e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public NodeType getPrimaryNodeType() throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ return sessionContext.getNodeTypeManager().getNodeType(
+ data.getNodeState().getNodeTypeName());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public NodeType[] getMixinNodeTypes() throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ Set mixinNames = data.getNodeState().getMixinTypeNames();
+ if (mixinNames.isEmpty()) {
+ return new NodeType[0];
+ }
+ NodeType[] nta = new NodeType[mixinNames.size()];
+ Iterator iter = mixinNames.iterator();
+ int i = 0;
+ while (iter.hasNext()) {
+ nta[i++] = sessionContext.getNodeTypeManager().getNodeType(iter.next());
+ }
+ return nta;
+ }
+
+ /** Wrapper around {@link #addMixin(Name)}. */
+ public void addMixin(String mixinName) throws RepositoryException {
+ try {
+ addMixin(sessionContext.getQName(mixinName));
+ } catch (NameException e) {
+ throw new RepositoryException(
+ "Invalid mixin type name: " + mixinName, e);
+ }
+ }
+
+ /** Wrapper around {@link #removeMixin(Name)}. */
+ public void removeMixin(String mixinName) throws RepositoryException {
+ try {
+ removeMixin(sessionContext.getQName(mixinName));
+ } catch (NameException e) {
+ throw new RepositoryException(
+ "Invalid mixin type name: " + mixinName, e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean canAddMixin(String mixinName)
+ throws NoSuchNodeTypeException, RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ Name ntName = sessionContext.getQName(mixinName);
+ NodeTypeManagerImpl ntMgr = sessionContext.getNodeTypeManager();
+ NodeTypeImpl mixin = ntMgr.getNodeType(ntName);
+ if (!mixin.isMixin()) {
+ return false;
+ }
+
+ int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_CHECKED_OUT
+ | ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD;
+ int permissions = Permission.NODE_TYPE_MNGMT;
+ // special handling of mix:(simple)versionable. since adding the mixin alters
+ // the version storage jcr:versionManagement privilege is required
+ // in addition.
+ if (NameConstants.MIX_VERSIONABLE.equals(ntName)
+ || NameConstants.MIX_SIMPLE_VERSIONABLE.equals(ntName)) {
+ permissions |= Permission.VERSION_MNGMT;
+ }
+ if (!sessionContext.getItemValidator().canModify(this, options, permissions)) {
+ return false;
+ }
+
+ final Name primaryTypeName = data.getNodeState().getNodeTypeName();
+
+ NodeTypeImpl primaryType = ntMgr.getNodeType(primaryTypeName);
+ if (primaryType.isDerivedFrom(ntName)) {
+ // mixin already inherited -> addMixin is allowed but has no effect.
+ return true;
+ }
+
+ // build effective node type of mixins & primary type
+ // in order to detect conflicts
+ NodeTypeRegistry ntReg = ntMgr.getNodeTypeRegistry();
+ EffectiveNodeType entExisting;
+ try {
+ // existing mixin's
+ Set mixins = new HashSet(data.getNodeState().getMixinTypeNames());
+
+ // build effective node type representing primary type including existing mixin's
+ entExisting = ntReg.getEffectiveNodeType(primaryTypeName, mixins);
+ if (entExisting.includesNodeType(ntName)) {
+ // the existing mixins already include the mixin to be added.
+ // addMixin would succeed without modifying the node.
+ return true;
+ }
+
+ // add new mixin
+ mixins.add(ntName);
+ // try to build new effective node type (will throw in case of conflicts)
+ ntReg.getEffectiveNodeType(primaryTypeName, mixins);
+ } catch (NodeTypeConflictException ntce) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasProperty(String relPath) throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ PropertyId id = resolveRelativePropertyPath(relPath);
+ if (id != null) {
+ return itemMgr.itemExists(id);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public PropertyIterator getReferences() throws RepositoryException {
+ return getReferences(null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public NodeDefinition getDefinition() throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ return data.getNodeDefinition();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public NodeIterator getNodes(String namePattern) throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ return ChildrenCollectorFilter.collectChildNodes(this, namePattern);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public PropertyIterator getProperties(String namePattern)
+ throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ return ChildrenCollectorFilter.collectProperties(this, namePattern);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Item getPrimaryItem()
+ throws ItemNotFoundException, RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ String name = getPrimaryNodeType().getPrimaryItemName();
+ if (name == null) {
+ throw new ItemNotFoundException();
+ }
+ if (hasProperty(name)) {
+ return getProperty(name);
+ } else if (hasNode(name)) {
+ return getNode(name);
+ } else {
+ throw new ItemNotFoundException();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getUUID()
+ throws UnsupportedRepositoryOperationException, RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ if (!isNodeType(NameConstants.MIX_REFERENCEABLE)) {
+ throw new UnsupportedRepositoryOperationException();
+ }
+
+ return getNodeId().toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getCorrespondingNodePath(String workspaceName)
+ throws ItemNotFoundException, NoSuchWorkspaceException,
+ AccessDeniedException, RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ SessionImpl srcSession = null;
+ try {
+ // create session on other workspace for current subject
+ // (may throw NoSuchWorkspaceException and AccessDeniedException)
+ RepositoryImpl rep = (RepositoryImpl) getSession().getRepository();
+ srcSession = rep.createSession(
+ sessionContext.getSessionImpl().getSubject(), workspaceName);
+
+ // search nearest ancestor that is referenceable
+ NodeImpl m1 = this;
+ while (m1.getDepth() != 0 && !m1.isNodeType(NameConstants.MIX_REFERENCEABLE)) {
+ m1 = (NodeImpl) m1.getParent();
+ }
+
+ // if root is common ancestor, corresponding path is same as ours
+ if (m1.getDepth() == 0) {
+ // check existence
+ if (!srcSession.getItemManager().nodeExists(getPrimaryPath())) {
+ throw new ItemNotFoundException("Node not found: " + this);
+ } else {
+ return getPath();
+ }
+ }
+
+ // get corresponding ancestor
+ Node m2 = srcSession.getNodeByUUID(m1.getUUID());
+
+ // return path of m2, if m1 == n1
+ if (m1 == this) {
+ return m2.getPath();
+ }
+
+ String relPath;
+ try {
+ Path p = m1.getPrimaryPath().computeRelativePath(getPrimaryPath());
+ // use prefix mappings of srcSession
+ relPath = sessionContext.getJCRPath(p);
+ } catch (NameException be) {
+ // should never get here...
+ String msg = "internal error: failed to determine relative path";
+ log.error(msg, be);
+ throw new RepositoryException(msg, be);
+ }
+
+ if (!m2.hasNode(relPath)) {
+ throw new ItemNotFoundException();
+ } else {
+ return m2.getNode(relPath).getPath();
+ }
+ } finally {
+ if (srcSession != null) {
+ // we don't need the other session anymore, logout
+ srcSession.logout();
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getIndex() throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ NodeId parentId = getParentId();
+ if (parentId == null) {
+ // the root node cannot have same-name siblings; always return 1
+ return 1;
+ }
+
+ try {
+ NodeState parent =
+ (NodeState) stateMgr.getItemState(parentId);
+ ChildNodeEntry parentEntry =
+ parent.getChildNodeEntry(getNodeId());
+ return parentEntry.getIndex();
+ } catch (ItemStateException ise) {
+ // should never get here...
+ String msg = "internal error: failed to determine index";
+ log.error(msg, ise);
+ throw new RepositoryException(msg, ise);
+ }
+ }
+
+ //-------------------------------------------------------< shareable nodes >
+
+ /**
+ * Returns an iterator over all nodes that are in the shared set of this
+ * node. If this node is not shared then the returned iterator contains
+ * only this node.
+ *
+ * @return a NodeIterator
+ * @throws RepositoryException if an error occurs.
+ * @since JCR 2.0
+ */
+ public NodeIterator getSharedSet() throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ ArrayList list = new ArrayList();
+
+ if (!isShareable()) {
+ list.add(this);
+ } else {
+ NodeState state = data.getNodeState();
+ for (NodeId parentId : state.getSharedSet()) {
+ list.add(itemMgr.getNode(getNodeId(), parentId));
+ }
+ }
+ return new NodeIteratorAdapter(list);
+ }
+
+ /**
+ * A special kind of remove() that removes this node and every
+ * other node in the shared set of this node.
+ *
+ * This removal must be done atomically, i.e., if one of the nodes cannot be
+ * removed, the function throws the exception remove() would
+ * have thrown in that case, and none of the nodes are removed.
+ *
+ * If this node is not shared this method removes only this node.
+ *
+ * @throws VersionException
+ * @throws LockException
+ * @throws ConstraintViolationException
+ * @throws RepositoryException
+ * @see #removeShare()
+ * @see Item#remove()
+ * @since JCR 2.0
+ */
+ public void removeSharedSet() throws VersionException, LockException,
+ ConstraintViolationException, RepositoryException {
+
+ // check state of this instance
+ sanityCheck();
+
+ NodeIterator iter = getSharedSet();
+ while (iter.hasNext()) {
+ iter.nextNode().removeShare();
+ }
+ }
+
+ /**
+ * A special kind of remove() that removes this node, but does
+ * not remove any other node in the shared set of this node.
+ *
+ * All of the exceptions defined for remove() apply to this
+ * function. In addition, a RepositoryException is thrown if
+ * this node cannot be removed without removing another node in the shared
+ * set of this node.
+ *
+ * If this node is not shared this method removes only this node.
+ *
+ * @throws VersionException
+ * @throws LockException
+ * @throws ConstraintViolationException
+ * @throws RepositoryException
+ * @see #removeSharedSet()
+ * @see Item#remove()
+ * @since JCR 2.0
+ */
+ public void removeShare() throws VersionException, LockException,
+ ConstraintViolationException, RepositoryException {
+
+ // check state of this instance
+ sanityCheck();
+
+ // Standard remove() will remove just this node
+ remove();
+ }
+
+ /**
+ * Helper method, returning a flag that indicates whether this node is
+ * shareable.
+ *
+ * @return true if this node is shareable;
+ * false otherwise.
+ * @see NodeState#isShareable()
+ */
+ boolean isShareable() {
+ return data.getNodeState().isShareable();
+ }
+
+ /**
+ * Helper method, returning the parent id this node is attached to. If this
+ * node is shareable, it returns the primary parent id (which remains
+ * fixed since shareable nodes are not moveable). Otherwise returns the
+ * underlying state's parent id.
+ *
+ * @return parent id
+ */
+ public NodeId getParentId() {
+ return data.getParentId();
+ }
+
+ /**
+ * Helper method, returning a flag indicating whether this node has
+ * the given share-parent.
+ *
+ * @param parentId parent id
+ * @return true if the node has the given shared parent;
+ * false otherwise.
+ */
+ boolean hasShareParent(NodeId parentId) {
+ return data.getNodeState().containsShare(parentId);
+ }
+
+ /**
+ * Add a share-parent to this node. This method checks, whether:
+ *
+ *
this node is shareable
+ *
adding the given would create a share cycle
+ *
the given parent is already a share-parent
+ *
+ * @param parentId parent to add to the shared set
+ * @throws RepositoryException if an error occurs
+ */
+ void addShareParent(NodeId parentId) throws RepositoryException {
+ // verify that we're shareable
+ if (!isShareable()) {
+ String msg = this + " is not shareable.";
+ log.debug(msg);
+ throw new RepositoryException(msg);
+ }
+
+ // detect share cycle
+ NodeId srcId = getNodeId();
+ HierarchyManager hierMgr = sessionContext.getHierarchyManager();
+ if (parentId.equals(srcId) || hierMgr.isAncestor(srcId, parentId)) {
+ String msg = "This would create a share cycle.";
+ log.debug(msg);
+ throw new RepositoryException(msg);
+ }
+
+ // quickly verify whether the share is already contained before creating
+ // a transient state in vain
+ NodeState state = data.getNodeState();
+ if (!state.containsShare(parentId)) {
+ state = (NodeState) getOrCreateTransientItemState();
+ if (state.addShare(parentId)) {
+ return;
+ }
+ }
+ String msg = "Adding a shareable node twice to the same parent is not supported.";
+ log.debug(msg);
+ throw new UnsupportedRepositoryOperationException(msg);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Overridden to return a different path for shareable nodes.
+ *
+ * TODO SN: copies functionality in that is already available in
+ * HierarchyManagerImpl, namely composing a path by
+ * concatenating the parent path + this node's name and index:
+ * rather use hierarchy manager to do this
+ */
+ @Override
+ public Path getPrimaryPath() throws RepositoryException {
+ if (!isShareable()) {
+ return super.getPrimaryPath();
+ }
+
+ NodeId parentId = getParentId();
+ NodeImpl parentNode = (NodeImpl) getParent();
+ Path parentPath = parentNode.getPrimaryPath();
+ PathBuilder builder = new PathBuilder(parentPath);
+
+ ChildNodeEntry entry =
+ parentNode.getNodeState().getChildNodeEntry(getNodeId());
+ if (entry == null) {
+ String msg = "failed to build path of " + id + ": "
+ + parentId + " has no child entry for "
+ + id;
+ log.debug(msg);
+ throw new ItemNotFoundException(msg);
+ }
+ // add to path
+ if (entry.getIndex() == 1) {
+ builder.addLast(entry.getName());
+ } else {
+ builder.addLast(entry.getName(), entry.getIndex());
+ }
+ return builder.getPath();
+ }
+
+ //------------------------------< versioning support: public Node methods >
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isCheckedOut() throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ // try shortcut first:
+ // if current node is 'new' we can safely consider it checked-out since
+ // otherwise it would had been impossible to add it in the first place
+ if (isNew()) {
+ return true;
+ }
+
+ // search nearest ancestor that is versionable
+ // FIXME should not only rely on existence of jcr:isCheckedOut property
+ // but also verify that node.isNodeType("mix:versionable")==true;
+ // this would have a negative impact on performance though...
+ try {
+ NodeState state = getNodeState();
+ while (!state.hasPropertyName(JCR_ISCHECKEDOUT)) {
+ ItemId parentId = state.getParentId();
+ if (parentId == null) {
+ // root reached or out of hierarchy
+ return true;
+ }
+ state = (NodeState)
+ sessionContext.getItemStateManager().getItemState(parentId);
+ }
+ PropertyId id = new PropertyId(state.getNodeId(), JCR_ISCHECKEDOUT);
+ PropertyState ps =
+ (PropertyState) sessionContext.getItemStateManager().getItemState(id);
+ InternalValue[] values = ps.getValues();
+ if (values == null || values.length != 1) {
+ // the property is not fully set, or it is a multi-valued property
+ // in which case it's probably not mix:versionable
+ return true;
+ }
+ return values[0].getBoolean();
+ } catch (ItemStateException e) {
+ throw new RepositoryException(e);
+ }
+ }
+
+ /**
+ * Returns the version manager of this workspace.
+ */
+ private VersionManagerImpl getVersionManagerImpl() {
+ return sessionContext.getWorkspace().getVersionManagerImpl();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void update(String srcWorkspaceName) throws RepositoryException {
+ getVersionManagerImpl().update(this, srcWorkspaceName);
+ }
+
+ /**
+ * Use {@link VersionManager#checkin(String)} instead
+ */
+ @Deprecated
+ public Version checkin() throws RepositoryException {
+ return getVersionManagerImpl().checkin(getPath());
+ }
+
+ /**
+ * Use {@link VersionManagerImpl#checkin(String, Calendar)} instead
+ *
+ * @since Apache Jackrabbit 1.6
+ * @see JCR-1972
+ */
+ @Deprecated
+ public Version checkin(Calendar created) throws RepositoryException {
+ return getVersionManagerImpl().checkin(getPath(), created);
+ }
+
+ /**
+ * Use {@link VersionManager#checkout(String)} instead
+ */
+ @Deprecated
+ public void checkout() throws RepositoryException {
+ getVersionManagerImpl().checkout(getPath());
+ }
+
+ /**
+ * Use {@link VersionManager#merge(String, String, boolean)} instead
+ */
+ @Deprecated
+ public NodeIterator merge(String srcWorkspace, boolean bestEffort)
+ throws RepositoryException {
+ return getVersionManagerImpl().merge(
+ getPath(), srcWorkspace, bestEffort);
+ }
+
+ /**
+ * Use {@link VersionManager#cancelMerge(String, Version)} instead
+ */
+ @Deprecated
+ public void cancelMerge(Version version) throws RepositoryException {
+ getVersionManagerImpl().cancelMerge(getPath(), version);
+ }
+
+ /**
+ * Use {@link VersionManager#doneMerge(String, Version)} instead
+ */
+ @Deprecated
+ public void doneMerge(Version version) throws RepositoryException {
+ getVersionManagerImpl().doneMerge(getPath(), version);
+ }
+
+ /**
+ * Use {@link VersionManager#restore(String, String, boolean)} instead
+ */
+ @Deprecated
+ public void restore(String versionName, boolean removeExisting)
+ throws RepositoryException {
+ getVersionManagerImpl().restore(getPath(), versionName, removeExisting);
+ }
+
+ /**
+ * Use {@link VersionManager#restore(String, Version, boolean)} instead
+ */
+ @Deprecated
+ public void restore(Version version, boolean removeExisting)
+ throws RepositoryException {
+ getVersionManagerImpl().restore(this, version, removeExisting);
+ }
+
+ /**
+ * Use {@link VersionManager#restore(String, Version, boolean)} instead
+ */
+ @Deprecated
+ public void restore(Version version, String relPath, boolean removeExisting)
+ throws RepositoryException {
+ if (hasNode(relPath)) {
+ getVersionManagerImpl().restore((NodeImpl) getNode(relPath), version, removeExisting);
+ } else {
+ getVersionManagerImpl().restore(
+ getPath() + "/" + relPath, version, removeExisting);
+ }
+ }
+
+ /**
+ * Use {@link VersionManager#restoreByLabel(String, String, boolean)}
+ * instead
+ */
+ @Deprecated
+ public void restoreByLabel(String versionLabel, boolean removeExisting)
+ throws RepositoryException {
+ getVersionManagerImpl().restoreByLabel(
+ getPath(), versionLabel, removeExisting);
+ }
+
+ /**
+ * Use {@link VersionManager#getVersionHistory(String)} instead
+ */
+ @Deprecated
+ public VersionHistory getVersionHistory() throws RepositoryException {
+ return getVersionManagerImpl().getVersionHistory(getPath());
+ }
+
+ /**
+ * Use {@link VersionManager#getBaseVersion(String)} instead
+ */
+ @Deprecated
+ public Version getBaseVersion() throws RepositoryException {
+ return getVersionManagerImpl().getBaseVersion(getPath());
+ }
+
+ //------------------------------------------------------< locking support >
+ /**
+ * {@inheritDoc}
+ */
+ public Lock lock(boolean isDeep, boolean isSessionScoped)
+ throws UnsupportedRepositoryOperationException, LockException,
+ AccessDeniedException, InvalidItemStateException,
+ RepositoryException {
+ // check state of this instance
+ sanityCheck();
+ LockManager lockMgr = getSession().getWorkspace().getLockManager();
+ return lockMgr.lock(getPath(), isDeep, isSessionScoped,
+ sessionContext.getWorkspace().getConfig().getDefaultLockTimeout(), null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Lock getLock()
+ throws UnsupportedRepositoryOperationException, LockException,
+ AccessDeniedException, RepositoryException {
+ // check state of this instance
+ sanityCheck();
+ LockManager lockMgr = getSession().getWorkspace().getLockManager();
+ return lockMgr.getLock(getPath());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void unlock()
+ throws UnsupportedRepositoryOperationException, LockException,
+ AccessDeniedException, InvalidItemStateException,
+ RepositoryException {
+ // check state of this instance
+ sanityCheck();
+ LockManager lockMgr = getSession().getWorkspace().getLockManager();
+ lockMgr.unlock(getPath());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean holdsLock() throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+ LockManager lockMgr = getSession().getWorkspace().getLockManager();
+ return lockMgr.holdsLock(getPath());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isLocked() throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+ LockManager lockMgr = getSession().getWorkspace().getLockManager();
+ return lockMgr.isLocked(getPath());
+ }
+
+ /**
+ * Check whether this node is locked by somebody else.
+ *
+ * @throws LockException if this node is locked by somebody else
+ * @throws RepositoryException if some other error occurs
+ * @deprecated
+ */
+ protected void checkLock() throws LockException, RepositoryException {
+ if (isNew()) {
+ // a new node needs no check
+ return;
+ }
+ sessionContext.getWorkspace().getInternalLockManager().checkLock(this);
+ }
+
+ //--------------------------------------------------< new JSR 283 methods >
+ /**
+ * {@inheritDoc}
+ */
+ public String getIdentifier() throws RepositoryException {
+ return id.toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public PropertyIterator getReferences(String name)
+ throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ try {
+ if (stateMgr.hasNodeReferences(getNodeId())) {
+ NodeReferences refs = stateMgr.getNodeReferences(getNodeId());
+ // refs.getReferences() returns a list of PropertyId's
+ List idList = refs.getReferences();
+ if (name != null) {
+ Name qName;
+ try {
+ qName = sessionContext.getQName(name);
+ } catch (NameException e) {
+ throw new RepositoryException("invalid property name: " + name, e);
+ }
+ ArrayList filteredList = new ArrayList(idList.size());
+ for (PropertyId propId : idList) {
+ if (propId.getName().equals(qName)) {
+ filteredList.add(propId);
+ }
+ }
+ idList = filteredList;
+ }
+ return new LazyItemIterator(sessionContext, idList);
+ } else {
+ // there are no references, return empty iterator
+ return PropertyIteratorAdapter.EMPTY;
+ }
+ } catch (ItemStateException e) {
+ String msg = "Unable to retrieve REFERENCE properties that refer to " + id;
+ log.debug(msg);
+ throw new RepositoryException(msg, e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public PropertyIterator getWeakReferences() throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ // shortcut if node isn't referenceable
+ if (!isNodeType(NameConstants.MIX_REFERENCEABLE)) {
+ return PropertyIteratorAdapter.EMPTY;
+ }
+
+ Value ref = getSession().getValueFactory().createValue(this, true);
+ List props = new ArrayList();
+ QueryManagerImpl qm = (QueryManagerImpl) getSession().getWorkspace().getQueryManager();
+ for (Node n : qm.getWeaklyReferringNodes(this)) {
+ for (PropertyIterator it = n.getProperties(); it.hasNext(); ) {
+ Property p = it.nextProperty();
+ if (p.getType() == PropertyType.WEAKREFERENCE) {
+ Collection refs;
+ if (p.isMultiple()) {
+ refs = Arrays.asList(p.getValues());
+ } else {
+ refs = Collections.singleton(p.getValue());
+ }
+ if (refs.contains(ref)) {
+ props.add(p);
+ }
+ }
+ }
+ }
+ return new PropertyIteratorAdapter(props);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public PropertyIterator getWeakReferences(String name) throws RepositoryException {
+ if (name == null) {
+ return getWeakReferences();
+ }
+
+ // check state of this instance
+ sanityCheck();
+
+ // shortcut if node isn't referenceable
+ if (!isNodeType(NameConstants.MIX_REFERENCEABLE)) {
+ return PropertyIteratorAdapter.EMPTY;
+ }
+
+ try {
+ StringBuilder stmt = new StringBuilder();
+ stmt.append("//*[@").append(ISO9075.encode(name));
+ stmt.append(" = '").append(data.getId()).append("']");
+ Query q = getSession().getWorkspace().getQueryManager().createQuery(
+ stmt.toString(), Query.XPATH);
+ QueryResult result = q.execute();
+ ArrayList l = new ArrayList();
+ for (NodeIterator nit = result.getNodes(); nit.hasNext();) {
+ Node n = nit.nextNode();
+ l.add(n.getProperty(name));
+ }
+ if (l.isEmpty()) {
+ return PropertyIteratorAdapter.EMPTY;
+ } else {
+ return new PropertyIteratorAdapter(l);
+ }
+ } catch (RepositoryException e) {
+ String msg = "Unable to retrieve WEAKREFERENCE properties that refer to " + id;
+ log.debug(msg);
+ throw new RepositoryException(msg, e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public NodeIterator getNodes(String[] nameGlobs)
+ throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ return ChildrenCollectorFilter.collectChildNodes(this, nameGlobs);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public PropertyIterator getProperties(String[] nameGlobs)
+ throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ return ChildrenCollectorFilter.collectProperties(this, nameGlobs);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setPrimaryType(String nodeTypeName)
+ throws NoSuchNodeTypeException, VersionException,
+ ConstraintViolationException, LockException, RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ // make sure this node is checked-out, neither protected nor locked and
+ // the editing session has sufficient permission to change the primary type.
+ int options = ItemValidator.CHECK_CHECKED_OUT | ItemValidator.CHECK_LOCK
+ | ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD;
+ sessionContext.getItemValidator().checkModify(this, options, Permission.NODE_TYPE_MNGMT);
+
+ final NodeState state = data.getNodeState();
+ if (state.getParentId() == null) {
+ String msg = "changing the primary type of the root node is not supported";
+ log.debug(msg);
+ throw new RepositoryException(msg);
+ }
+
+ Name ntName = sessionContext.getQName(nodeTypeName);
+ if (ntName.equals(state.getNodeTypeName())) {
+ log.debug("Node already has " + nodeTypeName + " as primary node type.");
+ return;
+ }
+
+ NodeTypeManagerImpl ntMgr = sessionContext.getNodeTypeManager();
+ NodeType nt = ntMgr.getNodeType(ntName);
+ if (nt.isMixin()) {
+ throw new ConstraintViolationException(nodeTypeName + ": not a primary node type.");
+ } else if (nt.isAbstract()) {
+ throw new ConstraintViolationException(nodeTypeName + ": is an abstract node type.");
+ }
+
+ // build effective node type of new primary type & existing mixin's
+ // in order to detect conflicts
+ NodeTypeRegistry ntReg = ntMgr.getNodeTypeRegistry();
+ EffectiveNodeType entNew, entOld, entAll;
+ try {
+ entNew = ntReg.getEffectiveNodeType(ntName);
+ entOld = ntReg.getEffectiveNodeType(state.getNodeTypeName());
+
+ // try to build new effective node type (will throw in case of conflicts)
+ entAll = ntReg.getEffectiveNodeType(ntName, state.getMixinTypeNames());
+ } catch (NodeTypeConflictException ntce) {
+ throw new ConstraintViolationException(ntce.getMessage());
+ }
+
+ // get applicable definition for this node using new primary type
+ QNodeDefinition nodeDef;
+ try {
+ NodeImpl parent = (NodeImpl) getParent();
+ nodeDef = parent.getApplicableChildNodeDefinition(getQName(), ntName).unwrap();
+ } catch (RepositoryException re) {
+ String msg = this + ": no applicable definition found in parent node's node type";
+ log.debug(msg);
+ throw new ConstraintViolationException(msg, re);
+ }
+
+ if (!nodeDef.equals(itemMgr.getDefinition(state).unwrap())) {
+ onRedefine(nodeDef);
+ }
+
+ Set oldDefs = new HashSet(Arrays.asList(entOld.getAllItemDefs()));
+ Set newDefs = new HashSet(Arrays.asList(entNew.getAllItemDefs()));
+ Set allDefs = new HashSet(Arrays.asList(entAll.getAllItemDefs()));
+
+ // added child item definitions
+ Set addedDefs = new HashSet(newDefs);
+ addedDefs.removeAll(oldDefs);
+
+ // referential integrity check
+ boolean referenceableOld = entOld.includesNodeType(NameConstants.MIX_REFERENCEABLE);
+ boolean referenceableNew = entNew.includesNodeType(NameConstants.MIX_REFERENCEABLE);
+ if (referenceableOld && !referenceableNew) {
+ // node would become non-referenceable;
+ // make sure no references exist
+ PropertyIterator iter = getReferences();
+ if (iter.hasNext()) {
+ throw new ConstraintViolationException(
+ "the new primary type cannot be set as it would render "
+ + "this node 'non-referenceable' while it is still being "
+ + "referenced through at least one property of type REFERENCE");
+ }
+ }
+
+ // do the actual modifications in content as mandated by the new primary type
+
+ // modify the state of this node
+ NodeState thisState = (NodeState) getOrCreateTransientItemState();
+ thisState.setNodeTypeName(ntName);
+
+ // set jcr:primaryType property
+ internalSetProperty(NameConstants.JCR_PRIMARYTYPE, InternalValue.create(ntName));
+
+ // walk through properties and child nodes and change definition as necessary
+
+ // use temp set to avoid ConcurrentModificationException
+ HashSet set = new HashSet(thisState.getPropertyNames());
+ for (Name propName : set) {
+ try {
+ PropertyState propState =
+ (PropertyState) stateMgr.getItemState(
+ new PropertyId(thisState.getNodeId(), propName));
+ if (!allDefs.contains(itemMgr.getDefinition(propState).unwrap())) {
+ // try to find new applicable definition first and
+ // redefine property if possible
+ try {
+ PropertyImpl prop = (PropertyImpl) itemMgr.getItem(propState.getId());
+ if (prop.getDefinition().isProtected()) {
+ // remove 'orphaned' protected properties immediately
+ removeChildProperty(propName);
+ continue;
+ }
+ PropertyDefinitionImpl pdi = getApplicablePropertyDefinition(
+ propName, propState.getType(),
+ propState.isMultiValued(), false);
+ if (pdi.getRequiredType() != PropertyType.UNDEFINED
+ && pdi.getRequiredType() != propState.getType()) {
+ // value conversion required
+ if (propState.isMultiValued()) {
+ // convert value
+ Value[] values =
+ ValueHelper.convert(
+ prop.getValues(),
+ pdi.getRequiredType(),
+ getSession().getValueFactory());
+ // redefine property
+ prop.onRedefine(pdi.unwrap());
+ // set converted values
+ prop.setValue(values);
+ } else {
+ // convert value
+ Value value =
+ ValueHelper.convert(
+ prop.getValue(),
+ pdi.getRequiredType(),
+ getSession().getValueFactory());
+ // redefine property
+ prop.onRedefine(pdi.unwrap());
+ // set converted values
+ prop.setValue(value);
+ }
+ } else {
+ // redefine property
+ prop.onRedefine(pdi.unwrap());
+ }
+ // update collection of added definitions
+ addedDefs.remove(pdi.unwrap());
+ } catch (ValueFormatException vfe) {
+ // value conversion failed, remove it
+ removeChildProperty(propName);
+ } catch (ConstraintViolationException cve) {
+ // no suitable definition found for this property,
+ // remove it
+ removeChildProperty(propName);
+ }
+ }
+ } catch (ItemStateException ise) {
+ String msg = propName + ": failed to retrieve property state";
+ log.error(msg, ise);
+ throw new RepositoryException(msg, ise);
+ }
+ }
+
+ // use temp array to avoid ConcurrentModificationException
+ ArrayList list = new ArrayList(thisState.getChildNodeEntries());
+ // start from tail to avoid problems with same-name siblings
+ for (int i = list.size() - 1; i >= 0; i--) {
+ ChildNodeEntry entry = list.get(i);
+ try {
+ NodeState nodeState = (NodeState) stateMgr.getItemState(entry.getId());
+ if (!allDefs.contains(itemMgr.getDefinition(nodeState).unwrap())) {
+ // try to find new applicable definition first and
+ // redefine node if possible
+ try {
+ NodeImpl node = (NodeImpl) itemMgr.getItem(nodeState.getId());
+ if (node.getDefinition().isProtected()) {
+ // remove 'orphaned' protected child node immediately
+ removeChildNode(entry.getId());
+ continue;
+ }
+ NodeDefinitionImpl ndi = getApplicableChildNodeDefinition(
+ entry.getName(),
+ nodeState.getNodeTypeName());
+ // redefine node
+ node.onRedefine(ndi.unwrap());
+ // update collection of added definitions
+ addedDefs.remove(ndi.unwrap());
+ } catch (ConstraintViolationException cve) {
+ // no suitable definition found for this child node,
+ // remove it
+ removeChildNode(entry.getId());
+ }
+ }
+ } catch (ItemStateException ise) {
+ String msg = entry.getName() + ": failed to retrieve node state";
+ log.error(msg, ise);
+ throw new RepositoryException(msg, ise);
+ }
+ }
+
+ // create items that are defined as auto-created by the new primary node
+ // type and at the same time were not present with the old nt
+ for (QItemDefinition def : addedDefs) {
+ if (def.isAutoCreated()) {
+ if (def.definesNode()) {
+ NodeDefinitionImpl ndi = ntMgr.getNodeDefinition((QNodeDefinition) def);
+ createChildNode(def.getName(), (NodeTypeImpl) ndi.getDefaultPrimaryType(), null);
+ } else {
+ PropertyDefinitionImpl pdi = ntMgr.getPropertyDefinition((QPropertyDefinition) def);
+ createChildProperty(pdi.unwrap().getName(), pdi.getRequiredType(), pdi);
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Property setProperty(String name, BigDecimal value)
+ throws ValueFormatException, VersionException, LockException,
+ ConstraintViolationException, RepositoryException {
+ Value v = null;
+ if (value != null) {
+ v = getSession().getValueFactory().createValue(value);
+ }
+ return setProperty(name, v);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Property setProperty(String name, Binary value)
+ throws ValueFormatException, VersionException, LockException,
+ ConstraintViolationException, RepositoryException {
+ Value v = null;
+ if (value != null) {
+ v = getSession().getValueFactory().createValue(value);
+ }
+ return setProperty(name, v);
+ }
+
+ /**
+ * Returns all allowed transitions from the current lifecycle state of
+ * this node.
+ *
+ * The lifecycle policy node referenced by the "jcr:lifecyclePolicy"
+ * property is expected to contain a "transitions" node with a list of
+ * child nodes, one for each transition. These transition nodes must
+ * have single-valued string "from" and "to" properties that identify
+ * the allowed source and target states of each transition.
+ *
+ * Note that future versions of Apache Jackrabbit may well use different
+ * lifecycle policy implementations.
+ *
+ * @since Apache Jackrabbit 2.0
+ * @return allowed transitions for the current lifecycle state of this node
+ * @throws UnsupportedRepositoryOperationException
+ * if this node does not have the mix:lifecycle mixin node type
+ * @throws RepositoryException if a repository error occurs
+ */
+ public String[] getAllowedLifecycleTransistions()
+ throws UnsupportedRepositoryOperationException, RepositoryException {
+ if (isNodeType(NameConstants.MIX_LIFECYCLE)) {
+ Node policy = getProperty(JCR_LIFECYCLE_POLICY).getNode();
+ String state = getProperty(JCR_CURRENT_LIFECYCLE_STATE).getString();
+
+ List targetStates = new ArrayList();
+ if (policy.hasNode("transitions")) {
+ Node transitions = policy.getNode("transitions");
+ for (Node transition : JcrUtils.getChildNodes(transitions)) {
+ String from = transition.getProperty("from").getString();
+ if (from.equals(state)) {
+ String to = transition.getProperty("to").getString();
+ targetStates.add(to);
+ }
+ }
+ }
+
+ return targetStates.toArray(new String[targetStates.size()]);
+ } else {
+ throw new UnsupportedRepositoryOperationException(
+ "Only nodes with mixin node type mix:lifecycle"
+ + " may participate in a lifecycle: " + this);
+ }
+ }
+
+ /**
+ * Transitions this node through its lifecycle to the given target state.
+ *
+ * @since Apache Jackrabbit 2.0
+ * @see #getAllowedLifecycleTransistions()
+ * @param transition target lifecycle state
+ * @throws UnsupportedRepositoryOperationException
+ * if this node does not have the mix:lifecycle mixin node type
+ * @throws InvalidLifecycleTransitionException
+ * if the given target state is not among the allowed
+ * transitions from the current lifecycle state of this node
+ * @throws RepositoryException if a repository error occurs
+ */
+ public void followLifecycleTransition(String transition)
+ throws UnsupportedRepositoryOperationException,
+ InvalidLifecycleTransitionException, RepositoryException {
+ // getAllowedLifecycleTransitions checks for the mix:lifecycle mixin
+ for (String target : getAllowedLifecycleTransistions()) {
+ if (target.equals(transition)) {
+ PropertyImpl property = getProperty(JCR_CURRENT_LIFECYCLE_STATE);
+ property.internalSetValue(
+ new InternalValue[] { InternalValue.create(target) },
+ PropertyType.STRING);
+ property.save();
+ return;
+ }
+ }
+
+ // No valid transition found
+ throw new InvalidLifecycleTransitionException(
+ "Invalid lifecycle transition \""
+ + transition + "\" for " + this);
+ }
+
+ /**
+ * Assigns the given lifecycle policy to this node and sets the
+ * current state to the one given.
+ *
+ * Note that currently no special checks are made against the given
+ * arguments, and that you will need to explicitly persist these changes
+ * by calling save().
+ *
+ * Note that future versions of Apache Jackrabbit may well use different
+ * lifecycle policy implementations.
+ *
+ * @param policy lifecycle policy node
+ * @param state current lifecycle state
+ * @throws RepositoryException if a repository error occurs
+ */
+ public void assignLifecyclePolicy(Node policy, String state)
+ throws RepositoryException {
+ if (!(policy instanceof NodeImpl)
+ || !((NodeImpl) policy).isNodeType(MIX_REFERENCEABLE)) {
+ throw new RepositoryException(
+ policy + " is not referenceable, so it can not be"
+ + " used as a lifecycle policy");
+ }
+
+ addMixin(MIX_LIFECYCLE);
+ internalSetProperty(
+ JCR_LIFECYCLE_POLICY,
+ InternalValue.create(((NodeImpl) policy).getNodeId()));
+ internalSetProperty(
+ JCR_CURRENT_LIFECYCLE_STATE,
+ InternalValue.create(state));
+ }
+
+ //-------------------------------------------------------< JackrabbitNode >
+
+ /**
+ * {@inheritDoc}
+ */
+ public void rename(String newName) throws RepositoryException {
+ // check if this is the root node
+ if (getDepth() == 0) {
+ throw new RepositoryException("Cannot rename the root node");
+ }
+
+ Name qName;
+ try {
+ qName = sessionContext.getQName(newName);
+ } catch (NameException e) {
+ throw new RepositoryException("invalid node name: " + newName, e);
+ }
+
+ NodeImpl parent = (NodeImpl) getParent();
+
+ // check for name collisions
+ NodeImpl existing = null;
+ try {
+ existing = parent.getNode(qName);
+ // there's already a node with that name:
+ // check same-name sibling setting of existing node
+ if (!existing.getDefinition().allowsSameNameSiblings()) {
+ throw new ItemExistsException(
+ "Same name siblings are not allowed: " + existing);
+ }
+ } catch (AccessDeniedException ade) {
+ // FIXME by throwing ItemExistsException we're disclosing too much information
+ throw new ItemExistsException();
+ } catch (ItemNotFoundException infe) {
+ // no name collision, fall through
+ }
+
+ // verify that parent node
+ // - is checked-out
+ // - is not protected neither by node type constraints nor by retention/hold
+ int options = ItemValidator.CHECK_CHECKED_OUT | ItemValidator.CHECK_LOCK |
+ ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD | ItemValidator.CHECK_RETENTION;
+ sessionContext.getItemValidator().checkRemove(parent, options, Permission.NONE);
+ sessionContext.getItemValidator().checkModify(parent, options, Permission.NONE);
+
+ // check constraints
+ // get applicable definition of renamed target node
+ NodeTypeImpl nt = (NodeTypeImpl) getPrimaryNodeType();
+ org.apache.jackrabbit.spi.commons.nodetype.NodeDefinitionImpl newTargetDef;
+ try {
+ newTargetDef = parent.getApplicableChildNodeDefinition(qName, nt.getQName());
+ } catch (RepositoryException re) {
+ String msg = safeGetJCRPath() + ": no definition found in parent node's node type for renamed node";
+ log.debug(msg);
+ throw new ConstraintViolationException(msg, re);
+ }
+ // if there's already a node with that name also check same-name sibling
+ // setting of new node; just checking same-name sibling setting on
+ // existing node is not sufficient since same-name sibling nodes don't
+ // necessarily have identical definitions
+ if (existing != null && !newTargetDef.allowsSameNameSiblings()) {
+ throw new ItemExistsException(
+ "Same name siblings not allowed: " + existing);
+ }
+
+ // check permissions:
+ // 1. on the parent node the session must have permission to manipulate the child-entries
+ AccessManager acMgr = sessionContext.getAccessManager();
+ if (!acMgr.isGranted(parent.getPrimaryPath(), qName, Permission.MODIFY_CHILD_NODE_COLLECTION)) {
+ String msg = "Not allowed to rename node " + safeGetJCRPath() + " to " + newName;
+ log.debug(msg);
+ throw new AccessDeniedException(msg);
+ }
+ // 2. in case of nt-changes the session must have permission to change
+ // the primary node type on this node itself.
+ if (!nt.getName().equals(newTargetDef.getName()) && !(acMgr.isGranted(getPrimaryPath(), Permission.NODE_TYPE_MNGMT))) {
+ String msg = "Not allowed to rename node " + safeGetJCRPath() + " to " + newName;
+ log.debug(msg);
+ throw new AccessDeniedException(msg);
+ }
+
+ // change definition
+ onRedefine(newTargetDef.unwrap());
+
+ // delegate to parent
+ parent.renameChildNode(getNodeId(), qName, true);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setMixins(String[] mixinNames)
+ throws NoSuchNodeTypeException, VersionException,
+ ConstraintViolationException, LockException, RepositoryException {
+
+ // check state of this instance
+ sanityCheck();
+
+ NodeTypeManagerImpl ntMgr = sessionContext.getNodeTypeManager();
+
+ Set newMixins = new HashSet();
+ for (String name : mixinNames) {
+ Name qName = sessionContext.getQName(name);
+ if (! ntMgr.getNodeType(qName).isMixin()) {
+ throw new RepositoryException(
+ sessionContext.getJCRName(qName) + " is not a mixin node type");
+ }
+ newMixins.add(qName);
+ }
+
+ // make sure this node is checked-out, neither protected nor locked and
+ // the editing session has sufficient permission to change the mixin types.
+
+ // special handling of mix:(simple)versionable. since adding the
+ // mixin alters the version storage jcr:versionManagement privilege
+ // is required in addition.
+ int permissions = Permission.NODE_TYPE_MNGMT;
+ if (newMixins.contains(MIX_VERSIONABLE)
+ || newMixins.contains(MIX_SIMPLE_VERSIONABLE)) {
+ permissions |= Permission.VERSION_MNGMT;
+ }
+ int options = ItemValidator.CHECK_CHECKED_OUT | ItemValidator.CHECK_LOCK
+ | ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD;
+ sessionContext.getItemValidator().checkModify(this, options, permissions);
+
+ final NodeState state = data.getNodeState();
+
+ // build effective node type of primary type & new mixin's
+ // in order to detect conflicts
+ NodeTypeRegistry ntReg = ntMgr.getNodeTypeRegistry();
+ EffectiveNodeType entNew, entOld, entAll;
+ try {
+ entNew = ntReg.getEffectiveNodeType(newMixins);
+ entOld = ntReg.getEffectiveNodeType(state.getMixinTypeNames());
+
+ // try to build new effective node type (will throw in case of conflicts)
+ entAll = ntReg.getEffectiveNodeType(state.getNodeTypeName(), newMixins);
+ } catch (NodeTypeConflictException ntce) {
+ throw new ConstraintViolationException(ntce.getMessage());
+ }
+
+ // added child item definitions
+ Set addedDefs = new HashSet(Arrays.asList(entNew.getAllItemDefs()));
+ addedDefs.removeAll(Arrays.asList(entOld.getAllItemDefs()));
+
+ // referential integrity check
+ boolean referenceableOld = getEffectiveNodeType().includesNodeType(NameConstants.MIX_REFERENCEABLE);
+ boolean referenceableNew = entAll.includesNodeType(NameConstants.MIX_REFERENCEABLE);
+ if (referenceableOld && !referenceableNew) {
+ // node would become non-referenceable;
+ // make sure no references exist
+ PropertyIterator iter = getReferences();
+ if (iter.hasNext()) {
+ throw new ConstraintViolationException(
+ "the new mixin types cannot be set as it would render "
+ + "this node 'non-referenceable' while it is still being "
+ + "referenced through at least one property of type REFERENCE");
+ }
+ }
+
+ // gather currently assigned definitions *before* doing actual modifications
+ Map oldDefs = new HashMap();
+ for (Name name : getNodeState().getPropertyNames()) {
+ PropertyId id = new PropertyId(getNodeId(), name);
+ try {
+ PropertyState propState = (PropertyState) stateMgr.getItemState(id);
+ oldDefs.put(id, itemMgr.getDefinition(propState));
+ } catch (ItemStateException ise) {
+ String msg = name + ": failed to retrieve property state";
+ log.error(msg, ise);
+ throw new RepositoryException(msg, ise);
+ }
+ }
+ for (ChildNodeEntry cne : getNodeState().getChildNodeEntries()) {
+ try {
+ NodeState nodeState = (NodeState) stateMgr.getItemState(cne.getId());
+ oldDefs.put(cne.getId(), itemMgr.getDefinition(nodeState));
+ } catch (ItemStateException ise) {
+ String msg = cne + ": failed to retrieve node state";
+ log.error(msg, ise);
+ throw new RepositoryException(msg, ise);
+ }
+ }
+
+ // now do the actual modifications in content as mandated by the new mixins
+
+ // modify the state of this node
+ NodeState thisState = (NodeState) getOrCreateTransientItemState();
+ thisState.setMixinTypeNames(newMixins);
+
+ // set jcr:mixinTypes property
+ setMixinTypesProperty(newMixins);
+
+ // walk through properties and child nodes and change definition as necessary
+
+ // use temp set to avoid ConcurrentModificationException
+ HashSet set = new HashSet(thisState.getPropertyNames());
+ for (Name propName : set) {
+ PropertyState propState = null;
+ try {
+ propState = (PropertyState) stateMgr.getItemState(
+ new PropertyId(thisState.getNodeId(), propName));
+ // the following call triggers ConstraintViolationException
+ // if there isn't any suitable definition anymore
+ itemMgr.getDefinition(propState);
+ } catch (ConstraintViolationException cve) {
+ // no suitable definition found for this property
+ // try to find new applicable definition first and
+ // redefine property if possible
+ try {
+ if (oldDefs.get(propState.getId()).isProtected()) {
+ // remove 'orphaned' protected properties immediately
+ removeChildProperty(propName);
+ continue;
+ }
+ PropertyDefinitionImpl pdi = getApplicablePropertyDefinition(
+ propName, propState.getType(),
+ propState.isMultiValued(), false);
+ PropertyImpl prop = (PropertyImpl) itemMgr.getItem(propState.getId());
+ if (pdi.getRequiredType() != PropertyType.UNDEFINED
+ && pdi.getRequiredType() != propState.getType()) {
+ // value conversion required
+ if (propState.isMultiValued()) {
+ // convert value
+ Value[] values =
+ ValueHelper.convert(
+ prop.getValues(),
+ pdi.getRequiredType(),
+ getSession().getValueFactory());
+ // redefine property
+ prop.onRedefine(pdi.unwrap());
+ // set converted values
+ prop.setValue(values);
+ } else {
+ // convert value
+ Value value =
+ ValueHelper.convert(
+ prop.getValue(),
+ pdi.getRequiredType(),
+ getSession().getValueFactory());
+ // redefine property
+ prop.onRedefine(pdi.unwrap());
+ // set converted values
+ prop.setValue(value);
+ }
+ } else {
+ // redefine property
+ prop.onRedefine(pdi.unwrap());
+ }
+ // update collection of added definitions
+ addedDefs.remove(pdi.unwrap());
+ } catch (ValueFormatException vfe) {
+ // value conversion failed, remove it
+ removeChildProperty(propName);
+ } catch (ConstraintViolationException cve1) {
+ // no suitable definition found for this property,
+ // remove it
+ removeChildProperty(propName);
+ }
+ } catch (ItemStateException ise) {
+ String msg = propName + ": failed to retrieve property state";
+ log.error(msg, ise);
+ throw new RepositoryException(msg, ise);
+ }
+ }
+
+ // use temp array to avoid ConcurrentModificationException
+ ArrayList list = new ArrayList(thisState.getChildNodeEntries());
+ // start from tail to avoid problems with same-name siblings
+ for (int i = list.size() - 1; i >= 0; i--) {
+ ChildNodeEntry entry = list.get(i);
+ NodeState nodeState = null;
+ try {
+ nodeState = (NodeState) stateMgr.getItemState(entry.getId());
+ // the following call triggers ConstraintViolationException
+ // if there isn't any suitable definition anymore
+ itemMgr.getDefinition(nodeState);
+ } catch (ConstraintViolationException cve) {
+ // no suitable definition found for this child node
+ // try to find new applicable definition first and
+ // redefine node if possible
+ try {
+ if (oldDefs.get(nodeState.getId()).isProtected()) {
+ // remove 'orphaned' protected child node immediately
+ removeChildNode(entry.getId());
+ continue;
+ }
+ NodeDefinitionImpl ndi = getApplicableChildNodeDefinition(
+ entry.getName(),
+ nodeState.getNodeTypeName());
+ NodeImpl node = (NodeImpl) itemMgr.getItem(nodeState.getId());
+ // redefine node
+ node.onRedefine(ndi.unwrap());
+ // update collection of added definitions
+ addedDefs.remove(ndi.unwrap());
+ } catch (ConstraintViolationException cve1) {
+ // no suitable definition found for this child node,
+ // remove it
+ removeChildNode(entry.getId());
+ }
+ } catch (ItemStateException ise) {
+ String msg = entry + ": failed to retrieve node state";
+ log.error(msg, ise);
+ throw new RepositoryException(msg, ise);
+ }
+ }
+
+ // create items that are defined as auto-created by the new mixins
+ // and at the same time were not present with the old mixins
+ for (QItemDefinition def : addedDefs) {
+ if (def.isAutoCreated()) {
+ if (def.definesNode()) {
+ NodeDefinitionImpl ndi = ntMgr.getNodeDefinition((QNodeDefinition) def);
+ createChildNode(def.getName(), (NodeTypeImpl) ndi.getDefaultPrimaryType(), null);
+ } else {
+ PropertyDefinitionImpl pdi = ntMgr.getPropertyDefinition((QPropertyDefinition) def);
+ createChildProperty(pdi.unwrap().getName(), pdi.getRequiredType(), pdi);
+ }
+ }
+ }
+ }
+
+ //--------------------------------------------------------------< Object >
+
+ /**
+ * Return a string representation of this node for diagnostic purposes.
+ *
+ * @return "node /path/to/item"
+ */
+ public String toString() {
+ return "node " + super.toString();
+ }
+
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeTypeInstanceHandler.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeTypeInstanceHandler.java
new file mode 100644
index 00000000000..c82125430f7
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/NodeTypeInstanceHandler.java
@@ -0,0 +1,143 @@
+/*
+ * 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.jackrabbit.core;
+
+import java.util.Calendar;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.PropertyState;
+import org.apache.jackrabbit.core.value.InternalValue;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.QPropertyDefinition;
+import org.apache.jackrabbit.spi.commons.name.NameConstants;
+
+/**
+ * The NodeTypeInstanceHandler is used to provide or initialize
+ * system protected properties (or child nodes).
+ *
+ */
+public class NodeTypeInstanceHandler {
+
+ /**
+ * Default user id in the case where the creating user cannot be determined.
+ */
+ public static final String DEFAULT_USERID = "system";
+
+ /**
+ * userid to use for the "*By" autocreated properties
+ */
+ private final String userId;
+
+ /**
+ * Creates a new node type instance handler.
+ * @param userId the user id. if null, {@value #DEFAULT_USERID} is used.
+ */
+ public NodeTypeInstanceHandler(String userId) {
+ this.userId = userId == null
+ ? DEFAULT_USERID
+ : userId;
+ }
+
+ /**
+ * Sets the system-generated or node type -specified default values
+ * of the given property. If such values are not specified, then the
+ * property is not modified.
+ *
+ * @param property property state
+ * @param parent parent node state
+ * @param def property definition
+ * @throws RepositoryException if the default values could not be created
+ */
+ public void setDefaultValues(
+ PropertyState property, NodeState parent, QPropertyDefinition def)
+ throws RepositoryException {
+ InternalValue[] values =
+ computeSystemGeneratedPropertyValues(parent, def);
+ if (values == null && def.getDefaultValues() != null) {
+ values = InternalValue.create(def.getDefaultValues());
+ }
+ if (values != null) {
+ property.setValues(values);
+ }
+ }
+
+ /**
+ * Computes the values of well-known system (i.e. protected) properties.
+ *
+ * @param parent the parent node state
+ * @param def the definition of the property to compute
+ * @return the computed values
+ */
+ public InternalValue[] computeSystemGeneratedPropertyValues(NodeState parent,
+ QPropertyDefinition def) {
+
+ InternalValue[] genValues = null;
+
+ Name name = def.getName();
+ Name declaringNT = def.getDeclaringNodeType();
+
+ if (NameConstants.JCR_UUID.equals(name)) {
+ // jcr:uuid property of the mix:referenceable node type
+ if (NameConstants.MIX_REFERENCEABLE.equals(declaringNT)) {
+ genValues = new InternalValue[]{InternalValue.create(parent.getNodeId().toString())};
+ }
+ } else if (NameConstants.JCR_PRIMARYTYPE.equals(name)) {
+ // jcr:primaryType property (of any node type)
+ genValues = new InternalValue[]{InternalValue.create(parent.getNodeTypeName())};
+ } else if (NameConstants.JCR_MIXINTYPES.equals(name)) {
+ // jcr:mixinTypes property (of any node type)
+ Set mixins = parent.getMixinTypeNames();
+ genValues = new InternalValue[mixins.size()];
+ int i = 0;
+ for (Name n : mixins) {
+ genValues[i++] = InternalValue.create(n);
+ }
+ } else if (NameConstants.JCR_CREATED.equals(name)) {
+ // jcr:created property of a version or a mix:created
+ if (NameConstants.MIX_CREATED.equals(declaringNT)
+ || NameConstants.NT_VERSION.equals(declaringNT)) {
+ genValues = new InternalValue[]{InternalValue.create(Calendar.getInstance())};
+ }
+ } else if (NameConstants.JCR_CREATEDBY.equals(name)) {
+ // jcr:createdBy property of a mix:created
+ if (NameConstants.MIX_CREATED.equals(declaringNT)) {
+ genValues = new InternalValue[]{InternalValue.create(userId)};
+ }
+ } else if (NameConstants.JCR_LASTMODIFIED.equals(name)) {
+ // jcr:lastModified property of a mix:lastModified
+ if (NameConstants.MIX_LASTMODIFIED.equals(declaringNT)) {
+ genValues = new InternalValue[]{InternalValue.create(Calendar.getInstance())};
+ }
+ } else if (NameConstants.JCR_LASTMODIFIEDBY.equals(name)) {
+ // jcr:lastModifiedBy property of a mix:lastModified
+ if (NameConstants.MIX_LASTMODIFIED.equals(declaringNT)) {
+ genValues = new InternalValue[]{InternalValue.create(userId)};
+ }
+ } else if (NameConstants.JCR_ETAG.equals(name)) {
+ // jcr:etag property of a mix:etag
+ if (NameConstants.MIX_ETAG.equals(declaringNT)) {
+ // TODO: provide real implementation
+ genValues = new InternalValue[]{InternalValue.create("")};
+ }
+ }
+ return genValues;
+ }
+
+}
\ No newline at end of file
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/PropertyData.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/PropertyData.java
new file mode 100644
index 00000000000..30e38c07f9e
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/PropertyData.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.jackrabbit.core;
+
+import javax.jcr.nodetype.PropertyDefinition;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.state.PropertyState;
+
+/**
+ * Data object representing a property.
+ */
+public class PropertyData extends ItemData {
+
+ /**
+ * Create a new instance of this class.
+ *
+ * @param state associated property state
+ * @param itemMgr item manager
+ */
+ PropertyData(PropertyState state, ItemManager itemMgr) {
+ super(state, itemMgr);
+ }
+
+ /**
+ * Return the associated property state.
+ *
+ * @return property state
+ */
+ public PropertyState getPropertyState() {
+ return (PropertyState) getState();
+ }
+
+ /**
+ * Return the associated property definition.
+ *
+ * @return property definition
+ * @throws RepositoryException if the definition cannot be retrieved.
+ */
+ public PropertyDefinition getPropertyDefinition() throws RepositoryException {
+ return (PropertyDefinition) getDefinition();
+ }
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/PropertyImpl.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/PropertyImpl.java
new file mode 100644
index 00000000000..e89f2453ce2
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/PropertyImpl.java
@@ -0,0 +1,926 @@
+/*
+ * 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.jackrabbit.core;
+
+import static javax.jcr.PropertyType.BINARY;
+import static javax.jcr.PropertyType.NAME;
+import static javax.jcr.PropertyType.PATH;
+import static javax.jcr.PropertyType.REFERENCE;
+import static javax.jcr.PropertyType.STRING;
+import static javax.jcr.PropertyType.UNDEFINED;
+import static javax.jcr.PropertyType.WEAKREFERENCE;
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_CHECKED_OUT;
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_CONSTRAINTS;
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_HOLD;
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_LOCK;
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_RETENTION;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Calendar;
+
+import javax.jcr.Binary;
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.ItemVisitor;
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Property;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+import javax.jcr.lock.LockException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.PropertyDefinition;
+import javax.jcr.version.VersionException;
+
+import org.apache.jackrabbit.core.id.PropertyId;
+import org.apache.jackrabbit.core.security.authorization.Permission;
+import org.apache.jackrabbit.core.session.SessionContext;
+import org.apache.jackrabbit.core.state.ItemState;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.PropertyState;
+import org.apache.jackrabbit.core.value.InternalValue;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.QPropertyDefinition;
+import org.apache.jackrabbit.spi.commons.value.ValueFormat;
+import org.apache.jackrabbit.spi.commons.nodetype.PropertyDefinitionImpl;
+import org.apache.jackrabbit.value.ValueHelper;
+import org.apache.commons.io.input.AutoCloseInputStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * PropertyImpl implements the Property interface.
+ */
+public class PropertyImpl extends ItemImpl implements Property {
+
+ private static Logger log = LoggerFactory.getLogger(PropertyImpl.class);
+
+ /** property data (avoids casting ItemImpl.data) */
+ private final PropertyData data;
+
+ /**
+ * Package private constructor.
+ *
+ * @param itemMgr the ItemManager that created this Property
+ * @param sessionContext the component context of the associated session
+ * @param data the property data
+ */
+ PropertyImpl(
+ ItemManager itemMgr, SessionContext sessionContext,
+ PropertyData data) {
+ super(itemMgr, sessionContext, data);
+ this.data = data;
+ // value will be read on demand
+ }
+
+ /**
+ * Checks that this property is valid (session not closed, property not
+ * removed, etc.) and returns the underlying property state if all is OK.
+ *
+ * @return property state
+ * @throws RepositoryException if the property is not valid
+ */
+ private PropertyState getPropertyState() throws RepositoryException {
+ // JCR-1272: Need to get the state reference now so it
+ // doesn't get invalidated after the sanity check
+ ItemState state = getItemState();
+ sanityCheck();
+ return (PropertyState) state;
+ }
+
+ @Override
+ protected synchronized ItemState getOrCreateTransientItemState()
+ throws RepositoryException {
+
+ synchronized (data) {
+ if (!isTransient()) {
+ // make transient (copy-on-write)
+ try {
+ PropertyState transientState =
+ stateMgr.createTransientPropertyState(
+ data.getPropertyState(), ItemState.STATUS_EXISTING_MODIFIED);
+ // swap persistent with transient state
+ data.setState(transientState);
+ } catch (ItemStateException ise) {
+ String msg = "failed to create transient state";
+ log.debug(msg);
+ throw new RepositoryException(msg, ise);
+ }
+ }
+ return getItemState();
+ }
+ }
+
+ @Override
+ protected void makePersistent() throws InvalidItemStateException {
+ if (!isTransient()) {
+ log.debug(this + " (" + id + "): there's no transient state to persist");
+ return;
+ }
+
+ PropertyState transientState = data.getPropertyState();
+ PropertyState persistentState = (PropertyState) transientState.getOverlayedState();
+ if (persistentState == null) {
+ // this property is 'new'
+ try {
+ persistentState = stateMgr.createNew(transientState);
+ } catch (ItemStateException e) {
+ throw new InvalidItemStateException(e);
+ }
+ }
+
+ synchronized (persistentState) {
+ // check staleness of transient state first
+ if (transientState.isStale()) {
+ String msg =
+ this + ": the property cannot be saved because it has"
+ + " been modified externally.";
+ log.debug(msg);
+ throw new InvalidItemStateException(msg);
+ }
+ // copy state from transient state
+ persistentState.setType(transientState.getType());
+ persistentState.setMultiValued(transientState.isMultiValued());
+ persistentState.setValues(transientState.getValues());
+ // make state persistent
+ stateMgr.store(persistentState);
+ }
+
+ // tell state manager to disconnect item state
+ stateMgr.disconnectTransientItemState(transientState);
+ // swap transient state with persistent state
+ data.setState(persistentState);
+ // reset status
+ data.setStatus(STATUS_NORMAL);
+ }
+
+ protected void restoreTransient(PropertyState transientState)
+ throws RepositoryException {
+ PropertyState thisState = null;
+
+ if (!isTransient()) {
+ thisState = (PropertyState) getOrCreateTransientItemState();
+ if (transientState.getStatus() == ItemState.STATUS_NEW
+ && thisState.getStatus() != ItemState.STATUS_NEW) {
+ thisState.setStatus(ItemState.STATUS_NEW);
+ stateMgr.disconnectTransientItemState(thisState);
+ }
+ } else {
+ // JCR-2503: Re-create transient state in the state manager,
+ // because it was removed
+ synchronized (data) {
+ try {
+ thisState = stateMgr.createTransientPropertyState(
+ transientState.getParentId(),
+ transientState.getName(),
+ PropertyState.STATUS_NEW);
+ data.setState(thisState);
+ } catch (ItemStateException e) {
+ throw new RepositoryException(e);
+ }
+ }
+ }
+
+ // reapply transient changes
+ thisState.setType(transientState.getType());
+ thisState.setMultiValued(transientState.isMultiValued());
+ thisState.setValues(transientState.getValues());
+ thisState.setModCount(transientState.getModCount());
+ }
+
+ protected void onRedefine(QPropertyDefinition def) throws RepositoryException {
+ PropertyDefinitionImpl newDef =
+ sessionContext.getNodeTypeManager().getPropertyDefinition(def);
+ data.setDefinition(newDef);
+ }
+
+ /**
+ * Determines the length of the given value.
+ *
+ * @param value value whose length should be determined
+ * @return the length of the given value
+ * @throws RepositoryException if an error occurs
+ * @see javax.jcr.Property#getLength()
+ * @see javax.jcr.Property#getLengths()
+ */
+ protected long getLength(InternalValue value) throws RepositoryException {
+ long length;
+ switch (value.getType()) {
+ case NAME:
+ case PATH:
+ String str = ValueFormat.getJCRString(value, sessionContext);
+ length = str.length();
+ break;
+ default:
+ length = value.getLength();
+ break;
+ }
+ return length;
+ }
+
+ /**
+ * Checks various pre-conditions that are common to all
+ * setValue() methods. The checks performed are:
+ *
+ *
parent node must be checked-out
+ *
property must not be protected
+ *
parent node must not be locked by somebody else
+ *
property must be multi-valued when set to an array of values
+ * (and vice versa)
+ *
+ *
+ * @param multipleValues flag indicating whether the property is about to
+ * be set to an array of values
+ * @throws ValueFormatException if a single-valued property is set to an
+ * array of values (and vice versa)
+ * @throws VersionException if the parent node is not checked-out
+ * @throws LockException if the parent node is locked by somebody else
+ * @throws ConstraintViolationException if the property is protected
+ * @throws RepositoryException if another error occurs
+ * @see javax.jcr.Property#setValue
+ */
+ protected void checkSetValue(boolean multipleValues)
+ throws ValueFormatException, VersionException,
+ LockException, ConstraintViolationException,
+ RepositoryException {
+ NodeImpl parent = (NodeImpl) getParent(false);
+ // check multi-value flag
+ if (multipleValues != isMultiple()) {
+ String msg = (multipleValues) ?
+ "Single-valued property can not be set to an array of values:" :
+ "Multivalued property can not be set to a single value (an array of length one is OK): ";
+ throw new ValueFormatException(msg + this);
+ }
+
+ // check protected flag and for retention/hold
+ sessionContext.getItemValidator().checkModify(
+ this, CHECK_CONSTRAINTS, Permission.NONE);
+
+ // make sure the parent is checked-out and neither locked nor under retention
+ sessionContext.getItemValidator().checkModify(
+ parent,
+ CHECK_CHECKED_OUT | CHECK_LOCK | CHECK_HOLD | CHECK_RETENTION,
+ Permission.NONE);
+ }
+
+ /**
+ * @param values
+ * @param type
+ * @throws ConstraintViolationException
+ * @throws RepositoryException
+ */
+ protected void internalSetValue(InternalValue[] values, int type)
+ throws ConstraintViolationException, RepositoryException {
+ // check for null value
+ if (values == null) {
+ // setting a property to null removes it automatically
+ ((NodeImpl) getParent()).removeChildProperty(((PropertyId) id).getName());
+ return;
+ }
+ ArrayList list = new ArrayList();
+ // compact array (purge null entries)
+ for (InternalValue v : values) {
+ if (v != null) {
+ list.add(v);
+ }
+ }
+ values = list.toArray(new InternalValue[list.size()]);
+
+ // modify the state of this property
+ PropertyState thisState = (PropertyState) getOrCreateTransientItemState();
+
+ // free old values as necessary
+ InternalValue[] oldValues = thisState.getValues();
+ if (oldValues != null) {
+ for (InternalValue old : oldValues) {
+ if (old != null && old.getType() == BINARY) {
+ // make sure temporarily allocated data is discarded
+ // before overwriting it
+ old.discard();
+ }
+ }
+ }
+
+ // set new values
+ thisState.setValues(values);
+ // set type
+ if (type == UNDEFINED) {
+ // fallback to default type
+ type = STRING;
+ }
+ thisState.setType(type);
+ }
+
+ protected Node getParent(boolean checkPermission) throws RepositoryException {
+ return (Node) itemMgr.getItem(getPropertyState().getParentId(), checkPermission);
+ }
+
+ /**
+ * Same as {@link Property#setValue(String)} except that
+ * this method takes a Name instead of a String
+ * value.
+ *
+ * @param name
+ * @throws ValueFormatException
+ * @throws VersionException
+ * @throws LockException
+ * @throws ConstraintViolationException
+ * @throws RepositoryException
+ */
+ public void setValue(Name name)
+ throws ValueFormatException, VersionException,
+ LockException, ConstraintViolationException,
+ RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ // check pre-conditions for setting property value
+ checkSetValue(false);
+
+ // check type according to definition of this property
+ final PropertyDefinition definition = data.getPropertyDefinition();
+ int reqType = definition.getRequiredType();
+ if (reqType == UNDEFINED) {
+ reqType = NAME;
+ }
+
+ if (name == null) {
+ internalSetValue(null, reqType);
+ return;
+ }
+
+ InternalValue internalValue;
+ if (reqType != NAME) {
+ // type conversion required
+ Value targetValue = ValueHelper.convert(
+ ValueFormat.getJCRValue(InternalValue.create(name), sessionContext, getSession().getValueFactory()),
+ reqType, getSession().getValueFactory());
+ internalValue = InternalValue.create(
+ targetValue, sessionContext, sessionContext.getDataStore());
+ } else {
+ // no type conversion required
+ internalValue = InternalValue.create(name);
+ }
+
+ internalSetValue(new InternalValue[]{internalValue}, reqType);
+ }
+
+ /**
+ * Same as {@link Property#setValue(String[])} except that
+ * this method takes an array of Name instead of
+ * String values.
+ *
+ * @param names
+ * @throws ValueFormatException
+ * @throws VersionException
+ * @throws LockException
+ * @throws ConstraintViolationException
+ * @throws RepositoryException
+ */
+ public void setValue(Name[] names)
+ throws ValueFormatException, VersionException,
+ LockException, ConstraintViolationException,
+ RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ // check pre-conditions for setting property value
+ checkSetValue(true);
+
+ // check type according to definition of this property
+ final PropertyDefinition definition = data.getPropertyDefinition();
+ int reqType = definition.getRequiredType();
+ if (reqType == UNDEFINED) {
+ reqType = NAME;
+ }
+
+ InternalValue[] internalValues = null;
+ // convert to internal values of correct type
+ if (names != null) {
+ internalValues = new InternalValue[names.length];
+ for (int i = 0; i < names.length; i++) {
+ Name name = names[i];
+ InternalValue internalValue = null;
+ if (name != null) {
+ if (reqType != NAME) {
+ // type conversion required
+ Value targetValue = ValueHelper.convert(
+ ValueFormat.getJCRValue(InternalValue.create(name), sessionContext, getSession().getValueFactory()),
+ reqType, getSession().getValueFactory());
+ internalValue = InternalValue.create(
+ targetValue, sessionContext,
+ sessionContext.getDataStore());
+ } else {
+ // no type conversion required
+ internalValue = InternalValue.create(name);
+ }
+ }
+ internalValues[i] = internalValue;
+ }
+ }
+
+ internalSetValue(internalValues, reqType);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Name getQName() {
+ return ((PropertyId) id).getName();
+ }
+
+ /**
+ * Returns the internal values of a multi-valued property.
+ *
+ * @return array of values
+ * @throws ValueFormatException if this property is not multi-valued
+ * @throws RepositoryException
+ */
+ public InternalValue[] internalGetValues() throws RepositoryException {
+ final PropertyDefinition definition = data.getPropertyDefinition();
+ if (isMultiple()) {
+ return getPropertyState().getValues();
+ } else {
+ throw new ValueFormatException(
+ this + " is a single-valued property,"
+ + " so it's value can not be retrieved as an array");
+ }
+
+ }
+
+ /**
+ * Returns the internal value of a single-valued property.
+ *
+ * @return value
+ * @throws ValueFormatException if this property is not single-valued
+ * @throws RepositoryException
+ */
+ public InternalValue internalGetValue() throws RepositoryException {
+ if (isMultiple()) {
+ throw new ValueFormatException(
+ this + " is a multi-valued property,"
+ + " so it's values can only be retrieved as an array");
+ } else {
+ InternalValue[] values = getPropertyState().getValues();
+ if (values.length > 0) {
+ return values[0];
+ } else {
+ // should never be the case, but being a little paranoid can't hurt...
+ throw new RepositoryException(this + ": single-valued property with no value");
+ }
+ }
+ }
+
+ //-------------------------------------------------------------< Property >
+
+ public Value[] getValues() throws RepositoryException {
+ InternalValue[] internals = internalGetValues();
+ Value[] values = new Value[internals.length];
+ for (int i = 0; i < internals.length; i++) {
+ values[i] = ValueFormat.getJCRValue(internals[i], sessionContext, getSession().getValueFactory());
+ }
+ return values;
+ }
+
+ public Value getValue() throws RepositoryException {
+ try {
+ return ValueFormat.getJCRValue(internalGetValue(), sessionContext, getSession().getValueFactory());
+ } catch (RuntimeException e) {
+ String msg = "Internal error while retrieving value of " + this;
+ log.error(msg, e);
+ throw new RepositoryException(msg, e);
+ }
+ }
+
+ /** Wrapper around {@link #getValue()} */
+ public String getString() throws RepositoryException {
+ return getValue().getString();
+ }
+
+ /** Wrapper around {@link #getValue()} */
+ public InputStream getStream() throws RepositoryException {
+ final Binary binary = getValue().getBinary();
+ // make sure binary is disposed after stream had been consumed
+ return new AutoCloseInputStream(binary.getStream()) {
+ @Override
+ public void close() throws IOException {
+ super.close();
+ binary.dispose();
+ }
+ };
+ }
+
+ /** Wrapper around {@link #getValue()} */
+ public long getLong() throws RepositoryException {
+ return getValue().getLong();
+ }
+
+ /** Wrapper around {@link #getValue()} */
+ public double getDouble() throws RepositoryException {
+ return getValue().getDouble();
+ }
+
+ /** Wrapper around {@link #getValue()} */
+ public Calendar getDate() throws RepositoryException {
+ return getValue().getDate();
+ }
+
+ /** Wrapper around {@link #getValue()} */
+ public boolean getBoolean() throws RepositoryException {
+ return getValue().getBoolean();
+ }
+
+ public Node getNode() throws ValueFormatException, RepositoryException {
+ Session session = getSession();
+ Value value = getValue();
+ int type = value.getType();
+ switch (type) {
+ case REFERENCE:
+ case WEAKREFERENCE:
+ return session.getNodeByUUID(value.getString());
+
+ case PATH:
+ case NAME:
+ String path = value.getString();
+ Path p = sessionContext.getQPath(path);
+ boolean absolute = p.isAbsolute();
+ try {
+ return (absolute) ? session.getNode(path) : getParent().getNode(path);
+ } catch (PathNotFoundException e) {
+ throw new ItemNotFoundException(path);
+ }
+
+ case STRING:
+ try {
+ Value refValue = ValueHelper.convert(value, REFERENCE, session.getValueFactory());
+ return session.getNodeByUUID(refValue.getString());
+ } catch (RepositoryException e) {
+ // try if STRING value can be interpreted as PATH value
+ Value pathValue = ValueHelper.convert(value, PATH, session.getValueFactory());
+ p = sessionContext.getQPath(pathValue.getString());
+ absolute = p.isAbsolute();
+ try {
+ return (absolute) ? session.getNode(pathValue.getString()) : getParent().getNode(pathValue.getString());
+ } catch (PathNotFoundException e1) {
+ throw new ItemNotFoundException(pathValue.getString());
+ }
+ }
+
+ default:
+ throw new ValueFormatException("Property value cannot be converted to a PATH, REFERENCE or WEAKREFERENCE");
+ }
+ }
+
+ public Property getProperty() throws RepositoryException {
+ Value value = getValue();
+ Value pathValue = ValueHelper.convert(value, PATH, getSession().getValueFactory());
+ String path = pathValue.getString();
+ boolean absolute;
+ try {
+ Path p = sessionContext.getQPath(path);
+ absolute = p.isAbsolute();
+ } catch (RepositoryException e) {
+ throw new ValueFormatException("Property value cannot be converted to a PATH");
+ }
+ try {
+ return (absolute) ? getSession().getProperty(path) : getParent().getProperty(path);
+ } catch (PathNotFoundException e) {
+ throw new ItemNotFoundException(path);
+ }
+ }
+
+ /** Wrapper around {@link #getValue()} */
+ public BigDecimal getDecimal() throws RepositoryException {
+ return getValue().getDecimal();
+ }
+
+ /** Wrapper around {@link #setValue(Value)} */
+ public void setValue(BigDecimal value) throws RepositoryException {
+ if (value != null) {
+ setValue(getValueFactory().createValue(value));
+ } else {
+ setValue((Value) null);
+ }
+ }
+
+ /** Wrapper around {@link #getValue()} */
+ public Binary getBinary() throws RepositoryException {
+ return getValue().getBinary();
+ }
+
+ /** Wrapper around {@link #setValue(Value)} */
+ public void setValue(Binary value) throws RepositoryException {
+ if (value != null) {
+ setValue(getValueFactory().createValue(value));
+ } else {
+ setValue((Value) null);
+ }
+ }
+
+ /** Wrapper around {@link #setValue(Value)} */
+ public void setValue(Calendar value) throws RepositoryException {
+ if (value != null) {
+ try {
+ setValue(getSession().getValueFactory().createValue(value));
+ } catch (IllegalArgumentException e) {
+ throw new ValueFormatException(
+ "Value is not an ISO8601 date: " + value, e);
+ }
+ } else {
+ setValue((Value) null);
+ }
+ }
+
+ /** Wrapper around {@link #setValue(Value)} */
+ public void setValue(double value) throws RepositoryException {
+ setValue(getValueFactory().createValue(value));
+ }
+
+ /** Wrapper around {@link #setValue(Value)} */
+ public void setValue(InputStream value) throws RepositoryException {
+ if (value != null) {
+ Binary binary = getValueFactory().createBinary(value);
+ try {
+ setValue(getValueFactory().createValue(binary));
+ } finally {
+ binary.dispose();
+ }
+ } else {
+ setValue((Value) null);
+ }
+ }
+
+ /** Wrapper around {@link #setValue(Value)} */
+ public void setValue(String value) throws RepositoryException {
+ if (value != null) {
+ setValue(getValueFactory().createValue(value));
+ } else {
+ setValue((Value) null);
+ }
+ }
+
+ /** Wrapper around {@link #setValue(Value[])} */
+ public void setValue(String[] strings) throws RepositoryException {
+ if (strings != null) {
+ setValue(getValues(strings, STRING));
+ } else {
+ setValue((Value[]) null);
+ }
+ }
+
+ /** Wrapper around {@link #setValue(Value)} */
+ public void setValue(boolean value) throws RepositoryException {
+ setValue(getValueFactory().createValue(value));
+ }
+
+ /** Wrapper around {@link #setValue(Value)} */
+ public void setValue(Node value) throws RepositoryException {
+ if (value != null) {
+ try {
+ setValue(getValueFactory().createValue(value));
+ } catch (UnsupportedRepositoryOperationException e) {
+ throw new ValueFormatException(
+ "Node is not referenceable: " + value, e);
+ }
+ } else {
+ setValue((Value) null);
+ }
+ }
+
+ /** Wrapper around {@link #setValue(Value)} */
+ public void setValue(long value) throws RepositoryException {
+ setValue(getValueFactory().createValue(value));
+ }
+
+ public synchronized void setValue(Value value)
+ throws ValueFormatException, VersionException,
+ LockException, ConstraintViolationException,
+ RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ // check pre-conditions for setting property value
+ checkSetValue(false);
+
+ // check type according to definition of this property
+ final PropertyDefinition definition = data.getPropertyDefinition();
+ int reqType = definition.getRequiredType();
+ if (reqType == UNDEFINED) {
+ if (value != null) {
+ reqType = value.getType();
+ } else {
+ reqType = STRING;
+ }
+ }
+
+ if (value == null) {
+ internalSetValue(null, reqType);
+ return;
+ }
+
+ InternalValue internalValue;
+ if (reqType != value.getType()) {
+ // type conversion required
+ Value targetVal = ValueHelper.convert(
+ value, reqType, getSession().getValueFactory());
+ internalValue = InternalValue.create(
+ targetVal, sessionContext, sessionContext.getDataStore());
+ } else {
+ // no type conversion required
+ internalValue = InternalValue.create(
+ value, sessionContext, sessionContext.getDataStore());
+ }
+ internalSetValue(new InternalValue[]{internalValue}, reqType);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setValue(Value[] values) throws RepositoryException {
+ setValue(values, UNDEFINED);
+ }
+
+ /**
+ * Sets the values of this property.
+ *
+ * @param values property values (possibly null)
+ * @param valueType default value type if not set in the node type,
+ * may be {@link PropertyType#UNDEFINED}
+ * @throws RepositoryException if the property values could not be set
+ */
+ public void setValue(Value[] values, int valueType)
+ throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ // check pre-conditions for setting property value
+ checkSetValue(true);
+
+ if (values != null) {
+ // check type of values
+ int firstValueType = UNDEFINED;
+ for (Value value : values) {
+ if (value != null) {
+ if (firstValueType == UNDEFINED) {
+ firstValueType = value.getType();
+ } else if (firstValueType != value.getType()) {
+ throw new ValueFormatException(
+ "inhomogeneous type of values");
+ }
+ }
+ }
+ }
+
+ final PropertyDefinition definition = data.getPropertyDefinition();
+ int reqType = definition.getRequiredType();
+ if (reqType == UNDEFINED) {
+ reqType = valueType; // use the given type as property type
+ }
+
+ InternalValue[] internalValues = null;
+ // convert to internal values of correct type
+ if (values != null) {
+ internalValues = new InternalValue[values.length];
+
+ // check type of values
+ for (int i = 0; i < values.length; i++) {
+ Value value = values[i];
+ if (value != null) {
+ if (reqType == UNDEFINED) {
+ // Use the type of the fist value as the type
+ reqType = value.getType();
+ }
+ if (reqType != value.getType()) {
+ value = ValueHelper.convert(
+ value, reqType, getSession().getValueFactory());
+ }
+ internalValues[i] = InternalValue.create(
+ value, sessionContext, sessionContext.getDataStore());
+ } else {
+ internalValues[i] = null;
+ }
+ }
+ }
+
+ internalSetValue(internalValues, reqType);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public long getLength() throws RepositoryException {
+ return getLength(internalGetValue());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public long[] getLengths() throws RepositoryException {
+ InternalValue[] values = internalGetValues();
+ long[] lengths = new long[values.length];
+ for (int i = 0; i < values.length; i++) {
+ lengths[i] = getLength(values[i]);
+ }
+ return lengths;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public PropertyDefinition getDefinition() throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ return data.getPropertyDefinition();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public int getType() throws RepositoryException {
+ return getPropertyState().getType();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isMultiple() throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ return getPropertyState().isMultiValued();
+ }
+
+ //-----------------------------------------------------------------< Item >
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isNode() {
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getName() throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+ return sessionContext.getJCRName(((PropertyId) id).getName());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void accept(ItemVisitor visitor) throws RepositoryException {
+ // check state of this instance
+ sanityCheck();
+
+ visitor.visit(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Node getParent() throws RepositoryException {
+ return getParent(true);
+ }
+
+ //--------------------------------------------------------------< Object >
+
+ /**
+ * Return a string representation of this property for diagnostic purposes.
+ *
+ * @return "property /path/to/item"
+ */
+ public String toString() {
+ return "property " + super.toString();
+ }
+
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ProtectedItemModifier.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ProtectedItemModifier.java
new file mode 100644
index 00000000000..2da032f71fd
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/ProtectedItemModifier.java
@@ -0,0 +1,193 @@
+/*
+ * 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.jackrabbit.core;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.ItemExistsException;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
+import org.apache.jackrabbit.core.retention.RetentionManagerImpl;
+import org.apache.jackrabbit.core.security.AccessManager;
+import org.apache.jackrabbit.core.security.authentication.token.TokenProvider;
+import org.apache.jackrabbit.core.security.authorization.Permission;
+import org.apache.jackrabbit.core.security.authorization.acl.ACLEditor;
+import org.apache.jackrabbit.core.security.user.UserManagerImpl;
+import org.apache.jackrabbit.core.session.SessionOperation;
+import org.apache.jackrabbit.core.state.ChildNodeEntry;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.value.InternalValue;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+
+/**
+ * ProtectedItemModifier: An abstract helper class to allow classes
+ * residing outside of the core package to modify and remove protected items.
+ * The protected item definitions are required in order not to have security
+ * relevant content being changed through common item operations but forcing
+ * the usage of the corresponding APIs, which assert that implementation
+ * specific constraints are not violated.
+ */
+public abstract class ProtectedItemModifier {
+
+ private static final int DEFAULT_PERM_CHECK = -1;
+ private final int permission;
+
+ protected ProtectedItemModifier() {
+ this(DEFAULT_PERM_CHECK);
+ }
+
+ protected ProtectedItemModifier(int permission) {
+ Class extends ProtectedItemModifier> cl = getClass();
+ if (!(UserManagerImpl.class.isAssignableFrom(cl) ||
+ RetentionManagerImpl.class.isAssignableFrom(cl) ||
+ ACLEditor.class.isAssignableFrom(cl) ||
+ TokenProvider.class.isAssignableFrom(cl) ||
+ org.apache.jackrabbit.core.security.authorization.principalbased.ACLEditor.class.isAssignableFrom(cl))) {
+ throw new IllegalArgumentException("Only UserManagerImpl, RetentionManagerImpl and ACLEditor may extend from the ProtectedItemModifier");
+ }
+ this.permission = permission;
+ }
+
+ protected NodeImpl addNode(NodeImpl parentImpl, Name name, Name ntName) throws RepositoryException {
+ return addNode(parentImpl, name, ntName, null);
+ }
+
+ protected NodeImpl addNode(NodeImpl parentImpl, Name name, Name ntName, NodeId nodeId) throws RepositoryException {
+ checkPermission(parentImpl, name, getPermission(true, false));
+ // validation: make sure Node is not locked or checked-in.
+ parentImpl.checkSetProperty();
+
+ NodeTypeImpl nodeType = parentImpl.sessionContext.getNodeTypeManager().getNodeType(ntName);
+ org.apache.jackrabbit.spi.commons.nodetype.NodeDefinitionImpl def = parentImpl.getApplicableChildNodeDefinition(name, ntName);
+
+ // check for name collisions
+ // TODO: improve. copied from NodeImpl
+ NodeState thisState = parentImpl.getNodeState();
+ ChildNodeEntry cne = thisState.getChildNodeEntry(name, 1);
+ if (cne != null) {
+ // there's already a child node entry with that name;
+ // check same-name sibling setting of new node
+ if (!def.allowsSameNameSiblings()) {
+ throw new ItemExistsException();
+ }
+ // check same-name sibling setting of existing node
+ NodeId newId = cne.getId();
+ NodeImpl n = (NodeImpl) parentImpl.sessionContext.getItemManager().getItem(newId);
+ if (!n.getDefinition().allowsSameNameSiblings()) {
+ throw new ItemExistsException();
+ }
+ }
+
+ return parentImpl.createChildNode(name, nodeType, nodeId);
+ }
+
+ protected Property setProperty(NodeImpl parentImpl, Name name, Value value) throws RepositoryException {
+ return setProperty(parentImpl, name, value, false);
+ }
+
+ protected Property setProperty(NodeImpl parentImpl, Name name, Value value, boolean ignorePermissions) throws RepositoryException {
+ if (!ignorePermissions) {
+ checkPermission(parentImpl, name, getPermission(false, false));
+ }
+ // validation: make sure Node is not locked or checked-in.
+ parentImpl.checkSetProperty();
+ InternalValue intVs = InternalValue.create(value, parentImpl.sessionContext);
+ return parentImpl.internalSetProperty(name, intVs);
+ }
+
+ protected Property setProperty(NodeImpl parentImpl, Name name, Value[] values) throws RepositoryException {
+ checkPermission(parentImpl, name, getPermission(false, false));
+ // validation: make sure Node is not locked or checked-in.
+ parentImpl.checkSetProperty();
+ InternalValue[] intVs = new InternalValue[values.length];
+ for (int i = 0; i < values.length; i++) {
+ intVs[i] = InternalValue.create(values[i], parentImpl.sessionContext);
+ }
+ return parentImpl.internalSetProperty(name, intVs);
+ }
+
+ protected Property setProperty(NodeImpl parentImpl, Name name, Value[] values, int type) throws RepositoryException {
+ checkPermission(parentImpl, name, getPermission(false, false));
+ // validation: make sure Node is not locked or checked-in.
+ parentImpl.checkSetProperty();
+ InternalValue[] intVs = new InternalValue[values.length];
+ for (int i = 0; i < values.length; i++) {
+ intVs[i] = InternalValue.create(values[i], parentImpl.sessionContext);
+ }
+ return parentImpl.internalSetProperty(name, intVs, type);
+ }
+
+ protected void removeItem(ItemImpl itemImpl) throws RepositoryException {
+ NodeImpl n;
+ if (itemImpl.isNode()) {
+ n = (NodeImpl) itemImpl;
+ } else {
+ n = (NodeImpl) itemImpl.getParent();
+ }
+ checkPermission(itemImpl, getPermission(itemImpl.isNode(), true));
+ // validation: make sure Node is not locked or checked-in.
+ n.checkSetProperty();
+ itemImpl.perform(new ItemRemoveOperation(itemImpl, false));
+ }
+
+ protected void markModified(NodeImpl parentImpl) throws RepositoryException {
+ parentImpl.getOrCreateTransientItemState();
+ }
+
+ protected T performProtected(SessionImpl session, SessionOperation operation) throws RepositoryException {
+ ItemValidator itemValidator = session.context.getItemValidator();
+ return itemValidator.performRelaxed(operation, ItemValidator.CHECK_CONSTRAINTS);
+ }
+
+ private void checkPermission(ItemImpl item, int perm) throws RepositoryException {
+ if (perm > Permission.NONE) {
+ SessionImpl sImpl = (SessionImpl) item.getSession();
+ AccessManager acMgr = sImpl.getAccessManager();
+
+ Path path = item.getPrimaryPath();
+ acMgr.checkPermission(path, perm);
+ }
+ }
+
+ private void checkPermission(NodeImpl node, Name childName, int perm) throws RepositoryException {
+ if (perm > Permission.NONE) {
+ SessionImpl sImpl = (SessionImpl) node.getSession();
+ AccessManager acMgr = sImpl.getAccessManager();
+
+ boolean isGranted = acMgr.isGranted(node.getPrimaryPath(), childName, perm);
+ if (!isGranted) {
+ throw new AccessDeniedException("Permission denied.");
+ }
+ }
+ }
+
+ private int getPermission(boolean isNode, boolean isRemove) {
+ if (permission < Permission.NONE) {
+ if (isNode) {
+ return (isRemove) ? Permission.REMOVE_NODE : Permission.ADD_NODE;
+ } else {
+ return (isRemove) ? Permission.REMOVE_PROPERTY : Permission.SET_PROPERTY;
+ }
+ } else {
+ return permission;
+ }
+ }
+}
\ No newline at end of file
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RemoveMixinOperation.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RemoveMixinOperation.java
new file mode 100644
index 00000000000..ea45517cecf
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RemoveMixinOperation.java
@@ -0,0 +1,305 @@
+/*
+ * 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.jackrabbit.core;
+
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_CHECKED_OUT;
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_CONSTRAINTS;
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_HOLD;
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_LOCK;
+import static org.apache.jackrabbit.spi.commons.name.NameConstants.MIX_REFERENCEABLE;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.PropertyDefinition;
+
+import org.apache.jackrabbit.core.id.PropertyId;
+import org.apache.jackrabbit.core.nodetype.EffectiveNodeType;
+import org.apache.jackrabbit.core.nodetype.NodeTypeConflictException;
+import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
+import org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl;
+import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.core.security.authorization.Permission;
+import org.apache.jackrabbit.core.session.SessionContext;
+import org.apache.jackrabbit.core.session.SessionWriteOperation;
+import org.apache.jackrabbit.core.state.ChildNodeEntry;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.PropertyState;
+import org.apache.jackrabbit.core.state.SessionItemStateManager;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.commons.name.NameConstants;
+import org.apache.jackrabbit.spi.commons.nodetype.NodeDefinitionImpl;
+import org.apache.jackrabbit.spi.commons.nodetype.PropertyDefinitionImpl;
+import org.apache.jackrabbit.value.ValueHelper;
+
+/**
+ * Session operation for removing a mixin type from a node.
+ */
+class RemoveMixinOperation implements SessionWriteOperation {
+
+ private final NodeImpl node;
+
+ private final Name mixinName;
+
+ public RemoveMixinOperation(NodeImpl node, Name mixinName) {
+ this.node = node;
+ this.mixinName = mixinName;
+ }
+
+ public Object perform(SessionContext context) throws RepositoryException {
+ SessionImpl session = context.getSessionImpl();
+ ItemManager itemMgr = context.getItemManager();
+ SessionItemStateManager stateMgr = context.getItemStateManager();
+
+ context.getItemValidator().checkModify(
+ node,
+ CHECK_LOCK | CHECK_CHECKED_OUT | CHECK_CONSTRAINTS | CHECK_HOLD,
+ Permission.NODE_TYPE_MNGMT);
+
+ // check if mixin is assigned
+ NodeState state = node.getNodeState();
+ if (!state.getMixinTypeNames().contains(mixinName)) {
+ throw new NoSuchNodeTypeException(
+ "Mixin " + context.getJCRName(mixinName)
+ + " not included in " + node);
+ }
+
+ NodeTypeManagerImpl ntMgr = context.getNodeTypeManager();
+ NodeTypeRegistry ntReg = context.getNodeTypeRegistry();
+
+ // build effective node type of remaining mixin's & primary type
+ Set remainingMixins = new HashSet(state.getMixinTypeNames());
+ // remove name of target mixin
+ remainingMixins.remove(mixinName);
+ EffectiveNodeType entResulting;
+ try {
+ // build effective node type representing primary type
+ // including remaining mixin's
+ entResulting = ntReg.getEffectiveNodeType(
+ state.getNodeTypeName(), remainingMixins);
+ } catch (NodeTypeConflictException e) {
+ throw new ConstraintViolationException(e.getMessage(), e);
+ }
+
+ // mix:referenceable needs special handling because it has
+ // special semantics:
+ // it can only be removed if there no more references to this node
+ NodeTypeImpl mixin = ntMgr.getNodeType(mixinName);
+ if (isReferenceable(mixin)
+ && !entResulting.includesNodeType(MIX_REFERENCEABLE)) {
+ if (node.getReferences().hasNext()) {
+ throw new ConstraintViolationException(
+ mixinName + " can not be removed:"
+ + " the node is being referenced through at least"
+ + " one property of type REFERENCE");
+ }
+ }
+
+ // mix:lockable: the mixin cannot be removed if the node is
+ // currently locked even if the editing session is the lock holder.
+ if ((NameConstants.MIX_LOCKABLE.equals(mixinName)
+ || mixin.isDerivedFrom(NameConstants.MIX_LOCKABLE))
+ && !entResulting.includesNodeType(NameConstants.MIX_LOCKABLE)
+ && node.isLocked()) {
+ throw new ConstraintViolationException(
+ mixinName + " can not be removed: the node is locked.");
+ }
+
+ NodeState thisState = (NodeState) node.getOrCreateTransientItemState();
+
+ // collect information about properties and nodes which require further
+ // action as a result of the mixin removal; we need to do this *before*
+ // actually changing the assigned mixin types, otherwise we wouldn't
+ // be able to retrieve the current definition of an item.
+ Map affectedProps =
+ new HashMap();
+ Map affectedNodes =
+ new HashMap();
+ try {
+ Set names = thisState.getPropertyNames();
+ for (Name propName : names) {
+ PropertyId propId =
+ new PropertyId(thisState.getNodeId(), propName);
+ PropertyState propState =
+ (PropertyState) stateMgr.getItemState(propId);
+ PropertyDefinition oldDef = itemMgr.getDefinition(propState);
+ // check if property has been defined by mixin type
+ // (or one of its supertypes)
+ NodeTypeImpl declaringNT =
+ (NodeTypeImpl) oldDef.getDeclaringNodeType();
+ if (!entResulting.includesNodeType(declaringNT.getQName())) {
+ // the resulting effective node type doesn't include the
+ // node type that declared this property
+ affectedProps.put(propId, oldDef);
+ }
+ }
+
+ List entries = thisState.getChildNodeEntries();
+ for (ChildNodeEntry entry : entries) {
+ NodeState nodeState =
+ (NodeState) stateMgr.getItemState(entry.getId());
+ NodeDefinition oldDef = itemMgr.getDefinition(nodeState);
+ // check if node has been defined by mixin type
+ // (or one of its supertypes)
+ NodeTypeImpl declaringNT =
+ (NodeTypeImpl) oldDef.getDeclaringNodeType();
+ if (!entResulting.includesNodeType(declaringNT.getQName())) {
+ // the resulting effective node type doesn't include the
+ // node type that declared this child node
+ affectedNodes.put(entry, oldDef);
+ }
+ }
+ } catch (ItemStateException e) {
+ throw new RepositoryException(
+ "Failed to determine effect of removing mixin "
+ + context.getJCRName(mixinName), e);
+ }
+
+ // modify the state of this node
+ thisState.setMixinTypeNames(remainingMixins);
+ // set jcr:mixinTypes property
+ node.setMixinTypesProperty(remainingMixins);
+
+ // process affected nodes & properties:
+ // 1. try to redefine item based on the resulting
+ // new effective node type (see JCR-2130)
+ // 2. remove item if 1. fails
+ boolean success = false;
+ try {
+ for (Map.Entry entry : affectedProps.entrySet()) {
+ PropertyId id = entry.getKey();
+ PropertyImpl prop = (PropertyImpl) itemMgr.getItem(id);
+ PropertyDefinition oldDef = entry.getValue();
+
+ if (oldDef.isProtected()) {
+ // remove 'orphaned' protected properties immediately
+ node.removeChildProperty(id.getName());
+ continue;
+ }
+ // try to find new applicable definition first and
+ // redefine property if possible (JCR-2130)
+ try {
+ PropertyDefinitionImpl newDef =
+ node.getApplicablePropertyDefinition(
+ id.getName(), prop.getType(),
+ oldDef.isMultiple(), false);
+ if (newDef.getRequiredType() != PropertyType.UNDEFINED
+ && newDef.getRequiredType() != prop.getType()) {
+ // value conversion required
+ if (oldDef.isMultiple()) {
+ // convert value
+ Value[] values =
+ ValueHelper.convert(
+ prop.getValues(),
+ newDef.getRequiredType(),
+ session.getValueFactory());
+ // redefine property
+ prop.onRedefine(newDef.unwrap());
+ // set converted values
+ prop.setValue(values);
+ } else {
+ // convert value
+ Value value =
+ ValueHelper.convert(
+ prop.getValue(),
+ newDef.getRequiredType(),
+ session.getValueFactory());
+ // redefine property
+ prop.onRedefine(newDef.unwrap());
+ // set converted values
+ prop.setValue(value);
+ }
+ } else {
+ // redefine property
+ prop.onRedefine(newDef.unwrap());
+ }
+ } catch (ValueFormatException vfe) {
+ // value conversion failed, remove it
+ node.removeChildProperty(id.getName());
+ } catch (ConstraintViolationException cve) {
+ // no suitable definition found for this property,
+ // remove it
+ node.removeChildProperty(id.getName());
+ }
+ }
+
+ for (ChildNodeEntry entry : affectedNodes.keySet()) {
+ NodeState nodeState = (NodeState) stateMgr.getItemState(entry.getId());
+ NodeImpl childNode = (NodeImpl) itemMgr.getItem(entry.getId());
+ NodeDefinition oldDef = affectedNodes.get(entry);
+
+ if (oldDef.isProtected()) {
+ // remove 'orphaned' protected child node immediately
+ node.removeChildNode(entry.getId());
+ continue;
+ }
+
+ // try to find new applicable definition first and
+ // redefine node if possible (JCR-2130)
+ try {
+ NodeDefinitionImpl newDef =
+ node.getApplicableChildNodeDefinition(
+ entry.getName(),
+ nodeState.getNodeTypeName());
+ // redefine node
+ childNode.onRedefine(newDef.unwrap());
+ } catch (ConstraintViolationException cve) {
+ // no suitable definition found for this child node,
+ // remove it
+ node.removeChildNode(entry.getId());
+ }
+ }
+ success = true;
+ } catch (ItemStateException e) {
+ throw new RepositoryException(
+ "Failed to clean up child items defined by removed mixin "
+ + context.getJCRName(mixinName), e);
+ } finally {
+ if (!success) {
+ // TODO JCR-1914: revert any changes made so far
+ }
+ }
+
+ return this;
+ }
+
+ private boolean isReferenceable(NodeTypeImpl mixin) {
+ return MIX_REFERENCEABLE.equals(mixinName)
+ || mixin.isDerivedFrom(MIX_REFERENCEABLE);
+ }
+
+ //--------------------------------------------------------------< Object >
+
+ /**
+ * Returns a string representation of this operation.
+ */
+ public String toString() {
+ return "node.removeMixin(" + mixinName + ")";
+ }
+
+}
\ No newline at end of file
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryChecker.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryChecker.java
new file mode 100644
index 00000000000..eff796440f4
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryChecker.java
@@ -0,0 +1,335 @@
+/*
+ * 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.jackrabbit.core;
+
+import static org.apache.jackrabbit.core.RepositoryImpl.SYSTEM_ROOT_NODE_ID;
+import static org.apache.jackrabbit.spi.commons.name.NameConstants.JCR_BASEVERSION;
+import static org.apache.jackrabbit.spi.commons.name.NameConstants.JCR_ISCHECKEDOUT;
+import static org.apache.jackrabbit.spi.commons.name.NameConstants.JCR_PREDECESSORS;
+import static org.apache.jackrabbit.spi.commons.name.NameConstants.JCR_ROOTVERSION;
+import static org.apache.jackrabbit.spi.commons.name.NameConstants.JCR_VERSIONHISTORY;
+import static org.apache.jackrabbit.spi.commons.name.NameConstants.MIX_VERSIONABLE;
+import static org.apache.jackrabbit.spi.commons.name.NameConstants.MIX_REFERENCEABLE;
+
+import java.util.Calendar;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.id.PropertyId;
+import org.apache.jackrabbit.core.persistence.PersistenceManager;
+import org.apache.jackrabbit.core.state.ChangeLog;
+import org.apache.jackrabbit.core.state.ChildNodeEntry;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.version.InconsistentVersioningState;
+import org.apache.jackrabbit.core.version.InternalVersion;
+import org.apache.jackrabbit.core.version.InternalVersionHistory;
+import org.apache.jackrabbit.core.version.InternalVersionManagerImpl;
+import org.apache.jackrabbit.core.version.VersionHistoryInfo;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.NameFactory;
+import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
+import org.apache.jackrabbit.util.ISO8601;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Tool for checking for and optionally fixing consistency issues in a
+ * repository. Currently this class only contains a simple versioning
+ * recovery feature for
+ * JCR-2551.
+ */
+class RepositoryChecker {
+
+ /**
+ * Logger instance.
+ */
+ private static final Logger log =
+ LoggerFactory.getLogger(RepositoryChecker.class);
+
+ private final PersistenceManager workspace;
+
+ private final ChangeLog workspaceChanges;
+
+ private final ChangeLog vworkspaceChanges;
+
+ private final InternalVersionManagerImpl versionManager;
+
+ // maximum size of changelog when running in "fixImmediately" mode
+ private final static long CHUNKSIZE = 256;
+
+ // number of nodes affected by pending changes
+ private long dirtyNodes = 0;
+
+ // total nodes checked, with problems
+ private long totalNodes = 0;
+ private long brokenNodes = 0;
+
+ // start time
+ private long startTime;
+
+ public RepositoryChecker(PersistenceManager workspace,
+ InternalVersionManagerImpl versionManager) {
+ this.workspace = workspace;
+ this.workspaceChanges = new ChangeLog();
+ this.vworkspaceChanges = new ChangeLog();
+ this.versionManager = versionManager;
+ }
+
+ public void check(NodeId id, boolean recurse, boolean fixImmediately)
+ throws RepositoryException {
+
+ log.info("Starting RepositoryChecker");
+
+ startTime = System.currentTimeMillis();
+
+ internalCheck(id, recurse, fixImmediately);
+
+ if (fixImmediately) {
+ internalFix(true);
+ }
+
+ log.info("RepositoryChecker finished; checked " + totalNodes
+ + " nodes in " + (System.currentTimeMillis() - startTime)
+ + "ms, problems found: " + brokenNodes);
+ }
+
+ private void internalCheck(NodeId id, boolean recurse,
+ boolean fixImmediately) throws RepositoryException {
+ try {
+ log.debug("Checking consistency of node {}", id);
+ totalNodes += 1;
+
+ NodeState state = workspace.load(id);
+ checkVersionHistory(state);
+
+ if (fixImmediately && dirtyNodes > CHUNKSIZE) {
+ internalFix(false);
+ }
+
+ if (recurse) {
+ for (ChildNodeEntry child : state.getChildNodeEntries()) {
+ if (!SYSTEM_ROOT_NODE_ID.equals(child.getId())) {
+ internalCheck(child.getId(), recurse, fixImmediately);
+ }
+ }
+ }
+ } catch (ItemStateException e) {
+ throw new RepositoryException("Unable to access node " + id, e);
+ }
+ }
+
+ private void fix(PersistenceManager pm, ChangeLog changes, String store,
+ boolean verbose) throws RepositoryException {
+ if (changes.hasUpdates()) {
+ if (log.isWarnEnabled()) {
+ log.warn("Fixing " + store + " inconsistencies: "
+ + changes.toString());
+ }
+ try {
+ pm.store(changes);
+ changes.reset();
+ } catch (ItemStateException e) {
+ String message = "Failed to fix " + store
+ + " inconsistencies (aborting)";
+ log.error(message, e);
+ throw new RepositoryException(message, e);
+ }
+ } else {
+ if (verbose) {
+ log.info("No " + store + " inconsistencies found");
+ }
+ }
+ }
+
+ public void fix() throws RepositoryException {
+ internalFix(true);
+ }
+
+ private void internalFix(boolean verbose) throws RepositoryException {
+ fix(workspace, workspaceChanges, "workspace", verbose);
+ fix(versionManager.getPersistenceManager(), vworkspaceChanges,
+ "versioning workspace", verbose);
+ dirtyNodes = 0;
+ }
+
+ private void checkVersionHistory(NodeState node) {
+
+ String message = null;
+ NodeId nid = node.getNodeId();
+ boolean isVersioned = node.hasPropertyName(JCR_VERSIONHISTORY);
+
+ NodeId vhid = null;
+
+ try {
+ String type = isVersioned ? "in-use" : "candidate";
+
+ log.debug("Checking " + type + " version history of node {}", nid);
+
+ String intro = "Removing references to an inconsistent " + type
+ + " version history of node " + nid;
+
+ message = intro + " (getting the VersionInfo)";
+ VersionHistoryInfo vhi = versionManager.getVersionHistoryInfoForNode(node);
+ if (vhi != null) {
+ // get the version history's node ID as early as possible
+ // so we can attempt a fixup even when the next call fails
+ vhid = vhi.getVersionHistoryId();
+ }
+
+ message = intro + " (getting the InternalVersionHistory)";
+
+ InternalVersionHistory vh = null;
+
+ try {
+ vh = versionManager.getVersionHistoryOfNode(nid);
+ }
+ catch (ItemNotFoundException ex) {
+ // it's ok if we get here if the node didn't claim to be versioned
+ if (isVersioned) {
+ throw ex;
+ }
+ }
+
+ if (vh == null) {
+ if (isVersioned) {
+ message = intro + "getVersionHistoryOfNode returned null";
+ throw new InconsistentVersioningState(message);
+ }
+ } else {
+ vhid = vh.getId();
+
+ // additional checks, see JCR-3101
+
+ message = intro + " (getting the version names failed)";
+ Name[] versionNames = vh.getVersionNames();
+ boolean seenRoot = false;
+
+ for (Name versionName : versionNames) {
+ seenRoot |= JCR_ROOTVERSION.equals(versionName);
+
+ log.debug("Checking version history of node {}, version {}", nid, versionName);
+
+ message = intro + " (getting version " + versionName + " failed)";
+ InternalVersion v = vh.getVersion(versionName);
+
+ message = intro + "(frozen node of root version " + v.getId() + " missing)";
+ if (null == v.getFrozenNode()) {
+ throw new InconsistentVersioningState(message);
+ }
+ }
+
+ if (!seenRoot) {
+ message = intro + " (root version is missing)";
+ throw new InconsistentVersioningState(message);
+ }
+ }
+ } catch (InconsistentVersioningState e) {
+ log.info(message, e);
+ NodeId nvhid = e.getVersionHistoryNodeId();
+ if (nvhid != null) {
+ if (vhid != null && !nvhid.equals(vhid)) {
+ log.error("vhrid returned with InconsistentVersioningState does not match the id we already had: "
+ + vhid + " vs " + nvhid);
+ }
+ vhid = nvhid;
+ }
+ removeVersionHistoryReferences(node, vhid);
+ } catch (Exception e) {
+ log.info(message, e);
+ removeVersionHistoryReferences(node, vhid);
+ }
+ }
+
+ // un-versions the node, and potentially moves the version history away
+ private void removeVersionHistoryReferences(NodeState node, NodeId vhid) {
+
+ dirtyNodes += 1;
+ brokenNodes += 1;
+
+ NodeState modified =
+ new NodeState(node, NodeState.STATUS_EXISTING_MODIFIED, true);
+
+ Set mixins = new HashSet(node.getMixinTypeNames());
+ if (mixins.remove(MIX_VERSIONABLE)) {
+ // we are keeping jcr:uuid, so we need to make sure the type info stays valid
+ mixins.add(MIX_REFERENCEABLE);
+ modified.setMixinTypeNames(mixins);
+ }
+
+ removeProperty(modified, JCR_VERSIONHISTORY);
+ removeProperty(modified, JCR_BASEVERSION);
+ removeProperty(modified, JCR_PREDECESSORS);
+ removeProperty(modified, JCR_ISCHECKEDOUT);
+
+ workspaceChanges.modified(modified);
+
+ if (vhid != null) {
+ // attempt to rename the version history, so it doesn't interfere with
+ // a future attempt to put the node under version control again
+ // (see JCR-3115)
+
+ log.info("trying to rename version history of node " + node.getId());
+
+ NameFactory nf = NameFactoryImpl.getInstance();
+
+ // Name of VHR in parent folder is ID of versionable node
+ Name vhrname = nf.create(Name.NS_DEFAULT_URI, node.getId().toString());
+
+ try {
+ NodeState vhrState = versionManager.getPersistenceManager().load(vhid);
+ NodeState vhrParentState = versionManager.getPersistenceManager().load(vhrState.getParentId());
+
+ if (vhrParentState.hasChildNodeEntry(vhrname)) {
+ NodeState modifiedParent = (NodeState) vworkspaceChanges.get(vhrState.getParentId());
+ if (modifiedParent == null) {
+ modifiedParent = new NodeState(vhrParentState, NodeState.STATUS_EXISTING_MODIFIED, true);
+ }
+
+ Calendar now = Calendar.getInstance();
+ String appendme = " (disconnected by RepositoryChecker on "
+ + ISO8601.format(now) + ")";
+ modifiedParent.renameChildNodeEntry(vhid,
+ nf.create(vhrname.getNamespaceURI(), vhrname.getLocalName() + appendme));
+
+ vworkspaceChanges.modified(modifiedParent);
+ }
+ else {
+ log.info("child node entry " + vhrname + " for version history not found inside parent folder.");
+ }
+ } catch (Exception ex) {
+ log.error("while trying to rename the version history", ex);
+ }
+ }
+ }
+
+ private void removeProperty(NodeState node, Name name) {
+ if (node.hasPropertyName(name)) {
+ node.removePropertyName(name);
+ try {
+ workspaceChanges.deleted(workspace.load(
+ new PropertyId(node.getNodeId(), name)));
+ } catch (ItemStateException ignoe) {
+ }
+ }
+ }
+
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryContext.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryContext.java
new file mode 100644
index 00000000000..e98cc8d9868
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryContext.java
@@ -0,0 +1,477 @@
+/*
+ * 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.jackrabbit.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.ScheduledExecutorService;
+
+import javax.jcr.NoSuchWorkspaceException;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.core.RepositoryImpl.WorkspaceInfo;
+import org.apache.jackrabbit.core.cluster.ClusterNode;
+import org.apache.jackrabbit.core.config.RepositoryConfig;
+import org.apache.jackrabbit.core.data.DataStore;
+import org.apache.jackrabbit.core.fs.FileSystem;
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.id.NodeIdFactory;
+import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.core.security.JackrabbitSecurityManager;
+import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
+import org.apache.jackrabbit.core.state.ItemStateCacheFactory;
+import org.apache.jackrabbit.stats.RepositoryStatisticsImpl;
+import org.apache.jackrabbit.core.stats.StatManager;
+import org.apache.jackrabbit.core.version.InternalVersionManagerImpl;
+
+/**
+ * Internal component context of a Jackrabbit content repository.
+ * A repository context consists of the internal repository-level
+ * components and resources like the namespace and node type
+ * registries. Access to these resources is available only to objects
+ * with a reference to the context object.
+ */
+public class RepositoryContext {
+
+ /**
+ * The repository instance to which this context is associated.
+ */
+ private final RepositoryImpl repository;
+
+ /**
+ * The namespace registry of this repository.
+ */
+ private NamespaceRegistryImpl namespaceRegistry;
+
+ /**
+ * The node type registry of this repository.
+ */
+ private NodeTypeRegistry nodeTypeRegistry;
+
+ /**
+ * The privilege registry for this repository.
+ */
+ private PrivilegeRegistry privilegeRegistry;
+
+ /**
+ * The internal version manager of this repository.
+ */
+ private InternalVersionManagerImpl internalVersionManager;
+
+ /**
+ * The root node identifier of this repository.
+ */
+ private NodeId rootNodeId;
+
+ /**
+ * The repository file system.
+ */
+ private FileSystem fileSystem;
+
+ /**
+ * The data store of this repository, or null.
+ */
+ private DataStore dataStore;
+
+ /**
+ * The cluster node instance of this repository, or null.
+ */
+ private ClusterNode clusterNode;
+
+ /**
+ * Workspace manager of this repository.
+ */
+ private WorkspaceManager workspaceManager;
+
+ /**
+ * Security manager of this repository;
+ */
+ private JackrabbitSecurityManager securityManager;
+
+ /**
+ * Item state cache factory of this repository.
+ */
+ private ItemStateCacheFactory itemStateCacheFactory;
+
+ private NodeIdFactory nodeIdFactory;
+
+ /**
+ * Thread pool of this repository.
+ */
+ private final ScheduledExecutorService executor =
+ new JackrabbitThreadPool();
+
+ /**
+ * Repository statistics collector.
+ */
+ private final RepositoryStatisticsImpl statistics;
+
+ /**
+ * The Statistics manager, handles statistics
+ */
+ private StatManager statManager;
+
+ /**
+ * flag to indicate if GC is running
+ */
+
+ private boolean gcRunning;
+
+ /**
+ * Creates a component context for the given repository.
+ *
+ * @param repository repository instance
+ */
+ RepositoryContext(RepositoryImpl repository) {
+ assert repository != null;
+ this.repository = repository;
+ this.statistics = new RepositoryStatisticsImpl(executor);
+ this.statManager = new StatManager();
+ }
+
+ /**
+ * Starts a repository with the given configuration and returns
+ * the internal component context of the started repository.
+ *
+ * @since Apache Jackrabbit 2.3.1
+ * @param config repository configuration
+ * @return component context of the repository
+ * @throws RepositoryException if the repository could not be started
+ */
+ public static RepositoryContext create(RepositoryConfig config)
+ throws RepositoryException {
+ RepositoryImpl repository = RepositoryImpl.create(config);
+ return repository.getRepositoryContext();
+ }
+
+ /**
+ * Starts a repository in the given directory and returns the
+ * internal component context of the started repository. If needed,
+ * the directory is created and a default repository configuration
+ * is installed inside it.
+ *
+ * @since Apache Jackrabbit 2.3.1
+ * @see RepositoryConfig#install(File)
+ * @param dir repository directory
+ * @return component context of the repository
+ * @throws RepositoryException if the repository could not be started
+ * @throws IOException if the directory could not be initialized
+ */
+ public static RepositoryContext install(File dir)
+ throws RepositoryException, IOException {
+ return create(RepositoryConfig.install(dir));
+ }
+
+ public RepositoryConfig getRepositoryConfig() {
+ return repository.getConfig();
+ }
+
+ /**
+ * Returns the repository instance to which this context is associated.
+ *
+ * @return repository instance
+ */
+ public RepositoryImpl getRepository() {
+ return repository;
+ }
+
+ /**
+ * Returns the thread pool of this repository.
+ *
+ * @return repository thread pool
+ */
+ public ScheduledExecutorService getExecutor() {
+ return executor;
+ }
+
+ /**
+ * Returns the namespace registry of this repository.
+ *
+ * @return namespace registry
+ */
+ public NamespaceRegistryImpl getNamespaceRegistry() {
+ assert namespaceRegistry != null;
+ return namespaceRegistry;
+ }
+
+ /**
+ * Sets the namespace registry of this repository.
+ *
+ * @param namespaceRegistry namespace registry
+ */
+ void setNamespaceRegistry(NamespaceRegistryImpl namespaceRegistry) {
+ assert namespaceRegistry != null;
+ this.namespaceRegistry = namespaceRegistry;
+ }
+
+ /**
+ * Returns the namespace registry of this repository.
+ *
+ * @return node type registry
+ */
+ public NodeTypeRegistry getNodeTypeRegistry() {
+ assert nodeTypeRegistry != null;
+ return nodeTypeRegistry;
+ }
+
+ /**
+ * Sets the node type registry of this repository.
+ *
+ * @param nodeTypeRegistry node type registry
+ */
+ void setNodeTypeRegistry(NodeTypeRegistry nodeTypeRegistry) {
+ assert nodeTypeRegistry != null;
+ this.nodeTypeRegistry = nodeTypeRegistry;
+ }
+
+ /**
+ * Returns the privilege registry of this repository.
+ *
+ * @return the privilege registry of this repository.
+ */
+ public PrivilegeRegistry getPrivilegeRegistry() {
+ return privilegeRegistry;
+ }
+
+ /**
+ * Sets the privilege registry of this repository.
+ *
+ * @param privilegeRegistry
+ */
+ void setPrivilegeRegistry(PrivilegeRegistry privilegeRegistry) {
+ assert privilegeRegistry != null;
+ this.privilegeRegistry = privilegeRegistry;
+ }
+
+ /**
+ * Returns the internal version manager of this repository.
+ *
+ * @return internal version manager
+ */
+ public InternalVersionManagerImpl getInternalVersionManager() {
+ return internalVersionManager;
+ }
+
+ /**
+ * Sets the internal version manager of this repository.
+ *
+ * @param internalVersionManager internal version manager
+ */
+ void setInternalVersionManager(
+ InternalVersionManagerImpl internalVersionManager) {
+ assert internalVersionManager != null;
+ this.internalVersionManager = internalVersionManager;
+ }
+
+ /**
+ * Returns the root node identifier of this repository.
+ *
+ * @return root node identifier
+ */
+ public NodeId getRootNodeId() {
+ assert rootNodeId != null;
+ return rootNodeId;
+ }
+
+ /**
+ * Sets the root node identifier of this repository.
+ *
+ * @param rootNodeId root node identifier
+ */
+ void setRootNodeId(NodeId rootNodeId) {
+ assert rootNodeId != null;
+ this.rootNodeId = rootNodeId;
+ }
+
+ /**
+ * Returns the repository file system.
+ *
+ * @return repository file system
+ */
+ public FileSystem getFileSystem() {
+ assert fileSystem != null;
+ return fileSystem;
+ }
+
+ /**
+ * Sets the repository file system.
+ *
+ * @param fileSystem repository file system
+ */
+ void setFileSystem(FileSystem fileSystem) {
+ assert fileSystem != null;
+ this.fileSystem = fileSystem;
+ }
+
+ /**
+ * Returns the data store of this repository, or null
+ * if a data store is not configured.
+ *
+ * @return data store, or null
+ */
+ public DataStore getDataStore() {
+ return dataStore;
+ }
+
+ /**
+ * Sets the data store of this repository.
+ *
+ * @param dataStore data store
+ */
+ void setDataStore(DataStore dataStore) {
+ assert dataStore != null;
+ this.dataStore = dataStore;
+ }
+
+ /**
+ * Returns the cluster node instance of this repository, or
+ * null if clustering is not enabled.
+ *
+ * @return cluster node
+ */
+ public ClusterNode getClusterNode() {
+ return clusterNode;
+ }
+
+ /**
+ * Sets the cluster node instance of this repository.
+ *
+ * @param clusterNode cluster node
+ */
+ void setClusterNode(ClusterNode clusterNode) {
+ assert clusterNode != null;
+ this.clusterNode = clusterNode;
+ }
+
+ /**
+ * Returns the workspace manager of this repository.
+ *
+ * @return workspace manager
+ */
+ public WorkspaceManager getWorkspaceManager() {
+ assert workspaceManager != null;
+ return workspaceManager;
+ }
+
+ /**
+ * Sets the workspace manager of this repository.
+ *
+ * @param workspaceManager workspace manager
+ */
+ void setWorkspaceManager(WorkspaceManager workspaceManager) {
+ assert workspaceManager != null;
+ this.workspaceManager = workspaceManager;
+ }
+
+ /**
+ * Returns the {@link WorkspaceInfo} for the named workspace.
+ *
+ * @param workspaceName The name of the workspace whose {@link WorkspaceInfo}
+ * is to be returned. This must not be null.
+ * @return The {@link WorkspaceInfo} for the named workspace. This will
+ * never be null.
+ * @throws NoSuchWorkspaceException If the named workspace does not exist.
+ * @throws RepositoryException If this repository has been shut down.
+ */
+ public WorkspaceInfo getWorkspaceInfo(String workspaceName)
+ throws NoSuchWorkspaceException, RepositoryException {
+ return repository.getWorkspaceInfo(workspaceName);
+ }
+
+ /**
+ * Returns the security manager of this repository.
+ *
+ * @return security manager
+ */
+ public JackrabbitSecurityManager getSecurityManager() {
+ assert securityManager != null;
+ return securityManager;
+ }
+
+ /**
+ * Sets the security manager of this repository.
+ *
+ * @param securityManager security manager
+ */
+ void setSecurityManager(JackrabbitSecurityManager securityManager) {
+ assert securityManager != null;
+ this.securityManager = securityManager;
+ }
+
+ /**
+ * Returns the item state cache factory of this repository.
+ *
+ * @return item state cache factory
+ */
+ public ItemStateCacheFactory getItemStateCacheFactory() {
+ assert itemStateCacheFactory != null;
+ return itemStateCacheFactory;
+ }
+
+ /**
+ * Sets the item state cache factory of this repository.
+ *
+ * @param itemStateCacheFactory item state cache factory
+ */
+ void setItemStateCacheFactory(ItemStateCacheFactory itemStateCacheFactory) {
+ assert itemStateCacheFactory != null;
+ this.itemStateCacheFactory = itemStateCacheFactory;
+ }
+
+ public void setNodeIdFactory(NodeIdFactory nodeIdFactory) {
+ this.nodeIdFactory = nodeIdFactory;
+ }
+
+ public NodeIdFactory getNodeIdFactory() {
+ return nodeIdFactory;
+ }
+
+ /**
+ * Returns the repository statistics collector.
+ *
+ * @return repository statistics collector
+ */
+ public RepositoryStatisticsImpl getRepositoryStatistics() {
+ return statistics;
+ }
+
+ /**
+ * @return the statistics manager object
+ */
+ public StatManager getStatManager() {
+ return statManager;
+ }
+
+ /**
+ *
+ * @return gcRunning status
+ */
+ public boolean isGcRunning() {
+ return gcRunning;
+ }
+
+ /**
+ * set gcRunnign status
+ * @param gcRunning
+ */
+ public synchronized void setGcRunning(boolean gcRunning) {
+ this.gcRunning = gcRunning;
+ }
+
+
+
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryCopier.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryCopier.java
new file mode 100644
index 00000000000..21baf74456f
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryCopier.java
@@ -0,0 +1,288 @@
+/*
+ * 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.jackrabbit.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+
+import javax.jcr.NamespaceRegistry;
+import javax.jcr.RepositoryException;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.jackrabbit.core.config.RepositoryConfig;
+import org.apache.jackrabbit.core.lock.LockManagerImpl;
+import org.apache.jackrabbit.core.nodetype.InvalidNodeTypeDefException;
+import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.core.persistence.PersistenceCopier;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.QNodeTypeDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Tool for backing up or migrating the entire contents (workspaces,
+ * version histories, namespaces, node types, etc.) of a repository to
+ * a new repository. The target repository (if it exists) is overwritten.
+ *
+ * No cluster journal records are written in the target repository. If the
+ * target repository is clustered, it should be the only node in the cluster.
+ *
+ * The target repository needs to be fully reindexed after the copy operation.
+ * The static copy() methods will remove the target search index folders from
+ * their default locations to trigger automatic reindexing when the repository
+ * is next started.
+ *
+ * @since Apache Jackrabbit 1.6
+ */
+public class RepositoryCopier {
+
+ /**
+ * Logger instance
+ */
+ private static final Logger logger =
+ LoggerFactory.getLogger(RepositoryCopier.class);
+
+ /**
+ * Source repository context.
+ */
+ private final RepositoryContext source;
+
+ /**
+ * Target repository context.
+ */
+ private final RepositoryContext target;
+
+ /**
+ * Copies the contents of the repository in the given source directory
+ * to a repository in the given target directory.
+ *
+ * @param source source repository directory
+ * @param target target repository directory
+ * @throws RepositoryException if the copy operation fails
+ * @throws IOException if the target repository can not be initialized
+ */
+ public static void copy(File source, File target)
+ throws RepositoryException, IOException {
+ copy(RepositoryConfig.create(source), RepositoryConfig.install(target));
+ }
+
+ /**
+ * Copies the contents of the repository with the given configuration
+ * to a repository in the given target directory.
+ *
+ * @param source source repository configuration
+ * @param target target repository directory
+ * @throws RepositoryException if the copy operation fails
+ * @throws IOException if the target repository can not be initialized
+ */
+ public static void copy(RepositoryConfig source, File target)
+ throws RepositoryException, IOException {
+ copy(source, RepositoryConfig.install(target));
+ }
+
+ /**
+ * Copies the contents of the source repository with the given
+ * configuration to a target repository with the given configuration.
+ *
+ * @param source source repository configuration
+ * @param target target repository directory
+ * @throws RepositoryException if the copy operation fails
+ */
+ public static void copy(RepositoryConfig source, RepositoryConfig target)
+ throws RepositoryException {
+ RepositoryImpl repository = RepositoryImpl.create(source);
+ try {
+ copy(repository, target);
+ } finally {
+ repository.shutdown();
+ }
+ }
+
+ /**
+ * Copies the contents of the given source repository to a repository in
+ * the given target directory.
+ *
+ * The source repository must not be modified while
+ * the copy operation is running to avoid an inconsistent copy.
+ *
+ * @param source source repository directory
+ * @param target target repository directory
+ * @throws RepositoryException if the copy operation fails
+ * @throws IOException if the target repository can not be initialized
+ */
+ public static void copy(RepositoryImpl source, File target)
+ throws RepositoryException, IOException {
+ copy(source, RepositoryConfig.install(target));
+ }
+
+ /**
+ * Copies the contents of the given source repository to a target
+ * repository with the given configuration.
+ *
+ * The source repository must not be modified while
+ * the copy operation is running to avoid an inconsistent copy.
+ *
+ * @param source source repository directory
+ * @param target target repository directory
+ * @throws RepositoryException if the copy operation fails
+ * @throws IOException if the target repository can not be initialized
+ */
+ public static void copy(RepositoryImpl source, RepositoryConfig target)
+ throws RepositoryException {
+ RepositoryImpl repository = RepositoryImpl.create(target);
+ try {
+ new RepositoryCopier(source, repository).copy();
+ } finally {
+ repository.shutdown();
+ }
+
+ // Remove index directories to force re-indexing on next startup
+ // TODO: There should be a cleaner way to do this
+ File targetDir = new File(target.getHomeDir());
+ File repoDir = new File(targetDir, "repository");
+ FileUtils.deleteQuietly(new File(repoDir, "index"));
+ File[] workspaces = new File(targetDir, "workspaces").listFiles();
+ if (workspaces != null) {
+ for (File workspace : workspaces) {
+ FileUtils.deleteQuietly(new File(workspace, "index"));
+ }
+ }
+ }
+
+ /**
+ * Creates a tool for copying the full contents of the source repository
+ * to the given target repository. Any existing content in the target
+ * repository will be overwritten.
+ *
+ * @param source source repository
+ * @param target target repository
+ */
+ public RepositoryCopier(RepositoryImpl source, RepositoryImpl target) {
+ // TODO: It would be better if we were given the RepositoryContext
+ // instances directly. Perhaps we should use something like
+ // RepositoryImpl.getRepositoryCopier(RepositoryImpl target)
+ // instead of this public constructor to achieve that.
+ this.source = source.getRepositoryContext();
+ this.target = target.getRepositoryContext();
+ }
+
+ /**
+ * Copies the full content from the source to the target repository.
+ *
+ * The source repository must not be modified while
+ * the copy operation is running to avoid an inconsistent copy.
+ *
+ * This method leaves the search indexes of the target repository in
+ * an
+ * Note that both the source and the target repository must be closed
+ * during the copy operation as this method requires exclusive access
+ * to the repositories.
+ *
+ * @throws RepositoryException if the copy operation fails
+ */
+ public void copy() throws RepositoryException {
+ logger.info(
+ "Copying repository content from {} to {}",
+ source.getRepository().repConfig.getHomeDir(),
+ target.getRepository().repConfig.getHomeDir());
+ try {
+ copyNamespaces();
+ copyNodeTypes();
+ copyVersionStore();
+ copyWorkspaces();
+ } catch (Exception e) {
+ throw new RepositoryException("Failed to copy content", e);
+ }
+ }
+
+ private void copyNamespaces() throws RepositoryException {
+ NamespaceRegistry sourceRegistry = source.getNamespaceRegistry();
+ NamespaceRegistry targetRegistry = target.getNamespaceRegistry();
+
+ logger.info("Copying registered namespaces");
+ Collection existing = Arrays.asList(targetRegistry.getURIs());
+ for (String uri : sourceRegistry.getURIs()) {
+ if (!existing.contains(uri)) {
+ // TODO: what if the prefix is already taken?
+ targetRegistry.registerNamespace(
+ sourceRegistry.getPrefix(uri), uri);
+ }
+ }
+ }
+
+ private void copyNodeTypes() throws RepositoryException {
+ NodeTypeRegistry sourceRegistry = source.getNodeTypeRegistry();
+ NodeTypeRegistry targetRegistry = target.getNodeTypeRegistry();
+
+ logger.info("Copying registered node types");
+ Collection existing =
+ Arrays.asList(targetRegistry.getRegisteredNodeTypes());
+ Collection register = new ArrayList();
+ for (Name name : sourceRegistry.getRegisteredNodeTypes()) {
+ // TODO: what about modified node types?
+ if (!existing.contains(name)) {
+ register.add(sourceRegistry.getNodeTypeDef(name));
+ }
+ }
+ try {
+ targetRegistry.registerNodeTypes(register);
+ } catch (InvalidNodeTypeDefException e) {
+ throw new RepositoryException("Unable to copy node types", e);
+ }
+ }
+
+ private void copyVersionStore() throws RepositoryException {
+ logger.info("Copying version histories");
+ PersistenceCopier copier = new PersistenceCopier(
+ source.getInternalVersionManager().getPersistenceManager(),
+ target.getInternalVersionManager().getPersistenceManager(),
+ target.getDataStore());
+ copier.copy(RepositoryImpl.VERSION_STORAGE_NODE_ID);
+ copier.copy(RepositoryImpl.ACTIVITIES_NODE_ID);
+ }
+
+ private void copyWorkspaces() throws RepositoryException {
+ Collection existing =
+ Arrays.asList(target.getRepository().getWorkspaceNames());
+ for (String name : source.getRepository().getWorkspaceNames()) {
+ logger.info("Copying workspace {}" , name);
+
+ if (!existing.contains(name)) {
+ target.getRepository().createWorkspace(name);
+ }
+
+ // Copy all the workspace content
+ PersistenceCopier copier = new PersistenceCopier(
+ source.getRepository().getWorkspaceInfo(name).getPersistenceManager(),
+ target.getRepository().getWorkspaceInfo(name).getPersistenceManager(),
+ target.getDataStore());
+ copier.excludeNode(RepositoryImpl.SYSTEM_ROOT_NODE_ID);
+ copier.copy(RepositoryImpl.ROOT_NODE_ID);
+
+ // Copy all the active open-scoped locks
+ LockManagerImpl sourceLockManager =
+ source.getRepository().getLockManager(name);
+ LockManagerImpl targetLockManager =
+ target.getRepository().getLockManager(name);
+ targetLockManager.copyOpenScopedLocksFrom(sourceLockManager);
+ }
+ }
+
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryFactoryImpl.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryFactoryImpl.java
new file mode 100644
index 00000000000..3d75e7c2ec6
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryFactoryImpl.java
@@ -0,0 +1,170 @@
+/*
+ * 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.jackrabbit.core;
+
+import static org.apache.jackrabbit.core.config.RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.api.JackrabbitRepository;
+import org.apache.jackrabbit.api.JackrabbitRepositoryFactory;
+import org.apache.jackrabbit.api.management.RepositoryManager;
+import org.apache.jackrabbit.commons.JcrUtils;
+
+/**
+ * RepositoryFactoryImpl implements a repository factory that
+ * creates a {@link TransientRepository} on {@link #getRepository(Map)}.
+ */
+public class RepositoryFactoryImpl implements JackrabbitRepositoryFactory {
+
+ /**
+ * Name of the repository home parameter.
+ */
+ public static final String REPOSITORY_HOME
+ = "org.apache.jackrabbit.repository.home";
+
+ /**
+ * Name of the repository configuration parameter.
+ */
+ public static final String REPOSITORY_CONF
+ = "org.apache.jackrabbit.repository.conf";
+
+ /**
+ * Map of repository instances.
+ * Key = repository parameters, value = repository instance.
+ */
+ private static final Map REPOSITORIES =
+ new HashMap();
+
+ /**
+ * The repository instances that were created by this factory.
+ */
+ private final Set ownRepositories =
+ new HashSet();
+
+ public Repository getRepository(Map parameters) throws RepositoryException {
+ if (parameters == null) {
+ return getRepository(null, Collections.emptyMap());
+ } else if (parameters.containsKey(REPOSITORY_HOME)) {
+ String home = parameters.get(REPOSITORY_HOME).toString();
+ return getRepository(home, parameters);
+ } else if (parameters.containsKey(JcrUtils.REPOSITORY_URI)) {
+ Object parameter = parameters.get(JcrUtils.REPOSITORY_URI);
+ try {
+ URI uri = new URI(parameter.toString().trim());
+ String scheme = uri.getScheme();
+ if (("file".equalsIgnoreCase(scheme)
+ || "jcr-jackrabbit".equalsIgnoreCase(scheme))
+ && uri.getAuthority() == null) {
+ File file = new File(uri.getPath());
+ if (file.isFile()) {
+ return null; // Not a (possibly missing) directory
+ } else {
+ return getRepository(file.getPath(), parameters);
+ }
+ } else {
+ return null; // not a file: or jcr-jackrabbit: URI
+ }
+ } catch (URISyntaxException e) {
+ return null; // not a valid URI
+ }
+ } else {
+ return null; // unknown or insufficient parameters
+ }
+ }
+
+ private Repository getRepository(String home, Map, ?> parameters)
+ throws RepositoryException {
+ TransientRepository repository =
+ getOrCreateRepository(home, parameters);
+ ownRepositories.add(repository);
+ return repository;
+ }
+
+ /**
+ * Either returns a cached repository or creates a repository instance and
+ * puts it into the {@link #REPOSITORIES} cache.
+ *
+ * @param home path to the repository home.
+ * @return the repository instance.
+ * @throws RepositoryException if an error occurs while creating the
+ * repository instance.
+ */
+ private static synchronized TransientRepository getOrCreateRepository(
+ String home, Map, ?> parameters) throws RepositoryException {
+ // Prepare the repository properties
+ Properties properties = new Properties(System.getProperties());
+ for (Map.Entry, ?> entry : parameters.entrySet()) {
+ Object key = entry.getKey();
+ if (key != null) {
+ Object value = entry.getValue();
+ if (value != null) {
+ properties.setProperty(
+ key.toString(), value.toString());
+ } else {
+ properties.remove(key.toString());
+ }
+ }
+ }
+ if (home != null) {
+ properties.put(REPOSITORY_HOME_VARIABLE, home);
+ }
+
+ TransientRepository repository = REPOSITORIES.get(properties);
+ if (repository == null) {
+ try {
+ TransientRepository tr;
+ if (home == null) {
+ tr = new TransientRepository(properties);
+ // also remember this instance as the default repository
+ REPOSITORIES.put(null, tr);
+ } else {
+ tr = new TransientRepository(properties);
+ }
+ REPOSITORIES.put(properties, tr);
+ repository = tr;
+ } catch (IOException e) {
+ throw new RepositoryException(
+ "Failed to install repository configuration", e);
+ }
+ }
+ return repository;
+ }
+
+ public RepositoryManager getRepositoryManager(JackrabbitRepository repo) throws RepositoryException {
+ if (!(repo instanceof TransientRepository)) {
+ throw new RepositoryException("The repository was not created in this factory");
+ }
+ if (!ownRepositories.contains(repo)) {
+ throw new RepositoryException("The repository was not created in this factory");
+ }
+ return new RepositoryManagerImpl((TransientRepository) repo);
+ }
+
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
new file mode 100644
index 00000000000..06645e3a67f
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
@@ -0,0 +1,2480 @@
+/*
+ * 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.jackrabbit.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.StringReader;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.Credentials;
+import javax.jcr.LoginException;
+import javax.jcr.NoSuchWorkspaceException;
+import javax.jcr.PropertyType;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.ObservationManager;
+import javax.security.auth.Subject;
+
+import org.apache.commons.collections.map.ReferenceMap;
+import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.api.JackrabbitRepository;
+import org.apache.jackrabbit.api.management.RepositoryManager;
+import org.apache.jackrabbit.api.security.authentication.token.TokenCredentials;
+import org.apache.jackrabbit.commons.AbstractRepository;
+import org.apache.jackrabbit.core.cache.CacheManager;
+import org.apache.jackrabbit.core.cluster.ClusterContext;
+import org.apache.jackrabbit.core.cluster.ClusterException;
+import org.apache.jackrabbit.core.cluster.ClusterNode;
+import org.apache.jackrabbit.core.cluster.LockEventChannel;
+import org.apache.jackrabbit.core.cluster.UpdateEventChannel;
+import org.apache.jackrabbit.core.cluster.UpdateEventListener;
+import org.apache.jackrabbit.core.cluster.WorkspaceEventChannel;
+import org.apache.jackrabbit.core.cluster.WorkspaceListener;
+import org.apache.jackrabbit.core.config.ClusterConfig;
+import org.apache.jackrabbit.core.config.PersistenceManagerConfig;
+import org.apache.jackrabbit.core.config.RepositoryConfig;
+import org.apache.jackrabbit.core.config.SecurityManagerConfig;
+import org.apache.jackrabbit.core.config.VersioningConfig;
+import org.apache.jackrabbit.core.config.WorkspaceConfig;
+import org.apache.jackrabbit.core.data.DataStore;
+import org.apache.jackrabbit.core.data.DataStoreException;
+import org.apache.jackrabbit.core.fs.FileSystem;
+import org.apache.jackrabbit.core.fs.FileSystemException;
+import org.apache.jackrabbit.core.fs.FileSystemResource;
+import org.apache.jackrabbit.core.gc.GarbageCollector;
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.id.NodeIdFactory;
+import org.apache.jackrabbit.core.lock.LockManager;
+import org.apache.jackrabbit.core.lock.LockManagerImpl;
+import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.core.nodetype.virtual.VirtualNodeTypeStateManager;
+import org.apache.jackrabbit.core.observation.DelegatingObservationDispatcher;
+import org.apache.jackrabbit.core.observation.EventState;
+import org.apache.jackrabbit.core.observation.EventStateCollection;
+import org.apache.jackrabbit.core.observation.ObservationDispatcher;
+import org.apache.jackrabbit.core.persistence.IterablePersistenceManager;
+import org.apache.jackrabbit.core.persistence.PMContext;
+import org.apache.jackrabbit.core.persistence.PersistenceManager;
+import org.apache.jackrabbit.core.persistence.check.ConsistencyChecker;
+import org.apache.jackrabbit.core.retention.RetentionRegistry;
+import org.apache.jackrabbit.core.retention.RetentionRegistryImpl;
+import org.apache.jackrabbit.core.security.JackrabbitSecurityManager;
+import org.apache.jackrabbit.core.security.authentication.AuthContext;
+import org.apache.jackrabbit.core.security.authentication.token.TokenBasedAuthentication;
+import org.apache.jackrabbit.core.security.authorization.PrivilegeRegistry;
+import org.apache.jackrabbit.core.security.simple.SimpleSecurityManager;
+import org.apache.jackrabbit.core.state.ChangeLog;
+import org.apache.jackrabbit.core.state.ISMLocking;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.ManagedMLRUItemStateCacheFactory;
+import org.apache.jackrabbit.core.state.SharedItemStateManager;
+import org.apache.jackrabbit.core.util.RepositoryLockMechanism;
+import org.apache.jackrabbit.core.version.InternalVersionManager;
+import org.apache.jackrabbit.core.version.InternalVersionManagerImpl;
+import org.apache.jackrabbit.core.xml.ClonedInputSource;
+import org.apache.jackrabbit.data.core.TransactionException;
+import org.apache.jackrabbit.spi.commons.name.NameConstants;
+import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver;
+import org.apache.jackrabbit.spi.commons.namespace.RegistryNamespaceResolver;
+import org.apache.jackrabbit.value.ValueFactoryImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.InputSource;
+
+import EDU.oswego.cs.dl.util.concurrent.Mutex;
+import EDU.oswego.cs.dl.util.concurrent.ReadWriteLock;
+import EDU.oswego.cs.dl.util.concurrent.ReentrantWriterPreferenceReadWriteLock;
+import EDU.oswego.cs.dl.util.concurrent.WriterPreferenceReadWriteLock;
+
+/**
+ * A RepositoryImpl ...
+ */
+public class RepositoryImpl extends AbstractRepository
+ implements javax.jcr.Repository, JackrabbitRepository, SessionListener, WorkspaceListener {
+
+ private static Logger log = LoggerFactory.getLogger(RepositoryImpl.class);
+
+ /**
+ * hardcoded id of the repository root node
+ */
+ public static final NodeId ROOT_NODE_ID = NodeId.valueOf("cafebabe-cafe-babe-cafe-babecafebabe");
+
+ /**
+ * hardcoded id of the "/jcr:system" node
+ */
+ public static final NodeId SYSTEM_ROOT_NODE_ID = NodeId.valueOf("deadbeef-cafe-babe-cafe-babecafebabe");
+
+ /**
+ * hardcoded id of the "/jcr:system/jcr:versionStorage" node
+ */
+ public static final NodeId VERSION_STORAGE_NODE_ID = NodeId.valueOf("deadbeef-face-babe-cafe-babecafebabe");
+
+ /**
+ * hardcoded id of the "/jcr:system/jcr:activities" node
+ */
+ public static final NodeId ACTIVITIES_NODE_ID = NodeId.valueOf("deadbeef-face-babe-ac71-babecafebabe");
+
+ /**
+ * hardcoded id of the "/jcr:system/jcr:configurations" node
+ */
+ public static final NodeId CONFIGURATIONS_NODE_ID = NodeId.valueOf("deadbeef-face-babe-c04f-babecafebabe");
+
+ /**
+ * hardcoded id of the "/jcr:system/jcr:nodeTypes" node
+ */
+ public static final NodeId NODETYPES_NODE_ID = NodeId.valueOf("deadbeef-cafe-cafe-cafe-babecafebabe");
+
+ /**
+ * the name of the resource containing customized descriptors of the repository.
+ */
+ private static final String PROPERTIES_RESOURCE = "repository.properties";
+
+ /**
+ * Key to a string descriptor. Returns the repository cluster id if
+ * and only if clustering is enabled.
+ */
+ public static final String JACKRABBIT_CLUSTER_ID = "jackrabbit.cluster.id";
+
+ /**
+ * the repository descriptors, maps String keys to Value/Value[] objects
+ */
+ private final Map repDescriptors = new HashMap();
+
+ protected final RepositoryContext context = new RepositoryContext(this);
+
+ private final VirtualNodeTypeStateManager virtNTMgr;
+
+ /**
+ * Security manager
+ */
+ private JackrabbitSecurityManager securityMgr;
+
+ /**
+ * Search manager for the jcr:system tree. May be null if
+ * none is configured.
+ */
+ private SearchManager systemSearchMgr;
+
+ // configuration of the repository
+ protected final RepositoryConfig repConfig;
+
+ protected NodeIdFactory nodeIdFactory;
+
+ /**
+ * the delegating observation dispatcher for all workspaces
+ */
+ private final DelegatingObservationDispatcher delegatingDispatcher =
+ new DelegatingObservationDispatcher();
+
+ /**
+ * map of workspace names and WorkspaceInfos.
+ */
+ private final HashMap wspInfos = new HashMap();
+
+ /**
+ * active sessions (weak references)
+ */
+ private final Map activeSessions =
+ new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK);
+
+ // flag indicating if repository has been shut down
+ private boolean disposed;
+
+ /**
+ * The repository lock mechanism ensures that a repository is only instantiated once.
+ */
+ private RepositoryLockMechanism repLock;
+
+ /**
+ * Shutdown lock for guaranteeing that no new sessions are started during
+ * repository shutdown and that a repository shutdown is not initiated
+ * during a login. Each session login acquires a read lock while the
+ * repository shutdown requires a write lock. This guarantees that there
+ * can be multiple concurrent logins when the repository is not shutting
+ * down, but that only a single shutdown and no concurrent logins can
+ * happen simultaneously.
+ */
+ private final ReadWriteLock shutdownLock = new WriterPreferenceReadWriteLock();
+
+ /**
+ * There is one cache manager per repository that manages the sizes of the caches used.
+ */
+ private final CacheManager cacheMgr = new CacheManager();
+
+ /**
+ * Chanel for posting create workspace messages.
+ */
+ private WorkspaceEventChannel createWorkspaceEventChannel;
+
+ /**
+ * Protected constructor.
+ *
+ * @param repConfig the repository configuration.
+ * @throws RepositoryException if there is already another repository
+ * instance running on the given configuration
+ * or another error occurs.
+ */
+ protected RepositoryImpl(RepositoryConfig repConfig) throws RepositoryException {
+ // Acquire a lock on the repository home
+ repLock = repConfig.getRepositoryLockMechanism();
+ repLock.init(repConfig.getHomeDir());
+ repLock.acquire();
+
+ long t0 = System.currentTimeMillis();
+ log.info("Starting repository...");
+
+ boolean succeeded = false;
+ try {
+ this.repConfig = repConfig;
+
+ context.setFileSystem(repConfig.getFileSystem());
+
+ // Load root node identifier
+ context.setRootNodeId(loadRootNodeId());
+
+ // initialize repository descriptors
+ initRepositoryDescriptors();
+
+ // create registries
+ context.setNamespaceRegistry(createNamespaceRegistry());
+ context.setNodeTypeRegistry(createNodeTypeRegistry());
+ context.setPrivilegeRegistry(new PrivilegeRegistry(context.getNamespaceRegistry(), context.getFileSystem()));
+
+ // Create item state cache manager
+ context.setItemStateCacheFactory(
+ new ManagedMLRUItemStateCacheFactory(cacheMgr));
+
+ DataStore dataStore = repConfig.getDataStore();
+ if (dataStore != null) {
+ context.setDataStore(dataStore);
+ }
+
+ nodeIdFactory = new NodeIdFactory(repConfig.getHomeDir());
+ nodeIdFactory.open();
+ context.setNodeIdFactory(nodeIdFactory);
+
+ context.setWorkspaceManager(new WorkspaceManager(this));
+
+ // init workspace configs
+ for (WorkspaceConfig config : repConfig.getWorkspaceConfigs()) {
+ WorkspaceInfo info = createWorkspaceInfo(config);
+ wspInfos.put(config.getName(), info);
+ }
+
+ // initialize optional clustering before setting up any other
+ // external event source that a cluster node will be interested in
+ ClusterNode clusterNode = null;
+ if (repConfig.getClusterConfig() != null) {
+ clusterNode = createClusterNode();
+ context.setClusterNode(clusterNode);
+ context.getNamespaceRegistry().setEventChannel(clusterNode);
+ context.getNodeTypeRegistry().setEventChannel(clusterNode);
+ context.getPrivilegeRegistry().setEventChannel(clusterNode);
+
+ createWorkspaceEventChannel = clusterNode;
+ clusterNode.setListener(this);
+ }
+
+ // init version manager
+ InternalVersionManagerImpl vMgr = createVersionManager(
+ repConfig.getVersioningConfig(), delegatingDispatcher);
+ context.setInternalVersionManager(vMgr);
+ if (clusterNode != null) {
+ vMgr.setEventChannel(clusterNode.createUpdateChannel(null));
+ }
+
+ // init virtual node type manager
+ virtNTMgr = new VirtualNodeTypeStateManager(
+ context.getNodeTypeRegistry(),
+ delegatingDispatcher, NODETYPES_NODE_ID, SYSTEM_ROOT_NODE_ID);
+
+ // initialize startup workspaces
+ initStartupWorkspaces();
+
+ // initialize system search manager
+ getSystemSearchManager(repConfig.getDefaultWorkspaceName());
+
+ // Initialise the security manager;
+ initSecurityManager();
+
+ // after the workspace is initialized we pass a system session to
+ // the virtual node type manager
+
+ // todo FIXME the *global* virtual node type manager is using a session that is bound to a single specific workspace...
+ virtNTMgr.setSession(getSystemSession(repConfig.getDefaultWorkspaceName()));
+
+ // now start cluster node as last step
+ if (clusterNode != null) {
+ setDescriptor(JACKRABBIT_CLUSTER_ID, repConfig.getClusterConfig().getId());
+ try {
+ clusterNode.start();
+ } catch (ClusterException e) {
+ String msg = "Unable to start clustered node, forcing shutdown...";
+ log.error(msg, e);
+ shutdown();
+ throw new RepositoryException(msg, e);
+ }
+ }
+
+ // amount of time in seconds before an idle workspace is automatically
+ // shut down
+ int maxIdleTime = repConfig.getWorkspaceMaxIdleTime();
+ if (maxIdleTime != 0) {
+ // start workspace janitor thread
+ Thread wspJanitor = new Thread(new WorkspaceJanitor(maxIdleTime * 1000));
+ wspJanitor.setName("WorkspaceJanitor");
+ wspJanitor.setPriority(Thread.MIN_PRIORITY);
+ wspJanitor.setDaemon(true);
+ wspJanitor.start();
+ }
+
+ succeeded = true;
+ log.info("Repository started (" + (System.currentTimeMillis() - t0) + "ms)");
+ } catch (RepositoryException e) {
+ log.error("failed to start Repository: " + e.getMessage(), e);
+ throw e;
+ } finally {
+ if (!succeeded) {
+ try {
+ // repository startup failed, clean up...
+ shutdown();
+ } catch (Throwable t) {
+ // ensure this exception does not overlay the original
+ // startup exception and only log it
+ log.error("In addition to startup fail, another unexpected problem " +
+ "occurred while shutting down the repository again.", t);
+ // Clear the repository lock if it was left in place
+ repLock.release();
+ }
+ }
+ }
+ }
+
+ /**
+ * Protected factory method for creating the namespace registry.
+ * Called by the constructor after the repository file system has
+ * been initialised.
+ *
+ * @return namespace registry
+ * @throws RepositoryException if the namespace registry can not be created
+ */
+ protected NamespaceRegistryImpl createNamespaceRegistry()
+ throws RepositoryException {
+ return new NamespaceRegistryImpl(context.getFileSystem());
+ }
+
+ /**
+ * Protected factory method for creating the node type registry.
+ * Called by the constructor after the repository file system and
+ * namespace registry have been initialised.
+ *
+ * @return node type registry
+ * @throws RepositoryException if the node type registry can not be created
+ */
+ protected NodeTypeRegistry createNodeTypeRegistry()
+ throws RepositoryException {
+ return new NodeTypeRegistry(
+ context.getNamespaceRegistry(), context.getFileSystem());
+ }
+
+ /**
+ * Returns the internal component context of this repository.
+ * This package-private method should only be used when there is
+ * no other reasonable way to access the repository context.
+ * A better design would be to access the repository instance
+ * through the repository context.
+ *
+ * @return repository context
+ */
+ RepositoryContext getRepositoryContext() { // TODO: Get rid of this method
+ return context;
+ }
+
+ /**
+ * Get the cache manager of this repository, useful
+ * for setting its memory parameters.
+ *
+ * @return the cache manager
+ * @since 1.3
+ */
+ public CacheManager getCacheManager() {
+ return cacheMgr;
+ }
+
+ /**
+ * Creates the {@link org.apache.jackrabbit.core.security.JackrabbitSecurityManager SecurityManager}
+ * of this Repository and adds it to the repository context.
+ *
+ * @throws RepositoryException if an error occurs.
+ */
+ private synchronized void initSecurityManager() throws RepositoryException {
+ SecurityManagerConfig smc =
+ getConfig().getSecurityConfig().getSecurityManagerConfig();
+ if (smc == null) {
+ log.debug("No configuration entry for SecurityManager. Using org.apache.jackrabbit.core.security.simple.SimpleSecurityManager");
+ securityMgr = new SimpleSecurityManager();
+ } else {
+ securityMgr = smc.newInstance(JackrabbitSecurityManager.class);
+ }
+
+ log.info("SecurityManager = " + securityMgr.getClass());
+
+ context.setSecurityManager(securityMgr);
+
+ String workspaceName = getConfig().getDefaultWorkspaceName();
+ if (smc != null && smc.getWorkspaceName() != null) {
+ workspaceName = smc.getWorkspaceName();
+ }
+
+ // mark the workspace as 'active' for that it does not get disposed
+ // by the workspace-janitor
+ // TODO: There should be a cleaner way to do this
+ markWorkspaceActive(workspaceName);
+
+ // FIXME: Note that this call must be done *after* the security
+ // manager has been added to the repository context, since the
+ // initialisation code may invoke code that depends on the presence
+ // of a security manager. It would be better if this was not the case.
+ SystemSession systemSession = getSystemSession(workspaceName);
+ securityMgr.init(this, systemSession);
+
+ // initial security specific repository descriptors that are defined
+ // by JackrabbitRepository
+ ValueFactory vf = ValueFactoryImpl.getInstance();
+ boolean hasUserMgt;
+ try {
+ securityMgr.getUserManager(systemSession);
+ hasUserMgt = true;
+ } catch (RepositoryException e) {
+ hasUserMgt = false;
+ }
+ setDescriptor(JackrabbitRepository.OPTION_USER_MANAGEMENT_SUPPORTED, vf.createValue(hasUserMgt));
+
+ boolean hasPrincipalMgt;
+ try {
+ securityMgr.getPrincipalManager(systemSession);
+ hasPrincipalMgt = true;
+ } catch (RepositoryException e) {
+ hasPrincipalMgt = false;
+ }
+ setDescriptor(JackrabbitRepository.OPTION_PRINCIPAL_MANAGEMENT_SUPPORTED, vf.createValue(hasPrincipalMgt));
+ setDescriptor(JackrabbitRepository.OPTION_PRIVILEGE_MANAGEMENT_SUPPORTED, vf.createValue(true));
+
+ }
+
+ /**
+ * Creates the version manager.
+ *
+ * @param vConfig the versioning config
+ * @return the newly created version manager
+ * @throws RepositoryException if an error occurs
+ */
+ protected InternalVersionManagerImpl createVersionManager(VersioningConfig vConfig,
+ DelegatingObservationDispatcher delegatingDispatcher)
+ throws RepositoryException {
+
+
+ FileSystem fs = vConfig.getFileSystem();
+ PersistenceManager pm = createPersistenceManager(
+ vConfig.getHomeDir(), fs,
+ vConfig.getPersistenceManagerConfig());
+
+ ISMLocking ismLocking = vConfig.getISMLocking();
+
+ return new InternalVersionManagerImpl(
+ pm, fs, context.getNodeTypeRegistry(), delegatingDispatcher,
+ SYSTEM_ROOT_NODE_ID,
+ VERSION_STORAGE_NODE_ID,
+ ACTIVITIES_NODE_ID,
+ context.getItemStateCacheFactory(),
+ ismLocking,
+ context.getNodeIdFactory());
+ }
+
+ /**
+ * Initialize startup workspaces. Base implementation will initialize the
+ * default workspace. Derived classes may initialize their own startup
+ * workspaces after having called the base implementation.
+ *
+ * @throws RepositoryException if an error occurs
+ */
+ protected void initStartupWorkspaces() throws RepositoryException {
+ String wspName = repConfig.getDefaultWorkspaceName();
+ String secWspName = null;
+ SecurityManagerConfig smc = repConfig.getSecurityConfig().getSecurityManagerConfig();
+ if (smc != null) {
+ secWspName = smc.getWorkspaceName();
+ }
+ try {
+ (wspInfos.get(wspName)).initialize();
+ if (secWspName != null && !wspInfos.containsKey(secWspName)) {
+ createWorkspace(secWspName);
+ log.info("created system workspace: {}", secWspName);
+ }
+ } catch (RepositoryException e) {
+ // if default workspace failed to initialize, shutdown again
+ log.error("Failed to initialize workspace '" + wspName + "'", e);
+ log.error("Unable to start repository, forcing shutdown...");
+ shutdown();
+ throw e;
+ }
+ }
+
+ /**
+ * Returns the root node identifier. The identifier is loaded from
+ * the meta/rootUUID file within the repository file system.
+ * If such a file does not yet exist, the hardcoded default root node
+ * identifier ({@link #ROOT_NODE_ID}) is used and written to that file.
+ *
+ * This utility method should only be used by the constructor after the
+ * repository file system has been initialised.
+ *
+ * @return root node identifier
+ * @throws RepositoryException if the identifier can not be loaded or saved
+ */
+ private NodeId loadRootNodeId() throws RepositoryException {
+ try {
+ FileSystemResource uuidFile = new FileSystemResource(
+ context.getFileSystem(), "/meta/rootUUID");
+ if (uuidFile.exists()) {
+ // Load uuid of the repository's root node. It is stored in
+ // text format (36 characters) for better readability.
+ InputStream in = uuidFile.getInputStream();
+ try {
+ return NodeId.valueOf(IOUtils.toString(in, "US-ASCII"));
+ } finally {
+ IOUtils.closeQuietly(in);
+ }
+ } else {
+ // Use hard-coded uuid for root node rather than generating
+ // a different uuid per repository instance; using a
+ // hard-coded uuid makes it easier to copy/move entire
+ // workspaces from one repository instance to another.
+ uuidFile.makeParentDirs();
+ OutputStream out = uuidFile.getOutputStream();
+ try {
+ out.write(ROOT_NODE_ID.toString().getBytes("US-ASCII"));
+ return ROOT_NODE_ID;
+ } finally {
+ IOUtils.closeQuietly(out);
+ }
+ }
+ } catch (IOException e) {
+ throw new RepositoryException(
+ "Failed to load or persist the root node identifier", e);
+ } catch (FileSystemException fse) {
+ throw new RepositoryException(
+ "Failed to access the root node identifier", fse);
+ }
+ }
+
+ /**
+ * Creates a new RepositoryImpl instance.
+ *
+ *
+ * @param config the configuration of the repository
+ * @return a new RepositoryImpl instance
+ * @throws RepositoryException If an error occurs
+ */
+ public static RepositoryImpl create(RepositoryConfig config)
+ throws RepositoryException {
+ return new RepositoryImpl(config);
+ }
+
+ /**
+ * Performs a sanity check on this repository instance.
+ *
+ * @throws RepositoryException if this repository has been rendered
+ * invalid for some reason (e.g. if it has been shut down)
+ */
+ protected void sanityCheck() throws RepositoryException {
+ // check repository status
+ if (disposed) {
+ throw new RepositoryException(
+ "This repository instance has been shut down.");
+ }
+ }
+
+ /**
+ * Returns the system search manager or null if none is
+ * configured.
+ */
+ protected SearchManager getSystemSearchManager(String wspName)
+ throws RepositoryException {
+ if (systemSearchMgr == null) {
+ if (repConfig.isSearchEnabled()) {
+ systemSearchMgr = new SearchManager(
+ null, context,
+ repConfig,
+ getWorkspaceInfo(wspName).itemStateMgr,
+ context.getInternalVersionManager().getPersistenceManager(),
+ SYSTEM_ROOT_NODE_ID, null, null);
+
+ SystemSession defSysSession = getSystemSession(wspName);
+ ObservationManager obsMgr = defSysSession.getWorkspace().getObservationManager();
+ obsMgr.addEventListener(systemSearchMgr, Event.NODE_ADDED
+ | Event.NODE_REMOVED | Event.PROPERTY_ADDED
+ | Event.PROPERTY_CHANGED | Event.PROPERTY_REMOVED,
+ "/" + defSysSession.getJCRName(NameConstants.JCR_SYSTEM),
+ true, null, null, false);
+ }
+ }
+ return systemSearchMgr;
+ }
+
+ /**
+ * Creates the cluster node.
+ *
+ * @return clustered node
+ */
+ protected ClusterNode createClusterNode() throws RepositoryException {
+ try {
+ ClusterNode clusterNode = new ClusterNode();
+ clusterNode.init(new ExternalEventListener());
+ return clusterNode;
+ } catch (Exception e) {
+ throw new RepositoryException(e);
+ }
+ }
+
+ /**
+ * Returns the names of all workspaces in this repository.
+ *
+ * @return the names of all workspaces in this repository.
+ * @see javax.jcr.Workspace#getAccessibleWorkspaceNames()
+ */
+ protected String[] getWorkspaceNames() {
+ synchronized (wspInfos) {
+ return wspInfos.keySet().toArray(new String[wspInfos.keySet().size()]);
+ }
+ }
+
+ /**
+ * Returns the {@link WorkspaceInfo} for the named workspace.
+ *
+ * @param workspaceName The name of the workspace whose {@link WorkspaceInfo}
+ * is to be returned. This must not be null.
+ * @return The {@link WorkspaceInfo} for the named workspace. This will
+ * never be null.
+ * @throws NoSuchWorkspaceException If the named workspace does not exist.
+ * @throws RepositoryException If this repository has been shut down.
+ */
+ protected WorkspaceInfo getWorkspaceInfo(String workspaceName)
+ throws NoSuchWorkspaceException, RepositoryException {
+ // check sanity of this instance
+ sanityCheck();
+
+ WorkspaceInfo wspInfo;
+ synchronized (wspInfos) {
+ wspInfo = wspInfos.get(workspaceName);
+ if (wspInfo == null) {
+ throw new NoSuchWorkspaceException(workspaceName);
+ }
+ }
+
+ try {
+ wspInfo.initialize();
+ } catch (RepositoryException e) {
+ log.error("Unable to initialize workspace '" + workspaceName + "'", e);
+ throw new NoSuchWorkspaceException(workspaceName);
+ }
+ return wspInfo;
+ }
+
+ /**
+ * Creates a workspace with the given name.
+ *
+ * @param workspaceName name of the new workspace
+ * @throws RepositoryException if a workspace with the given name
+ * already exists or if another error occurs
+ * @see WorkspaceImpl#createWorkspace(String)
+ */
+ protected void createWorkspace(String workspaceName)
+ throws RepositoryException {
+ synchronized (wspInfos) {
+ if (wspInfos.containsKey(workspaceName)) {
+ throw new RepositoryException("workspace '"
+ + workspaceName + "' already exists.");
+ }
+
+ // needed to get newly created workspace config file content when
+ // running in clustered environment
+ StringBuffer workspaceConfigContent = null;
+ if (context.getClusterNode() != null) {
+ workspaceConfigContent = new StringBuffer();
+ }
+
+ // create the workspace configuration
+ WorkspaceConfig config = repConfig.createWorkspaceConfig(workspaceName, workspaceConfigContent);
+ WorkspaceInfo info = createWorkspaceInfo(config);
+ wspInfos.put(workspaceName, info);
+
+ if (workspaceConfigContent != null && createWorkspaceEventChannel != null) {
+ // notify other cluster node that workspace has been created
+ InputSource s = new InputSource(new StringReader(workspaceConfigContent.toString()));
+ createWorkspaceEventChannel.workspaceCreated(workspaceName, new ClonedInputSource(s));
+ }
+ }
+ }
+
+ public void externalWorkspaceCreated(String workspaceName,
+ InputSource configTemplate) throws RepositoryException {
+
+ createWorkspaceInternal(workspaceName, configTemplate);
+ }
+
+ /**
+ * Creates a workspace with the given name and given workspace configuration
+ * template.
+ *
+ * The difference between this method and {@link #createWorkspace(String, InputSource)}
+ * is that the later notifies the other cluster node that workspace has been created
+ * whereas this method only creates the workspace.
+ *
+ * @param workspaceName name of the new workspace
+ * @param configTemplate the workspace configuration template of the new
+ * workspace
+ * @throws RepositoryException if a workspace with the given name already
+ * exists or if another error occurs
+ * @see WorkspaceImpl#createWorkspace(String,InputSource)
+ */
+ private void createWorkspaceInternal(String workspaceName,
+ InputSource configTemplate)
+ throws RepositoryException {
+ synchronized (wspInfos) {
+ if (wspInfos.containsKey(workspaceName)) {
+ throw new RepositoryException("workspace '"
+ + workspaceName + "' already exists.");
+ }
+
+ // create the workspace configuration
+ WorkspaceConfig config = repConfig.createWorkspaceConfig(workspaceName, configTemplate);
+ WorkspaceInfo info = createWorkspaceInfo(config);
+ wspInfos.put(workspaceName, info);
+ }
+ }
+
+ /**
+ * Creates a workspace with the given name and given workspace configuration
+ * template.
+ *
+ * @param workspaceName name of the new workspace
+ * @param configTemplate the workspace configuration template of the new
+ * workspace
+ * @throws RepositoryException if a workspace with the given name already
+ * exists or if another error occurs
+ * @see WorkspaceImpl#createWorkspace(String,InputSource)
+ */
+ protected void createWorkspace(String workspaceName,
+ InputSource configTemplate)
+ throws RepositoryException {
+
+ if (createWorkspaceEventChannel == null) {
+ createWorkspaceInternal(workspaceName, configTemplate);
+ } else {
+ ClonedInputSource template = new ClonedInputSource(configTemplate);
+ createWorkspaceInternal(workspaceName, template.cloneInputSource());
+ createWorkspaceEventChannel.workspaceCreated(workspaceName, template);
+ }
+ }
+
+ SharedItemStateManager getWorkspaceStateManager(String workspaceName)
+ throws NoSuchWorkspaceException, RepositoryException {
+ // check sanity of this instance
+ sanityCheck();
+
+ return getWorkspaceInfo(workspaceName).getItemStateProvider();
+ }
+
+ /**
+ * Enables or disables referential integrity checking for given workspace.
+ * Disabling referential integrity checks can result in a corrupted
+ * workspace, and thus this feature is only available to customized
+ * implementations that subclass RepositoryImpl.
+ *
+ * @see Issue JCR-954
+ * @param workspace name of the workspace
+ * @param enabled true to enable integrity checking (default),
+ * false to disable it
+ * @throws RepositoryException if an error occurs
+ */
+ protected void setReferentialIntegrityChecking(
+ String workspace, boolean enabled) throws RepositoryException {
+ SharedItemStateManager manager = getWorkspaceStateManager(workspace);
+ manager.setCheckReferences(enabled);
+ }
+
+ ObservationDispatcher getObservationDispatcher(String workspaceName)
+ throws NoSuchWorkspaceException, RepositoryException {
+ // check sanity of this instance
+ sanityCheck();
+
+ return getWorkspaceInfo(workspaceName).getObservationDispatcher();
+ }
+
+ /**
+ * Returns the {@link SearchManager} for the workspace with name
+ * workspaceName.
+ *
+ * @param workspaceName the name of the workspace.
+ * @return the SearchManager for the workspace, or
+ * null if the workspace does not have a
+ * SearchManager configured.
+ * @throws NoSuchWorkspaceException if there is no workspace with name
+ * workspaceName.
+ * @throws RepositoryException if an error occurs while opening the
+ * search index.
+ */
+ SearchManager getSearchManager(String workspaceName)
+ throws NoSuchWorkspaceException, RepositoryException {
+ // check sanity of this instance
+ sanityCheck();
+
+ return getWorkspaceInfo(workspaceName).getSearchManager();
+ }
+
+ /**
+ * Returns the {@link LockManager} for the workspace with name
+ * workspaceName
+ *
+ * @param workspaceName workspace name
+ * @return LockManager for the workspace
+ * @throws NoSuchWorkspaceException if such a workspace does not exist
+ * @throws RepositoryException if some other error occurs
+ */
+ LockManagerImpl getLockManager(String workspaceName) throws
+ NoSuchWorkspaceException, RepositoryException {
+ // check sanity of this instance
+ sanityCheck();
+
+ return getWorkspaceInfo(workspaceName).getLockManager();
+ }
+
+ /**
+ * Returns the {@link org.apache.jackrabbit.core.retention.RetentionRegistry} for the workspace with name
+ * workspaceName
+ *
+ * @param workspaceName workspace name
+ * @return RetentionEvaluator for the workspace
+ * @throws NoSuchWorkspaceException if such a workspace does not exist
+ * @throws RepositoryException if some other error occurs
+ */
+ RetentionRegistry getRetentionRegistry(String workspaceName) throws NoSuchWorkspaceException, RepositoryException {
+ // check sanity of this instance
+ sanityCheck();
+ return getWorkspaceInfo(workspaceName).getRetentionRegistry();
+ }
+
+ /**
+ * Returns the {@link SystemSession} for the workspace with name
+ * workspaceName
+ *
+ * @param workspaceName workspace name
+ * @return system session of the specified workspace
+ * @throws NoSuchWorkspaceException if such a workspace does not exist
+ * @throws RepositoryException if some other error occurs
+ */
+ SystemSession getSystemSession(String workspaceName)
+ throws NoSuchWorkspaceException, RepositoryException {
+ // check sanity of this instance
+ sanityCheck();
+
+ return getWorkspaceInfo(workspaceName).getSystemSession();
+ }
+
+ /**
+ * Marks the specified workspace as "active", so that the workspace
+ * janitor won't attempt to dispose it. This is used by features like
+ * security managers and the data store garbage collector to prevent
+ * workspaces from disappearing from below them.
+ *
+ * FIXME: There should be a cleaner way to do this.
+ *
+ * @param workspaceName workspace name
+ * @throws RepositoryException if the workspace can not be accessed
+ */
+ void markWorkspaceActive(String workspaceName) throws RepositoryException {
+ getWorkspaceInfo(workspaceName).setActive(true);
+ }
+
+ /**
+ * Creates a new repository session on the specified workspace for the
+ * authenticated subject of the given login context and
+ * adds it to the active sessions.
+ *
+ * Calls {@link #createSessionInstance(AuthContext, WorkspaceConfig)} to
+ * create the actual SessionImpl instance.
+ *
+ * @param loginContext login context with authenticated subject
+ * @param workspaceName workspace name
+ * @return a new session
+ * @throws NoSuchWorkspaceException if the specified workspace does not exist
+ * @throws AccessDeniedException if the subject of the given login context
+ * is not granted access to the specified
+ * workspace
+ * @throws RepositoryException if another error occurs
+ */
+ protected final SessionImpl createSession(AuthContext loginContext,
+ String workspaceName)
+ throws NoSuchWorkspaceException, AccessDeniedException,
+ RepositoryException {
+ WorkspaceInfo wspInfo = getWorkspaceInfo(workspaceName);
+ SessionImpl ses = createSessionInstance(loginContext, wspInfo.getConfig());
+ onSessionCreated(ses);
+ // reset idle timestamp
+ wspInfo.setIdleTimestamp(0);
+ return ses;
+ }
+
+ /**
+ * Creates a new repository session on the specified workspace for the given
+ * authenticated subject and adds it to the active
+ * sessions.
+ *
+ * Calls {@link #createSessionInstance(Subject, WorkspaceConfig)} to
+ * create the actual SessionImpl instance.
+ *
+ * @param subject authenticated subject
+ * @param workspaceName workspace name
+ * @return a new session
+ * @throws NoSuchWorkspaceException if the specified workspace does not exist
+ * @throws AccessDeniedException if the subject of the given login context
+ * is not granted access to the specified
+ * workspace
+ * @throws RepositoryException if another error occurs
+ */
+ protected final SessionImpl createSession(Subject subject,
+ String workspaceName)
+ throws NoSuchWorkspaceException, AccessDeniedException,
+ RepositoryException {
+ WorkspaceInfo wspInfo = getWorkspaceInfo(workspaceName);
+ SessionImpl ses = createSessionInstance(subject, wspInfo.getConfig());
+ onSessionCreated(ses);
+ // reset idle timestamp
+ wspInfo.setIdleTimestamp(0);
+ return ses;
+ }
+
+ /**
+ * Adds the given session to the list of active sessions and registers this
+ * repository as listener.
+ *
+ * @param session the session to register
+ */
+ protected void onSessionCreated(SessionImpl session) {
+ synchronized (activeSessions) {
+ session.addListener(this);
+ activeSessions.put(session, session);
+ }
+ }
+
+ /**
+ * Tries to add Principals to a given subject:
+ * First Access the Subject from the current AccessControlContext,
+ * If Subject is found the LoginContext is evoked for it, in order
+ * to possibly allow for extension of preauthenticated Subject.
+ * In contrast to a login with Credentials, a Session is created, even if the
+ * Authentication failed.
+ * If the {@link Subject} is marked to be unmodificable or if the
+ * authentication of the the Subject failed Session is build for unchanged
+ * Subject.
+ *
+ * @param workspaceName must not be null
+ * @return if a Subject is exsting null else
+ * @throws RepositoryException
+ * @throws AccessDeniedException
+ */
+ private Session extendAuthentication(String workspaceName)
+ throws RepositoryException, AccessDeniedException {
+
+ Subject subject = null;
+ try {
+ AccessControlContext acc = AccessController.getContext();
+ subject = Subject.getSubject(acc);
+ } catch (SecurityException e) {
+ log.warn("Can't check for preauthentication. Reason: {}", e.getMessage());
+ }
+ if (subject == null) {
+ log.debug("No preauthenticated subject found -> return null.");
+ return null;
+ }
+
+ Session s;
+ if (subject.isReadOnly()) {
+ log.debug("Preauthenticated Subject is read-only -> create Session");
+ s = createSession(subject, workspaceName);
+ } else {
+ log.debug("Found preauthenticated Subject, try to extend authentication");
+ // login either using JAAS or custom LoginModule
+ AuthContext authCtx = context.getSecurityManager().getAuthContext(
+ null, subject, workspaceName);
+ try {
+ authCtx.login();
+ s = createSession(authCtx, workspaceName);
+ } catch (javax.security.auth.login.LoginException e) {
+ // subject could not be extended
+ log.debug("Preauthentication could not be extended");
+ s = createSession(subject, workspaceName);
+ }
+ }
+ return s;
+ }
+
+ //-------------------------------------------------< JackrabbitRepository >
+
+ /**
+ * Shuts down this repository. The shutdown is guarded by a shutdown lock
+ * that prevents any new sessions from being started simultaneously.
+ */
+ public void shutdown() {
+ try {
+ shutdownLock.writeLock().acquire();
+ } catch (InterruptedException e) {
+ // TODO: Should this be a checked exception?
+ throw new RuntimeException("Shutdown lock could not be acquired", e);
+ }
+
+ try {
+ // check status of this instance
+ if (!disposed) {
+ doShutdown();
+ }
+ } finally {
+ shutdownLock.writeLock().release();
+ }
+ }
+
+ /**
+ * Protected method that performs the actual shutdown after the shutdown
+ * lock has been acquired by the {@link #shutdown()} method.
+ */
+ protected synchronized void doShutdown() {
+ log.info("Shutting down repository...");
+
+ // stop optional cluster node
+ ClusterNode clusterNode = context.getClusterNode();
+ if (clusterNode != null) {
+ clusterNode.stop();
+ }
+
+ if (securityMgr != null) {
+ securityMgr.close();
+ }
+
+ // close active user sessions
+ // (copy sessions to array to avoid ConcurrentModificationException;
+ // manually copy entries rather than calling ReferenceMap#toArray() in
+ // order to work around http://issues.apache.org/bugzilla/show_bug.cgi?id=25551)
+ List sa;
+ synchronized (activeSessions) {
+ sa = new ArrayList(activeSessions.size());
+ for (Session session : activeSessions.values()) {
+ sa.add(session);
+ }
+ }
+ for (Session session : sa) {
+ if (session != null) {
+ session.logout();
+ }
+ }
+
+ // shutdown system search manager if there is one
+ if (systemSearchMgr != null) {
+ systemSearchMgr.close();
+ }
+
+ // shut down workspaces
+ synchronized (wspInfos) {
+ for (WorkspaceInfo wspInfo : wspInfos.values()) {
+ wspInfo.dispose();
+ }
+ }
+
+ try {
+ InternalVersionManager m = context.getInternalVersionManager();
+ if (m != null) {
+ m.close();
+ }
+ } catch (Exception e) {
+ log.error("Error while closing Version Manager.", e);
+ }
+
+ repDescriptors.clear();
+
+ DataStore dataStore = context.getDataStore();
+ if (dataStore != null) {
+ try {
+ // close the datastore
+ dataStore.close();
+ } catch (DataStoreException e) {
+ log.error("error while closing datastore", e);
+ }
+ }
+
+ try {
+ // close repository file system
+ context.getFileSystem().close();
+ } catch (FileSystemException e) {
+ log.error("error while closing repository file system", e);
+ }
+
+ try {
+ nodeIdFactory.close();
+ } catch (RepositoryException e) {
+ log.error("error while closing repository file system", e);
+ }
+
+ // make sure this instance is not used anymore
+ disposed = true;
+
+ // wake up threads waiting on this instance's monitor (e.g. workspace janitor)
+ notifyAll();
+
+ // Shut down the executor service
+ ScheduledExecutorService executor = context.getExecutor();
+ executor.shutdown();
+ try {
+ // Wait for all remaining background threads to terminate
+ if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
+ log.warn("Attempting to forcibly shutdown runaway threads");
+ executor.shutdownNow();
+ }
+ } catch (InterruptedException e) {
+ log.warn("Interrupted while waiting for background threads", e);
+ }
+
+ repConfig.getConnectionFactory().close();
+
+ // finally release repository lock
+ if (repLock != null) {
+ try {
+ repLock.release();
+ } catch (RepositoryException e) {
+ log.error("failed to release the repository lock", e);
+ }
+ }
+
+ log.info("Repository has been shutdown");
+ }
+
+ /**
+ * Returns the configuration of this repository.
+ * @return repository configuration
+ */
+ public RepositoryConfig getConfig() {
+ return repConfig;
+ }
+
+ /**
+ * Initializes the repository descriptors by executing the following steps:
+ *
+ *
Sets standard descriptors
+ *
{@link #getCustomRepositoryDescriptors()} is called
+ * afterwards in order to add custom/overwrite standard repository descriptors.
+ * Overridable to allow subclasses to add custom descriptors or to
+ * override standard descriptor values.
+ *
+ * Note that the properties entries will be set as single-valued STRING
+ * descriptor values.
+ *
+ * This method tries to load the Properties from the
+ * org/apache/jackrabbit/core/repository.properties resource
+ * found in the class path.
+ *
+ * @throws RepositoryException if the properties can not be loaded
+ */
+ protected Properties getCustomRepositoryDescriptors() throws RepositoryException {
+ InputStream in = RepositoryImpl.class.getResourceAsStream(PROPERTIES_RESOURCE);
+ if (in != null) {
+ try {
+ Properties props = new Properties();
+ props.load(in);
+ return props;
+ } catch (IOException e) {
+ String msg = "Failed to load customized repository properties: " + e.toString();
+ log.error(msg);
+ throw new RepositoryException(msg, e);
+ } finally {
+ IOUtils.closeQuietly(in);
+ }
+ } else {
+ return null;
+ }
+ }
+
+ protected void setDescriptor(String desc, String value) {
+ setDescriptor(desc, ValueFactoryImpl.getInstance().createValue(value));
+ }
+
+ protected void setDescriptor(String desc, Value value) {
+ repDescriptors.put(desc, new DescriptorValue(value));
+ }
+
+ protected void setDescriptor(String desc, Value[] values) {
+ repDescriptors.put(desc, new DescriptorValue(values));
+ }
+
+ /**
+ * Creates a workspace persistence manager based on the given
+ * configuration. The persistence manager is instantiated using
+ * information in the given persistence manager configuration and
+ * initialized with a persistence manager context containing the other
+ * arguments.
+ *
+ * @return the created workspace persistence manager
+ * @throws RepositoryException if the persistence manager could
+ * not be instantiated/initialized
+ */
+ private PersistenceManager createPersistenceManager(
+ File homeDir, FileSystem fs, PersistenceManagerConfig pmConfig)
+ throws RepositoryException {
+ try {
+ PersistenceManager pm = pmConfig
+ .newInstance(PersistenceManager.class);
+ PMContext pmContext = new PMContext(
+ homeDir, fs,
+ context.getRootNodeId(),
+ context.getNamespaceRegistry(),
+ context.getNodeTypeRegistry(),
+ context.getDataStore(),
+ context.getRepositoryStatistics());
+ pm.init(pmContext);
+ return pm;
+ } catch (Exception e) {
+ String msg = "Cannot instantiate persistence manager " + pmConfig.getClassName();
+ throw new RepositoryException(msg, e);
+ }
+ }
+
+ /**
+ * Creates a SharedItemStateManager or derivative.
+ *
+ * @param persistMgr persistence manager
+ * @param usesReferences true if the item state manager should use
+ * node references to verify integrity of its reference properties;
+ * false otherwise
+ * @return item state manager
+ * @throws ItemStateException if an error occurs
+ */
+ protected SharedItemStateManager createItemStateManager(
+ PersistenceManager persistMgr, boolean usesReferences,
+ ISMLocking locking) throws ItemStateException {
+ return new SharedItemStateManager(
+ persistMgr,
+ context.getRootNodeId(),
+ context.getNodeTypeRegistry(),
+ true,
+ context.getItemStateCacheFactory(),
+ locking,
+ context.getNodeIdFactory());
+ }
+
+ /**
+ * Creates a data store garbage collector for this repository.
+ *
+ * Note that you should use the {@link RepositoryManager} interface
+ * to access this functionality. This RepositoryImpl method may be
+ * removed in future Jackrabbit versions.
+ */
+ public GarbageCollector createDataStoreGarbageCollector()
+ throws RepositoryException {
+ ArrayList pmList = new ArrayList();
+ InternalVersionManagerImpl vm = context.getInternalVersionManager();
+ PersistenceManager pm = vm.getPersistenceManager();
+ pmList.add(pm);
+ String[] wspNames = getWorkspaceNames();
+ SessionImpl[] sessions = new SessionImpl[wspNames.length];
+ for (int i = 0; i < wspNames.length; i++) {
+ String wspName = wspNames[i];
+ WorkspaceInfo wspInfo = getWorkspaceInfo(wspName);
+
+ // this will initialize the workspace if required
+ SessionImpl systemSession =
+ SystemSession.create(context, wspInfo.getConfig());
+
+ // mark the workspace as 'active' so it does not get disposed by
+ // the workspace-janitor until the garbage collector is done
+ wspInfo.setActive(true);
+
+ // the workspace could be disposed, so re-initialize if required
+ // afterwards it will not be disposed because it was marked active
+ wspInfo.initialize();
+
+ sessions[i] = systemSession;
+ pm = wspInfo.getPersistenceManager();
+ pmList.add(pm);
+ }
+ IterablePersistenceManager[] ipmList =
+ new IterablePersistenceManager[pmList.size()];
+ for (int i = 0; i < pmList.size(); i++) {
+ pm = pmList.get(i);
+ if (!(pm instanceof IterablePersistenceManager)) {
+ ipmList = null;
+ break;
+ }
+ ipmList[i] = (IterablePersistenceManager) pm;
+ }
+ GarbageCollector gc = new GarbageCollector(context, context.getDataStore(), ipmList, sessions);
+ synchronized (this) {
+ if (context.isGcRunning()) {
+ throw new RepositoryException("Cannot create GC. GC already running");
+ }
+ context.setGcRunning(true);
+ }
+ return gc;
+ }
+
+ //-----------------------------------------------------------< Repository >
+ /**
+ * {@inheritDoc}
+ */
+ public Session login(Credentials credentials, String workspaceName)
+ throws LoginException, NoSuchWorkspaceException, RepositoryException {
+ try {
+ shutdownLock.readLock().acquire();
+ } catch (InterruptedException e) {
+ throw new RepositoryException("Login lock could not be acquired", e);
+ }
+
+ try {
+ // check sanity of this instance
+ sanityCheck();
+
+ if (workspaceName == null) {
+ workspaceName = repConfig.getDefaultWorkspaceName();
+ }
+
+ // check if workspace exists (will throw NoSuchWorkspaceException if not)
+ getWorkspaceInfo(workspaceName);
+
+ if (credentials == null) {
+ // try to obtain the identity of the already authenticated
+ // subject from access control context
+ Session session = extendAuthentication(workspaceName);
+ if (session != null) {
+ // successful extended authentication
+ return session;
+ } else {
+ log.debug("Attempt to login without Credentials and Subject -> try login with null credentials.");
+ }
+ }
+ // not preauthenticated -> try login with credentials
+ AuthContext authCtx = context.getSecurityManager().getAuthContext(
+ credentials, new Subject(), workspaceName);
+ authCtx.login();
+
+ // create session, and add SimpleCredentials attributes (JCR-1932)
+ SessionImpl session = createSession(authCtx, workspaceName);
+ if (credentials instanceof SimpleCredentials) {
+ SimpleCredentials sc = (SimpleCredentials) credentials;
+ for (String name : sc.getAttributeNames()) {
+ if (!TokenBasedAuthentication.isMandatoryAttribute(name)) {
+ session.setAttribute(name, sc.getAttribute(name));
+ }
+ }
+ }
+ Set tokenCreds = session.getSubject().getPublicCredentials(TokenCredentials.class);
+ if (!tokenCreds.isEmpty()) {
+ TokenCredentials tc = tokenCreds.iterator().next();
+ for (String name : tc.getAttributeNames()) {
+ if (!TokenBasedAuthentication.isMandatoryAttribute(name)) {
+ session.setAttribute(name, tc.getAttribute(name));
+ }
+ }
+ }
+
+ log.debug("User {} logged in to workspace {}",
+ session.getUserID(), workspaceName);
+ return session;
+ } catch (SecurityException se) {
+ throw new LoginException("Unable to access authentication information", se);
+ } catch (javax.security.auth.login.LoginException le) {
+ throw new LoginException(le.getMessage(), le);
+ } catch (AccessDeniedException ade) {
+ // authenticated subject is not authorized for the specified workspace
+ throw new LoginException("Workspace access denied", ade);
+ } finally {
+ shutdownLock.readLock().release();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getDescriptor(String key) {
+ Value v = getDescriptorValue(key);
+ try {
+ return (v == null) ? null : v.getString();
+ } catch (RepositoryException e) {
+ log.error("corrupt descriptor value: " + key, e);
+ return null;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String[] getDescriptorKeys() {
+ String[] keys = repDescriptors.keySet().toArray(new String[repDescriptors.keySet().size()]);
+ Arrays.sort(keys);
+ return keys;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Value getDescriptorValue(String key) {
+ DescriptorValue descVal = repDescriptors.get(key);
+ return (descVal != null) ? descVal.getValue() : null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Value[] getDescriptorValues(String key) {
+ DescriptorValue descVal = repDescriptors.get(key);
+ return (descVal != null) ? descVal.getValues() : null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isSingleValueDescriptor(String key) {
+ DescriptorValue descVal = repDescriptors.get(key);
+ return (descVal != null && descVal.getValue() != null);
+ }
+
+ //------------------------------------------------------< SessionListener >
+ /**
+ * {@inheritDoc}
+ */
+ public void loggingOut(SessionImpl session) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void loggedOut(SessionImpl session) {
+ synchronized (activeSessions) {
+ // remove session from active sessions
+ activeSessions.remove(session);
+ }
+ }
+
+ //------------------------------------------< overridable factory methods >
+ /**
+ * Creates an instance of the {@link SessionImpl} class representing a
+ * user authenticated by the loginContext instance attached
+ * to the workspace configured by the wspConfig.
+ *
+ * @throws AccessDeniedException if the subject of the given login context
+ * is not granted access to the specified
+ * workspace
+ * @throws RepositoryException If any other error occurs creating the
+ * session.
+ */
+ protected SessionImpl createSessionInstance(AuthContext loginContext,
+ WorkspaceConfig wspConfig)
+ throws AccessDeniedException, RepositoryException {
+ return new XASessionImpl(context, loginContext, wspConfig);
+ }
+
+ /**
+ * Creates an instance of the {@link SessionImpl} class representing a
+ * user represented by the subject instance attached
+ * to the workspace configured by the wspConfig.
+ *
+ * @throws AccessDeniedException if the subject of the given login context
+ * is not granted access to the specified
+ * workspace
+ * @throws RepositoryException If any other error occurs creating the
+ * session.
+ */
+ protected SessionImpl createSessionInstance(Subject subject,
+ WorkspaceConfig wspConfig)
+ throws AccessDeniedException, RepositoryException {
+ return new XASessionImpl(context, subject, wspConfig);
+ }
+
+ /**
+ * Creates a new {@link RepositoryImpl.WorkspaceInfo} instance for
+ * wspConfig.
+ *
+ * @param wspConfig the workspace configuration.
+ * @return a new WorkspaceInfo instance.
+ */
+ protected WorkspaceInfo createWorkspaceInfo(WorkspaceConfig wspConfig) {
+ return new WorkspaceInfo(wspConfig);
+ }
+
+ //--------------------------------------------------------< inner classes >
+ /**
+ * WorkspaceInfo holds the objects that are shared
+ * among multiple per-session WorkspaceImpl instances
+ * representing the same named workspace, i.e. the same physical
+ * storage.
+ */
+ public class WorkspaceInfo implements UpdateEventListener {
+
+ /**
+ * workspace configuration (passed in constructor)
+ */
+ private final WorkspaceConfig config;
+
+ /**
+ * file system (instantiated on init)
+ */
+ private FileSystem fs;
+
+ /**
+ * persistence manager (instantiated on init)
+ */
+ private PersistenceManager persistMgr;
+
+ /**
+ * item state provider (instantiated on init)
+ */
+ private SharedItemStateManager itemStateMgr;
+
+ /**
+ * observation dispatcher (instantiated on init)
+ */
+ private ObservationDispatcher dispatcher;
+
+ /**
+ * system session (lazily instantiated)
+ */
+ private SystemSession systemSession;
+
+ /**
+ * search manager (lazily instantiated)
+ */
+ private SearchManager searchMgr;
+
+ /**
+ * lock manager (lazily instantiated)
+ */
+ private LockManagerImpl lockMgr;
+
+ /**
+ * internal manager for evaluation of effective retention policies
+ * and holds
+ */
+ private RetentionRegistryImpl retentionReg;
+
+ /**
+ * flag indicating whether this instance has been initialized.
+ */
+ private boolean initialized;
+
+ /**
+ * Flag used to mark this as an "active" workspace that should not
+ * get automatically disposed by the workspace janitor.
+ */
+ private boolean active;
+
+ /**
+ * lock that guards the initialization of this instance
+ */
+ private final ReadWriteLock initLock =
+ new ReentrantWriterPreferenceReadWriteLock();
+
+ /**
+ * timestamp when the workspace has been determined being idle
+ */
+ private long idleTimestamp;
+
+ /**
+ * mutex for this workspace, used for locking transactions
+ */
+ private final Mutex xaLock = new Mutex();
+
+ /**
+ * Update event channel, used in clustered environment.
+ */
+ private UpdateEventChannel updateChannel;
+
+ /**
+ * Lock event channel, used in clustered environment.
+ */
+ private LockEventChannel lockChannel;
+
+ /**
+ * Creates a new WorkspaceInfo based on the given
+ * config.
+ *
+ * @param config workspace configuration
+ */
+ protected WorkspaceInfo(WorkspaceConfig config) {
+ this.config = config;
+ idleTimestamp = 0;
+ initialized = false;
+ }
+
+ /**
+ * Returns the workspace name.
+ *
+ * @return the workspace name
+ */
+ protected String getName() {
+ return config.getName();
+ }
+
+ /**
+ * Returns the workspace configuration.
+ *
+ * @return the workspace configuration
+ */
+ public WorkspaceConfig getConfig() {
+ return config;
+ }
+
+ /**
+ * Returns the timestamp when the workspace has become idle or zero
+ * if the workspace is currently not idle.
+ *
+ * @return the timestamp when the workspace has become idle or zero if
+ * the workspace is not idle.
+ */
+ final long getIdleTimestamp() {
+ return idleTimestamp;
+ }
+
+ /**
+ * Sets the timestamp when the workspace has become idle. if
+ * ts == 0 the workspace is marked as being currently
+ * active.
+ *
+ * @param ts timestamp when workspace has become idle.
+ */
+ final void setIdleTimestamp(long ts) {
+ idleTimestamp = ts;
+ }
+
+ /**
+ * Returns true if this workspace info is initialized,
+ * otherwise returns false.
+ *
+ * @return true if this workspace info is initialized.
+ */
+ protected final boolean isInitialized() {
+ try {
+ if (!initLock.readLock().attempt(0)) {
+ return false;
+ }
+ } catch (InterruptedException e) {
+ return false;
+ }
+ // can't use 'finally' pattern here
+ boolean ret = initialized;
+ initLock.readLock().release();
+ return ret;
+ }
+
+ public boolean isActive() {
+ return active;
+ }
+
+ public void setActive(boolean active) {
+ this.active = active;
+ }
+
+ /**
+ * Returns the workspace file system.
+ *
+ * @return the workspace file system
+ */
+ protected FileSystem getFileSystem() {
+ if (!isInitialized()) {
+ throw new IllegalStateException("workspace '" + getName()
+ + "' not initialized");
+ }
+
+ return fs;
+ }
+
+ /**
+ * Returns the workspace persistence manager.
+ *
+ * @return the workspace persistence manager
+ * @throws RepositoryException if the persistence manager could not be
+ * instantiated/initialized
+ */
+ public PersistenceManager getPersistenceManager()
+ throws RepositoryException {
+ if (!isInitialized()) {
+ throw new IllegalStateException("workspace '" + getName()
+ + "' not initialized");
+ }
+
+ return persistMgr;
+ }
+
+ /**
+ * Returns the workspace item state provider
+ *
+ * @return the workspace item state provider
+ * @throws RepositoryException if the workspace item state provider
+ * could not be created
+ */
+ protected SharedItemStateManager getItemStateProvider()
+ throws RepositoryException {
+ if (!isInitialized()) {
+ throw new IllegalStateException("workspace '" + getName()
+ + "' not initialized");
+ }
+
+ return itemStateMgr;
+ }
+
+ /**
+ * Returns the observation dispatcher for this workspace
+ *
+ * @return the observation dispatcher for this workspace
+ */
+ protected ObservationDispatcher getObservationDispatcher() {
+ if (!isInitialized()) {
+ throw new IllegalStateException("workspace '" + getName()
+ + "' not initialized");
+ }
+
+ return dispatcher;
+ }
+
+ /**
+ * Returns the search manager for this workspace.
+ *
+ * @return the search manager for this workspace, or null
+ * if no SearchManager
+ * @throws RepositoryException if the search manager could not be created
+ */
+ protected SearchManager getSearchManager() throws RepositoryException {
+ if (!isInitialized()) {
+ throw new IllegalStateException("workspace '" + getName()
+ + "' not initialized");
+ }
+
+ synchronized (this) {
+ if (searchMgr == null && config.isSearchEnabled()) {
+ // search manager is lazily instantiated in order to avoid
+ // 'chicken & egg' bootstrap problems
+ searchMgr = new SearchManager(
+ getName(),
+ context,
+ config,
+ itemStateMgr, persistMgr,
+ context.getRootNodeId(),
+ getSystemSearchManager(getName()),
+ SYSTEM_ROOT_NODE_ID);
+ }
+ return searchMgr;
+ }
+ }
+
+ /**
+ * Returns the lock manager for this workspace.
+ *
+ * @return the lock manager for this workspace
+ * @throws RepositoryException if the lock manager could not be created
+ */
+ protected LockManagerImpl getLockManager() throws RepositoryException {
+ if (!isInitialized()) {
+ throw new IllegalStateException("workspace '" + getName()
+ + "' not initialized");
+ }
+
+ synchronized (this) {
+ // lock manager is lazily instantiated in order to avoid
+ // 'chicken & egg' bootstrap problems
+ if (lockMgr == null) {
+ lockMgr = createLockManager();
+ ClusterNode clusterNode = context.getClusterNode();
+ if (clusterNode != null && config.isClustered()) {
+ lockChannel = clusterNode.createLockChannel(getName());
+ lockMgr.setEventChannel(lockChannel);
+ }
+ }
+ return lockMgr;
+ }
+ }
+
+ /**
+ * Create a new lock manager. This method is only called once within
+ * getLockManager().
+ *
+ * @return the lock manager
+ */
+ protected LockManagerImpl createLockManager() throws RepositoryException {
+ return new LockManagerImpl(
+ getSystemSession(), fs, context.getExecutor());
+ }
+
+ /**
+ * Return manager used for evaluating effect retention and holds.
+ *
+ * @return
+ * @throws RepositoryException
+ */
+ protected RetentionRegistry getRetentionRegistry() throws RepositoryException {
+ if (!isInitialized()) {
+ throw new IllegalStateException("workspace '" + getName() + "' not initialized");
+ }
+ synchronized (this) {
+ if (retentionReg == null) {
+ retentionReg = new RetentionRegistryImpl(getSystemSession(), fs);
+ }
+ return retentionReg;
+ }
+ }
+
+ /**
+ * Returns the system session for this workspace.
+ *
+ * @return the system session for this workspace
+ * @throws RepositoryException if the system session could not be created
+ */
+ protected SystemSession getSystemSession() throws RepositoryException {
+ if (!isInitialized()) {
+ throw new IllegalStateException("workspace '" + getName()
+ + "' not initialized");
+ }
+
+ synchronized (this) {
+ // system session is lazily instantiated in order to avoid
+ // 'chicken & egg' bootstrap problems
+ if (systemSession == null) {
+ systemSession = SystemSession.create(context, config);
+ }
+ return systemSession;
+ }
+ }
+
+ /**
+ * Initializes this workspace info. The following components are
+ * initialized immediately:
+ *
+ *
file system
+ *
persistence manager
+ *
shared item state manager
+ *
observation manager factory
+ *
+ * The following components are initialized lazily (i.e. on demand)
+ * in order to save resources and to avoid 'chicken & egg' bootstrap
+ * problems:
+ *
+ *
system session
+ *
lock manager
+ *
search manager
+ *
+ * @return true if this instance has been successfully
+ * initialized, false if it is already initialized.
+ * @throws RepositoryException if an error occurred during the initialization
+ */
+ final boolean initialize() throws RepositoryException {
+ // check initialize status
+ try {
+ initLock.readLock().acquire();
+ } catch (InterruptedException e) {
+ throw new RepositoryException("Unable to aquire read lock.", e);
+ }
+ try {
+ if (initialized) {
+ // already initialized, we're done
+ return false;
+ }
+ } finally {
+ initLock.readLock().release();
+ }
+
+ // workspace info was not initialized, now check again with write lock
+ try {
+ initLock.writeLock().acquire();
+ } catch (InterruptedException e) {
+ throw new RepositoryException("Unable to aquire write lock.", e);
+ }
+ try {
+ if (initialized) {
+ // already initialized, some other thread was quicker, we're done
+ return false;
+ }
+ log.info("initializing workspace '" + getName() + "'...");
+ doInitialize();
+ initialized = true;
+ doPostInitialize();
+ log.info("workspace '" + getName() + "' initialized");
+ return true;
+ } finally {
+ initLock.writeLock().release();
+ }
+ }
+
+ /**
+ * Does the actual initialization work. assumes holding write lock.
+ * @throws RepositoryException if an error occurs.
+ */
+ protected void doInitialize() throws RepositoryException {
+ fs = config.getFileSystem();
+
+ persistMgr = createPersistenceManager(
+ new File(config.getHomeDir()), fs,
+ config.getPersistenceManagerConfig());
+
+ doVersionRecovery();
+
+ ISMLocking ismLocking = config.getISMLocking();
+
+ // create item state manager
+ try {
+ itemStateMgr =
+ createItemStateManager(persistMgr, true, ismLocking);
+ try {
+ itemStateMgr.addVirtualItemStateProvider(
+ context.getInternalVersionManager().getVirtualItemStateProvider());
+ itemStateMgr.addVirtualItemStateProvider(
+ virtNTMgr.getVirtualItemStateProvider());
+ } catch (Exception e) {
+ log.error("Unable to add vmgr: " + e.toString(), e);
+ }
+ ClusterNode clusterNode = context.getClusterNode();
+ if (clusterNode != null && config.isClustered()) {
+ updateChannel = clusterNode.createUpdateChannel(getName());
+ itemStateMgr.setEventChannel(updateChannel);
+ updateChannel.setListener(this);
+ if (persistMgr instanceof ConsistencyChecker) {
+ ((ConsistencyChecker) persistMgr).setEventChannel(updateChannel);
+ }
+ }
+ } catch (ItemStateException ise) {
+ String msg = "failed to instantiate shared item state manager";
+ log.debug(msg);
+ throw new RepositoryException(msg, ise);
+ }
+
+ dispatcher = new ObservationDispatcher();
+
+ // register the observation factory of that workspace
+ delegatingDispatcher.addDispatcher(dispatcher);
+ }
+
+ /**
+ * If necessary, recover from a lost version history.
+ */
+ protected void doVersionRecovery() throws RepositoryException {
+ // JCR-2551: Recovery from a lost version history
+ if (Boolean.getBoolean("org.apache.jackrabbit.version.recovery")) {
+ RepositoryChecker checker = new RepositoryChecker(
+ persistMgr, context.getInternalVersionManager());
+ checker.check(ROOT_NODE_ID, true, true);
+ }
+ }
+
+ /**
+ * Initializes the search manager of this workspace info. This method
+ * is called while still holding the write lock on this workspace
+ * info, but {@link #initialized} is already set to true.
+ *
+ * @throws RepositoryException if the search manager could not be created
+ */
+ protected void doPostInitialize()
+ throws RepositoryException {
+ // get system Workspace instance
+ WorkspaceImpl wsp = (WorkspaceImpl) getSystemSession().getWorkspace();
+
+ /**
+ * todo implement 'System' workspace
+ * FIXME
+ * - there should be one 'System' workspace per repository
+ * - the 'System' workspace should have the /jcr:system node
+ * - versions, version history and node types should be reflected in
+ * this system workspace as content under /jcr:system
+ * - all other workspaces should be dynamic workspaces based on
+ * this 'read-only' system workspace
+ *
+ * for now, the jcr:system node is created in
+ * {@link org.apache.jackrabbit.core.state.SharedItemStateManager#createRootNodeState}
+ */
+
+ log.debug("initializing SearchManager...");
+ long t0 = System.currentTimeMillis();
+ // register SearchManager as event listener
+ SearchManager searchMgr = getSearchManager();
+ if (searchMgr != null) {
+ wsp.getObservationManager().addEventListener(searchMgr,
+ Event.NODE_ADDED | Event.NODE_REMOVED
+ | Event.PROPERTY_ADDED | Event.PROPERTY_REMOVED
+ | Event.PROPERTY_CHANGED,
+ "/", true, null, null, false);
+ }
+ log.debug("SearchManager initialized (" + (System.currentTimeMillis() - t0) + "ms)");
+ }
+
+ /**
+ * Disposes this WorkspaceInfo if it has been idle for more
+ * than maxIdleTime milliseconds.
+ *
+ * @param maxIdleTime amount of time in mmilliseconds before an idle
+ * workspace is automatically shutdown.
+ */
+ final void disposeIfIdle(long maxIdleTime) {
+ try {
+ initLock.readLock().acquire();
+ } catch (InterruptedException e) {
+ return;
+ }
+ try {
+ if (!initialized || active) {
+ return;
+ }
+ long currentTS = System.currentTimeMillis();
+ if (idleTimestamp == 0) {
+ // set idle timestamp
+ idleTimestamp = currentTS;
+ } else {
+ if ((currentTS - idleTimestamp) > maxIdleTime) {
+ // temporarily shutdown workspace
+ log.info("disposing workspace '" + getName()
+ + "' which has been idle for "
+ + (currentTS - idleTimestamp) + " ms");
+ dispose();
+ }
+ }
+ } finally {
+ initLock.readLock().release();
+ }
+ }
+
+ /**
+ * Disposes all objects this WorkspaceInfo is holding.
+ */
+ final void dispose() {
+ try {
+ initLock.writeLock().acquire();
+ } catch (InterruptedException e) {
+ throw new IllegalStateException("Unable to aquire write lock.");
+ }
+ try {
+ if (!initialized) {
+ // nothing to dispose of, we're already done
+ return;
+ }
+
+ log.info("shutting down workspace '" + getName() + "'...");
+ doDispose();
+ // reset idle timestamp
+ idleTimestamp = 0;
+
+ active = false;
+ initialized = false;
+ log.info("workspace '" + getName() + "' has been shutdown");
+ } finally {
+ initLock.writeLock().release();
+ }
+ }
+
+ /**
+ * Does the actual disposal. assumes holding write lock.
+ */
+ protected void doDispose() {
+ // inform cluster node about disposal
+ if (updateChannel != null) {
+ updateChannel.setListener(null);
+ }
+ if (lockChannel != null) {
+ lockChannel.setListener(null);
+ }
+
+ // deregister the observation factory of that workspace
+ delegatingDispatcher.removeDispatcher(dispatcher);
+
+ // dispose observation manager factory
+ dispatcher.dispose();
+ dispatcher = null;
+
+ // shutdown search managers
+ if (searchMgr != null) {
+ searchMgr.close();
+ searchMgr = null;
+ }
+
+ // deregister
+ if (securityMgr != null) {
+ securityMgr.dispose(getName());
+ }
+
+
+ // close system session
+ if (systemSession != null) {
+ systemSession.removeListener(RepositoryImpl.this);
+ systemSession.logout();
+ systemSession = null;
+ }
+
+ // dispose shared item state manager
+ itemStateMgr.dispose();
+ itemStateMgr = null;
+
+ // close persistence manager
+ try {
+ persistMgr.close();
+ } catch (Exception e) {
+ log.error("error while closing persistence manager of workspace "
+ + config.getName(), e);
+ }
+ persistMgr = null;
+
+ // close lock manager
+ if (lockMgr != null) {
+ lockMgr.close();
+ lockMgr = null;
+ }
+
+ // close retention registry
+ if (retentionReg != null) {
+ retentionReg.close();
+ retentionReg = null;
+ }
+
+ // close workspace file system
+ try {
+ fs.close();
+ } catch (FileSystemException fse) {
+ log.error("error while closing file system of workspace " + config.getName(), fse);
+ }
+ fs = null;
+ }
+
+ /**
+ * Locks this workspace info. This is used (and only should be) by
+ * the {@link XASessionImpl} in order to lock all internal resources
+ * during a commit.
+ *
+ * @throws TransactionException
+ */
+ void lockAcquire() throws TransactionException {
+ try {
+ xaLock.acquire();
+ } catch (InterruptedException e) {
+ throw new TransactionException("Error while acquiering lock", e);
+ }
+
+ }
+
+ /**
+ * Unlocks this workspace info. This is used (and only should be) by
+ * the {@link XASessionImpl} in order to lock all internal resources
+ * during a commit.
+ */
+ void lockRelease() {
+ xaLock.release();
+ }
+
+ //----------------------------------------------< UpdateEventListener >
+
+ /**
+ * {@inheritDoc}
+ */
+ public void externalUpdate(ChangeLog external,
+ List events,
+ long timestamp,
+ String userData) throws RepositoryException {
+ try {
+ EventStateCollection esc = new EventStateCollection(
+ getObservationDispatcher(), null, null);
+ esc.setUserData(userData);
+ esc.addAll(events);
+ esc.setTimestamp(timestamp);
+
+ getItemStateProvider().externalUpdate(external, esc);
+ } catch (IllegalStateException e) {
+ String msg = "Unable to deliver events: " + e.getMessage();
+ throw new RepositoryException(msg, e);
+ }
+ }
+
+ }
+
+ /**
+ * The workspace janitor thread that will shutdown workspaces that have
+ * been idle for a certain amount of time.
+ */
+ private class WorkspaceJanitor implements Runnable {
+
+ /**
+ * amount of time in milliseconds before an idle workspace is
+ * automatically shutdown.
+ */
+ private long maxIdleTime;
+
+ /**
+ * interval in milliseconds between checks for idle workspaces.
+ */
+ private long checkInterval;
+
+ /**
+ * Creates a new WorkspaceJanitor instance responsible for
+ * shutting down idle workspaces.
+ *
+ * @param maxIdleTime amount of time in milliseconds before an idle
+ * workspace is automatically shutdown.
+ */
+ WorkspaceJanitor(long maxIdleTime) {
+ this.maxIdleTime = maxIdleTime;
+ // compute check interval as 10% of maxIdleTime
+ checkInterval = (long) (0.1 * maxIdleTime);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Performs the following tasks in a while (true) loop:
+ *
+ *
wait for checkInterval milliseconds
+ *
build list of initialized but currently inactive workspaces
+ * (excluding the default workspace)
+ *
shutdown those workspaces that have been idle for at least
+ * maxIdleTime milliseconds
+ *
+ */
+ public void run() {
+ while (true) {
+ synchronized (RepositoryImpl.this) {
+ try {
+ RepositoryImpl.this.wait(checkInterval);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ if (disposed) {
+ return;
+ }
+ }
+ // get names of workspaces
+ Set wspNames;
+ synchronized (wspInfos) {
+ wspNames = new HashSet(wspInfos.keySet());
+ }
+ // remove default workspace (will never be shutdown when idle)
+ wspNames.remove(repConfig.getDefaultWorkspaceName());
+
+ synchronized (activeSessions) {
+ // remove workspaces with active sessions
+ for (Session ses : activeSessions.values()) {
+ wspNames.remove(ses.getWorkspace().getName());
+ }
+ }
+
+ // remaining names denote workspaces which currently have not
+ // active sessions
+ for (String wspName : wspNames) {
+ WorkspaceInfo wspInfo;
+ synchronized (wspInfos) {
+ wspInfo = wspInfos.get(wspName);
+ }
+ wspInfo.disposeIfIdle(maxIdleTime);
+ }
+ }
+ }
+ }
+
+ /**
+ * Cluster context passed to a ClusterNode.
+ */
+ class ExternalEventListener implements ClusterContext {
+
+ /**
+ * {@inheritDoc}
+ */
+ public ClusterConfig getClusterConfig() {
+ return getConfig().getClusterConfig();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public File getRepositoryHome() {
+ return new File(getConfig().getHomeDir());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public NamespaceResolver getNamespaceResolver() {
+ return new RegistryNamespaceResolver(context.getNamespaceRegistry());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void updateEventsReady(String workspace) throws RepositoryException {
+ // toggle the initialization of some workspace
+ getWorkspaceInfo(workspace);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void lockEventsReady(String workspace) throws RepositoryException {
+ // toggle the initialization of some workspace's lock manager
+ getWorkspaceInfo(workspace).getLockManager();
+ }
+
+ }
+
+ /**
+ * Represents a Repository Descriptor Value (either Value or Value[])
+ */
+ protected static final class DescriptorValue {
+
+ private Value val;
+ private Value[] vals;
+
+ protected DescriptorValue(Value val) {
+ this.val = val;
+ }
+
+ protected DescriptorValue(Value[] vals) {
+ this.vals = vals;
+ }
+
+ protected Value getValue() {
+ return val;
+ }
+
+ protected Value[] getValues() {
+ return vals != null ? vals : new Value[] {val};
+ }
+ }
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryManagerImpl.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryManagerImpl.java
new file mode 100644
index 00000000000..a51a78dded3
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/RepositoryManagerImpl.java
@@ -0,0 +1,48 @@
+/*
+ * 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.jackrabbit.core;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.api.management.DataStoreGarbageCollector;
+import org.apache.jackrabbit.api.management.RepositoryManager;
+
+/**
+ * The repository manager implementation.
+ */
+public class RepositoryManagerImpl implements RepositoryManager {
+
+ private final TransientRepository tr;
+
+ RepositoryManagerImpl(TransientRepository tr) {
+ this.tr = tr;
+ }
+
+ public DataStoreGarbageCollector createDataStoreGarbageCollector() throws RepositoryException {
+ RepositoryImpl rep = tr.getRepository();
+ if (rep != null) {
+ return rep.createDataStoreGarbageCollector();
+ } else {
+ throw new RepositoryException("Repository is stopped");
+ }
+ }
+
+ public void stop() {
+ tr.shutdown();
+ }
+
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SearchManager.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SearchManager.java
new file mode 100644
index 00000000000..05cd8fc4099
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SearchManager.java
@@ -0,0 +1,461 @@
+/*
+ * 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.jackrabbit.core;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.jcr.NamespaceException;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.EventIterator;
+import javax.jcr.query.InvalidQueryException;
+import javax.jcr.query.Query;
+import javax.jcr.query.qom.QueryObjectModel;
+
+import org.apache.jackrabbit.core.config.SearchConfig;
+import org.apache.jackrabbit.core.fs.FileSystem;
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.observation.EventImpl;
+import org.apache.jackrabbit.core.observation.SynchronousEventListener;
+import org.apache.jackrabbit.core.persistence.PersistenceManager;
+import org.apache.jackrabbit.core.query.AbstractQueryImpl;
+import org.apache.jackrabbit.core.query.QueryHandler;
+import org.apache.jackrabbit.core.query.QueryHandlerContext;
+import org.apache.jackrabbit.core.query.QueryHandlerFactory;
+import org.apache.jackrabbit.core.query.QueryObjectModelImpl;
+import org.apache.jackrabbit.core.session.SessionContext;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.SharedItemStateManager;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.commons.conversion.MalformedPathException;
+import org.apache.jackrabbit.spi.commons.query.qom.QueryObjectModelTree;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Acts as a global entry point to execute queries and index nodes.
+ */
+public class SearchManager implements SynchronousEventListener {
+
+ /**
+ * Logger instance for this class
+ */
+ private static final Logger log = LoggerFactory.getLogger(SearchManager.class);
+
+ /**
+ * Namespace URI for xpath functions
+ */
+ private static final String NS_FN_PREFIX = "fn";
+ public static final String NS_FN_URI = "http://www.w3.org/2005/xpath-functions";
+
+ /**
+ * Deprecated namespace URI for xpath functions
+ */
+ private static final String NS_FN_OLD_PREFIX = "fn_old";
+ public static final String NS_FN_OLD_URI = "http://www.w3.org/2004/10/xpath-functions";
+
+ /**
+ * Namespace URI for XML schema
+ */
+ private static final String NS_XS_PREFIX = "xs";
+ public static final String NS_XS_URI = "http://www.w3.org/2001/XMLSchema";
+
+ /**
+ * The shared item state manager instance for the workspace.
+ */
+ private final SharedItemStateManager itemMgr;
+
+ /**
+ * QueryHandler where query execution is delegated to
+ */
+ private QueryHandler handler;
+
+ /**
+ * QueryHandler of the parent search manager or null if there
+ * is none.
+ */
+ private final QueryHandler parentHandler;
+
+ /**
+ * The namespace registry of the repository.
+ */
+ private final NamespaceRegistryImpl nsReg;
+
+ /**
+ * Path that will be excluded from indexing.
+ */
+ private Path excludePath;
+
+ /**
+ * Creates a new SearchManager.
+ *
+ * @param workspace the workspace name
+ * @param repositoryContext the repository context
+ * @param qhf the query handler factory
+ * @param itemMgr the shared item state manager.
+ * @param pm the underlying persistence manager.
+ * @param rootNodeId the id of the root node.
+ * @param parentMgr the parent search manager or null if
+ * there is no parent search manager.
+ * @param excludedNodeId id of the node that should be excluded from
+ * indexing. Any descendant of that node will also be
+ * excluded from indexing.
+ * @throws RepositoryException if the search manager cannot be initialized
+ */
+ public SearchManager(
+ String workspace,
+ RepositoryContext repositoryContext,
+ QueryHandlerFactory qhf,
+ SharedItemStateManager itemMgr,
+ PersistenceManager pm,
+ NodeId rootNodeId,
+ SearchManager parentMgr,
+ NodeId excludedNodeId) throws RepositoryException {
+ this.nsReg = repositoryContext.getNamespaceRegistry();
+ this.itemMgr = itemMgr;
+ this.parentHandler = (parentMgr != null) ? parentMgr.handler : null;
+
+ // register namespaces
+ safeRegisterNamespace(NS_XS_PREFIX, NS_XS_URI);
+ try {
+ if (nsReg.getPrefix(NS_FN_OLD_URI).equals(NS_FN_PREFIX)) {
+ // old uri is mapped to 'fn' prefix -> re-map
+ String prefix = NS_FN_OLD_PREFIX;
+ try {
+ // Find a free prefix
+ for (int i = 2; true; i++) {
+ nsReg.getURI(prefix);
+ prefix = NS_FN_OLD_PREFIX + i;
+ }
+ } catch (NamespaceException e) {
+ // Re-map the old fn URI to that prefix
+ nsReg.registerNamespace(prefix, NS_FN_OLD_URI);
+ }
+ }
+ } catch (NamespaceException e) {
+ // does not yet exist
+ safeRegisterNamespace(NS_FN_OLD_PREFIX, NS_FN_OLD_URI);
+ }
+ // at this point the 'fn' prefix shouldn't be assigned anymore
+ safeRegisterNamespace(NS_FN_PREFIX, NS_FN_URI);
+
+ if (excludedNodeId != null) {
+ HierarchyManagerImpl hmgr =
+ new HierarchyManagerImpl(rootNodeId, itemMgr);
+ excludePath = hmgr.getPath(excludedNodeId);
+ }
+
+ // initialize query handler
+ this.handler = qhf.getQueryHandler(new QueryHandlerContext(workspace,
+ repositoryContext, itemMgr, pm, rootNodeId, parentHandler,
+ excludedNodeId));
+ }
+
+ /**
+ * Registers a namespace using the given prefix hint. Does nothing
+ * if the namespace is already registered. If the given prefix hint
+ * is not yet registered as a prefix, then it is used as the prefix
+ * of the registered namespace. Otherwise a unique prefix is generated
+ * based on the given hint.
+ *
+ * @param prefixHint the prefix hint
+ * @param uri the namespace URI
+ * @throws NamespaceException if an illegal attempt is made to register
+ * a mapping
+ * @throws RepositoryException if an unexpected error occurs
+ * @see javax.jcr.NamespaceRegistry#registerNamespace(String, String)
+ */
+ private void safeRegisterNamespace(String prefixHint, String uri)
+ throws NamespaceException, RepositoryException {
+ try {
+ // Check if the namespace is already registered
+ nsReg.getPrefix(uri);
+ // ... it is, so do nothing.
+ } catch (NamespaceException e1) {
+ // ... it is not, try to find a unique prefix.
+ String prefix = prefixHint;
+ try {
+ for (int suffix = 2; true; suffix++) {
+ // Is this prefix already registered?
+ nsReg.getURI(prefix);
+ // ... it is, generate a new prefix and try again.
+ prefix = prefixHint + suffix;
+ }
+ } catch (NamespaceException e2) {
+ // ... it is not, register the namespace with this prefix.
+ nsReg.registerNamespace(prefix, uri);
+ }
+ }
+ }
+
+ /**
+ * Closes this SearchManager and also closes the
+ * {@link FileSystem} configured in {@link SearchConfig}.
+ */
+ public void close() {
+ try {
+ shutdownQueryHandler();
+ } catch (IOException e) {
+ log.error("Exception closing QueryHandler.", e);
+ }
+ }
+
+ /**
+ * Creates a query object that can be executed on the workspace.
+ *
+ * @param sessionContext component context of the current session
+ * @param statement the actual query statement.
+ * @param language the syntax of the query statement.
+ * @param node a nt:query node where the query was read from or
+ * null if it is not a stored query.
+ * @return a Query instance to execute.
+ * @throws InvalidQueryException if the query is malformed or the
+ * language is unknown.
+ * @throws RepositoryException if any other error occurs.
+ */
+ public Query createQuery(
+ SessionContext sessionContext,
+ String statement, String language, Node node)
+ throws InvalidQueryException, RepositoryException {
+ AbstractQueryImpl query = createQueryInstance();
+ query.init(sessionContext, handler, statement, language, node);
+ return query;
+ }
+
+ /**
+ * Creates a query object model that can be executed on the workspace.
+ *
+ * @param sessionContext component context of the current session
+ * @param qomTree the query object model tree, representing the query.
+ * @param langugage the original language of the query statement.
+ * @param node a nt:query node where the query was read from or
+ * null if it is not a stored query.
+ * @return the query object model for the query.
+ * @throws InvalidQueryException the the query object model tree is
+ * considered invalid by the query handler
+ * implementation.
+ * @throws RepositoryException if any other error occurs.
+ */
+ public QueryObjectModel createQueryObjectModel(
+ SessionContext sessionContext, QueryObjectModelTree qomTree,
+ String langugage, Node node)
+ throws InvalidQueryException, RepositoryException {
+ QueryObjectModelImpl qom = new QueryObjectModelImpl();
+ qom.init(sessionContext, handler, qomTree, langugage, node);
+ return qom;
+ }
+
+ /**
+ * Returns the ids of the nodes that refer to the node with id
+ * by weak references.
+ *
+ * @param id the id of the target node.
+ * @return the ids of the referring nodes.
+ * @throws RepositoryException if an error occurs.
+ * @throws IOException if an error occurs while reading from the
+ * index.
+ */
+ public Iterable getWeaklyReferringNodes(NodeId id)
+ throws RepositoryException, IOException {
+ return handler.getWeaklyReferringNodes(id);
+ }
+
+ /**
+ * Checks if the given event should be excluded based on the
+ * {@link #excludePath} setting.
+ *
+ * @param event observation event
+ * @return true if the event should be excluded,
+ * false otherwise
+ */
+ private boolean isExcluded(EventImpl event) {
+ try {
+ return excludePath != null
+ && excludePath.isAncestorOf(event.getQPath());
+ } catch (MalformedPathException ex) {
+ log.error("Error filtering events.", ex);
+ return false;
+ } catch (RepositoryException ex) {
+ log.error("Error filtering events.", ex);
+ return false;
+ }
+
+ }
+
+ //------------------------< for testing only >------------------------------
+
+ /**
+ * @return the query handler implementation.
+ */
+ public QueryHandler getQueryHandler() {
+ return handler;
+ }
+
+ //---------------< EventListener interface >--------------------------------
+
+ public void onEvent(EventIterator events) {
+ log.debug("onEvent: indexing started");
+ long time = System.currentTimeMillis();
+
+ // nodes that need to be removed from the index.
+ final Set removedNodes = new HashSet();
+ // nodes that need to be added to the index.
+ final Map addedNodes = new HashMap();
+ // property events
+ List propEvents = new ArrayList();
+
+ while (events.hasNext()) {
+ EventImpl e = (EventImpl) events.nextEvent();
+ if (!isExcluded(e)) {
+ long type = e.getType();
+ if (type == Event.NODE_ADDED) {
+ addedNodes.put(e.getChildId(), e);
+ if (e.isShareableChildNode()) {
+ // simply re-index shareable nodes
+ removedNodes.add(e.getChildId());
+ }
+ } else if (type == Event.NODE_REMOVED) {
+ removedNodes.add(e.getChildId());
+ if (e.isShareableChildNode()) {
+ // check if there is a node remaining in the shared set
+ if (itemMgr.hasItemState(e.getChildId())) {
+ addedNodes.put(e.getChildId(), e);
+ }
+ }
+ } else {
+ propEvents.add(e);
+ }
+ }
+ }
+
+ // sort out property events
+ for (EventImpl e : propEvents) {
+ NodeId nodeId = e.getParentId();
+ if (e.getType() == Event.PROPERTY_ADDED) {
+ if (addedNodes.put(nodeId, e) == null) {
+ // only property added
+ // need to re-index
+ removedNodes.add(nodeId);
+ } else {
+ // the node where this prop belongs to is also new
+ }
+ } else if (e.getType() == Event.PROPERTY_CHANGED) {
+ // need to re-index
+ addedNodes.put(nodeId, e);
+ removedNodes.add(nodeId);
+ } else {
+ // property removed event is only generated when node still exists
+ addedNodes.put(nodeId, e);
+ removedNodes.add(nodeId);
+ }
+ }
+
+ Iterator addedStates = new Iterator() {
+ private final Iterator iter = addedNodes.keySet().iterator();
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean hasNext() {
+ return iter.hasNext();
+ }
+
+ public NodeState next() {
+ NodeState item = null;
+ NodeId id = (NodeId) iter.next();
+ try {
+ item = (NodeState) itemMgr.getItemState(id);
+ } catch (ItemStateException ise) {
+ // check whether this item state change originated from
+ // an external event
+ EventImpl e = addedNodes.get(id);
+ if (e == null || !e.isExternal()) {
+ log.error("Unable to index node " + id + ": does not exist");
+ } else {
+ log.info("Node no longer available " + id + ", skipped.");
+ }
+ }
+ return item;
+ }
+ };
+ Iterator removedIds = removedNodes.iterator();
+
+ if (removedNodes.size() > 0 || addedNodes.size() > 0) {
+ try {
+ handler.updateNodes(removedIds, addedStates);
+ } catch (RepositoryException e) {
+ log.error("Error indexing node.", e);
+ } catch (IOException e) {
+ log.error("Error indexing node.", e);
+ }
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("onEvent: indexing finished in "
+ + String.valueOf(System.currentTimeMillis() - time)
+ + " ms.");
+ }
+ }
+
+ /**
+ * Creates a new instance of an {@link AbstractQueryImpl} which is not
+ * initialized.
+ *
+ * @return an new query instance.
+ * @throws RepositoryException if an error occurs while creating a new query
+ * instance.
+ */
+ protected AbstractQueryImpl createQueryInstance() throws RepositoryException {
+ try {
+ String queryImplClassName = handler.getQueryClass();
+ Object obj = Class.forName(queryImplClassName).newInstance();
+ if (obj instanceof AbstractQueryImpl) {
+ return (AbstractQueryImpl) obj;
+ } else {
+ throw new IllegalArgumentException(queryImplClassName
+ + " is not of type " + AbstractQueryImpl.class.getName());
+ }
+ } catch (Throwable t) {
+ throw new RepositoryException("Unable to create query: " + t.toString(), t);
+ }
+ }
+
+ //------------------------< internal >--------------------------------------
+
+ /**
+ * Shuts down the query handler. If the query handler is already shut down
+ * this method does nothing.
+ *
+ * @throws IOException if an error occurs while shutting down the query
+ * handler.
+ */
+ private void shutdownQueryHandler() throws IOException {
+ if (handler != null) {
+ handler.close();
+ handler = null;
+ }
+ }
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionFactory.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionFactory.java
new file mode 100644
index 00000000000..8a4e4db43f2
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionFactory.java
@@ -0,0 +1,45 @@
+/*
+ * 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.jackrabbit.core;
+
+import java.security.Principal;
+import java.util.Collections;
+
+import javax.jcr.RepositoryException;
+import javax.security.auth.Subject;
+
+import org.apache.jackrabbit.core.security.SecurityConstants;
+import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
+
+public class SessionFactory {
+
+ private final RepositoryContext context;
+
+ public SessionFactory(RepositoryContext context) {
+ this.context = context;
+ }
+
+ public SessionImpl createAdminSession(String workspace)
+ throws RepositoryException {
+ Principal admin = new AdminPrincipal(SecurityConstants.ADMIN_ID);
+ Subject subject = new Subject(
+ true, Collections.singleton(admin),
+ Collections.emptySet(), Collections.emptySet());
+ return context.getRepository().createSession(subject, workspace);
+ }
+
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
new file mode 100644
index 00000000000..fea4b42725e
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionImpl.java
@@ -0,0 +1,1371 @@
+/*
+ * 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.jackrabbit.core;
+
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_CHECKED_OUT;
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_CONSTRAINTS;
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_HOLD;
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_LOCK;
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_RETENTION;
+
+import java.io.File;
+import java.security.AccessControlException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.Credentials;
+import javax.jcr.Item;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.LoginException;
+import javax.jcr.NamespaceException;
+import javax.jcr.NoSuchWorkspaceException;
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Property;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.ValueFactory;
+import javax.jcr.Workspace;
+import javax.jcr.lock.Lock;
+import javax.jcr.lock.LockException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.observation.EventListener;
+import javax.jcr.observation.ObservationManager;
+import javax.jcr.retention.RetentionManager;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.version.VersionException;
+import javax.security.auth.Subject;
+
+import org.apache.commons.collections.IteratorUtils;
+import org.apache.commons.collections.map.ReferenceMap;
+import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.commons.AbstractSession;
+import org.apache.jackrabbit.core.config.WorkspaceConfig;
+import org.apache.jackrabbit.core.gc.GarbageCollector;
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.nodetype.NodeTypeManagerImpl;
+import org.apache.jackrabbit.core.observation.ObservationManagerImpl;
+import org.apache.jackrabbit.core.retention.RetentionManagerImpl;
+import org.apache.jackrabbit.core.retention.RetentionRegistry;
+import org.apache.jackrabbit.core.security.AMContext;
+import org.apache.jackrabbit.core.security.AccessManager;
+import org.apache.jackrabbit.core.security.SecurityConstants;
+import org.apache.jackrabbit.core.security.SystemPrincipal;
+import org.apache.jackrabbit.core.security.authentication.AuthContext;
+import org.apache.jackrabbit.core.security.authorization.Permission;
+import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
+import org.apache.jackrabbit.core.session.SessionContext;
+import org.apache.jackrabbit.core.session.SessionItemOperation;
+import org.apache.jackrabbit.core.session.SessionOperation;
+import org.apache.jackrabbit.core.session.SessionRefreshOperation;
+import org.apache.jackrabbit.core.session.SessionSaveOperation;
+import org.apache.jackrabbit.core.state.SessionItemStateManager;
+import org.apache.jackrabbit.core.version.InternalVersionManager;
+import org.apache.jackrabbit.core.xml.ImportHandler;
+import org.apache.jackrabbit.core.xml.SessionImporter;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.commons.SessionExtensions;
+import org.apache.jackrabbit.spi.commons.conversion.DefaultNamePathResolver;
+import org.apache.jackrabbit.spi.commons.conversion.IdentifierResolver;
+import org.apache.jackrabbit.spi.commons.conversion.IllegalNameException;
+import org.apache.jackrabbit.spi.commons.conversion.MalformedPathException;
+import org.apache.jackrabbit.spi.commons.conversion.NameException;
+import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
+import org.apache.jackrabbit.spi.commons.name.NameConstants;
+import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver;
+import org.apache.jackrabbit.util.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.ContentHandler;
+
+/**
+ * A SessionImpl ...
+ */
+public class SessionImpl extends AbstractSession
+ implements JackrabbitSession, SessionExtensions, NamespaceResolver, NamePathResolver, IdentifierResolver {
+
+ /**
+ * Name of the session attribute that controls whether the
+ * {@link #refresh(boolean)} method will cause the repository to
+ * synchronize itself to changes in other cluster nodes. This cluster
+ * synchronization is enabled by default, unless an attribute with this
+ * name is set (any non-null value) for this session.
+ *
+ * @since Apache Jackrabbit 1.6
+ * @see JCR-1753
+ */
+ public static final String DISABLE_CLUSTER_SYNC_ON_REFRESH =
+ "org.apache.jackrabbit.disableClusterSyncOnRefresh";
+
+ /**
+ * Name of the session attribute that controls whether repository
+ * inconsistencies should be automatically fixed when traversing over child
+ * nodes, when trying to add a child node, or removing a child node.
+ *
+ * @since Apache Jackrabbit 2.2
+ * @see JCR-2740
+ */
+ public static final String AUTO_FIX_CORRUPTIONS =
+ "org.apache.jackrabbit.autoFixCorruptions";
+
+ private static Logger log = LoggerFactory.getLogger(SessionImpl.class);
+
+ /**
+ * Session counter. Used to generate unique internal session names.
+ */
+ private static final AtomicLong SESSION_COUNTER = new AtomicLong();
+
+ /**
+ * The component context of this session.
+ */
+ protected final SessionContext context;
+
+ /**
+ * The component context of the repository that issued this session.
+ */
+ protected final RepositoryContext repositoryContext;
+
+ /**
+ * the AuthContext of this session (can be null if this
+ * session was not instantiated through a login process)
+ */
+ protected AuthContext loginContext;
+
+ /**
+ * the Subject of this session
+ */
+ protected final Subject subject;
+
+ /**
+ * the user ID that was used to acquire this session
+ */
+ protected final String userId;
+
+ /**
+ * Unique internal name of this session. Returned by the
+ * {@link #toString()} method for use in logging and debugging.
+ */
+ private final String sessionName;
+
+ /**
+ * the attributes of this session
+ */
+ protected final Map attributes =
+ new HashMap();
+
+ /**
+ * Name and Path resolver
+ */
+ protected NamePathResolver namePathResolver;
+
+ /**
+ * The version manager for this session
+ */
+ protected final InternalVersionManager versionMgr;
+
+ /**
+ * Listeners (weak references)
+ */
+ @SuppressWarnings("unchecked")
+ protected final Map listeners =
+ new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK);
+
+ /**
+ * Principal Manager
+ */
+ private PrincipalManager principalManager;
+
+ /**
+ * User Manager
+ */
+ private UserManager userManager;
+
+ /**
+ * Retention and Hold Manager
+ */
+ private RetentionManager retentionManager;
+
+ /**
+ * The stack trace knows who opened this session. It is logged
+ * if the session is finalized, but Session.logout() was never called.
+ */
+ private Exception openStackTrace = new Exception("Stack Trace");
+
+ /**
+ * Protected constructor.
+ *
+ * @param repositoryContext repository context
+ * @param loginContext
+ * @param wspConfig
+ * @throws AccessDeniedException if the subject of the given login context
+ * is not granted access to the specified
+ * workspace
+ * @throws RepositoryException if another error occurs
+ */
+ protected SessionImpl(
+ RepositoryContext repositoryContext, AuthContext loginContext,
+ WorkspaceConfig wspConfig)
+ throws AccessDeniedException, RepositoryException {
+ this(repositoryContext, loginContext.getSubject(), wspConfig);
+ this.loginContext = loginContext;
+ }
+
+ /**
+ * Protected constructor.
+ *
+ * @param repositoryContext repository context
+ * @param subject
+ * @param wspConfig
+ * @throws AccessDeniedException if the given subject is not granted access
+ * to the specified workspace
+ * @throws RepositoryException if another error occurs
+ */
+ protected SessionImpl(
+ RepositoryContext repositoryContext, Subject subject,
+ WorkspaceConfig wspConfig)
+ throws AccessDeniedException, RepositoryException {
+ this.context = new SessionContext(repositoryContext, this, wspConfig);
+ this.repositoryContext = repositoryContext;
+ this.subject = subject;
+
+ this.userId = retrieveUserId(subject, wspConfig.getName());
+ long count = SESSION_COUNTER.incrementAndGet();
+ if (userId != null) {
+ String user = Text.escapeIllegalJcrChars(userId);
+ this.sessionName = "session-" + user + "-" + count;
+ } else {
+ this.sessionName = "session-" + count;
+ }
+
+ namePathResolver = new DefaultNamePathResolver(this, this, true);
+ context.setItemStateManager(createSessionItemStateManager());
+ context.setItemManager(createItemManager());
+ context.setAccessManager(createAccessManager(subject));
+ context.setObservationManager(
+ createObservationManager(wspConfig.getName()));
+
+ versionMgr = createVersionManager();
+ }
+
+ /**
+ * Retrieve the userID from the specified subject.
+ *
+ * @return the userID.
+ */
+ protected String retrieveUserId(Subject subject, String workspaceName) throws RepositoryException {
+ return repositoryContext.getSecurityManager().getUserID(
+ subject, workspaceName);
+ }
+
+ /**
+ * Create the session item state manager.
+ *
+ * @return session item state manager
+ */
+ protected SessionItemStateManager createSessionItemStateManager() {
+ SessionItemStateManager mgr = new SessionItemStateManager(
+ context.getRootNodeId(),
+ context.getWorkspace().getItemStateManager());
+ context.getWorkspace().getItemStateManager().addListener(mgr);
+ return mgr;
+ }
+
+ /**
+ * Create the item manager.
+ * @return item manager
+ */
+ protected ItemManager createItemManager() {
+ ItemManager mgr = new ItemManager(context);
+ context.getItemStateManager().addListener(mgr);
+ return mgr;
+ }
+
+ protected ObservationManagerImpl createObservationManager(String wspName)
+ throws RepositoryException {
+ try {
+ return new ObservationManagerImpl(
+ context.getRepository().getObservationDispatcher(wspName),
+ this, context.getRepositoryContext().getClusterNode());
+ } catch (NoSuchWorkspaceException e) {
+ // should never get here
+ throw new RepositoryException(
+ "Internal error: failed to create observation manager", e);
+ }
+ }
+ /**
+ * Create the version manager. If we are not using XA, we may safely use
+ * the repository version manager.
+ * @return version manager
+ */
+ protected InternalVersionManager createVersionManager()
+ throws RepositoryException {
+ return context.getRepositoryContext().getInternalVersionManager();
+ }
+
+ /**
+ * Create the access manager.
+ *
+ * @param subject
+ * @return access manager
+ * @throws AccessDeniedException if the current subject is not granted access
+ * to the current workspace
+ * @throws RepositoryException if the access manager cannot be instantiated
+ */
+ protected AccessManager createAccessManager(Subject subject)
+ throws AccessDeniedException, RepositoryException {
+ String wspName = getWorkspace().getName();
+ AMContext ctx = new AMContext(
+ new File(context.getRepository().getConfig().getHomeDir()),
+ context.getRepositoryContext().getFileSystem(),
+ this,
+ subject,
+ context.getHierarchyManager(),
+ context.getPrivilegeManager(),
+ this,
+ wspName);
+ return repositoryContext.getSecurityManager().getAccessManager(this, ctx);
+ }
+
+ private T perform(SessionOperation operation)
+ throws RepositoryException {
+ return context.getSessionState().perform(operation);
+ }
+
+ /**
+ * Performs a sanity check on this session.
+ *
+ * @throws RepositoryException if this session has been rendered invalid
+ * for some reason (e.g. if this session has
+ * been closed explicitly or if it has expired)
+ */
+ private void sanityCheck() throws RepositoryException {
+ context.getSessionState().checkAlive();
+ }
+
+ /**
+ * Returns a read only copy of the Subject associated with this
+ * session.
+ *
+ * @return a read only copy of Subject associated with this session
+ */
+ public Subject getSubject() {
+ Subject readOnly = new Subject(true, subject.getPrincipals(), subject.getPublicCredentials(), subject.getPrivateCredentials());
+ return readOnly;
+ }
+
+ /**
+ * Returns true if the subject contains a
+ * SystemPrincipal; false otherwise.
+ *
+ * @return true if this is an system session.
+ */
+ public boolean isSystem() {
+ // NOTE: for backwards compatibility evaluate subject for containing SystemPrincipal
+ // TODO: Q: shouldn't 'isSystem' rather be covered by instances of SystemSession only?
+ return (subject != null && !subject.getPrincipals(SystemPrincipal.class).isEmpty());
+ }
+
+ /**
+ * Returns true if this session has been created for the
+ * administrator. False otherwise.
+ *
+ * @return true if this is an admin session.
+ */
+ public boolean isAdmin() {
+ // NOTE: don't replace by getUserManager()
+ if (userManager != null) {
+ try {
+ Authorizable a = userManager.getAuthorizable(userId);
+ if (a != null && !a.isGroup()) {
+ return ((User) a).isAdmin();
+ }
+ } catch (RepositoryException e) {
+ // no user management -> use fallback
+ }
+
+ }
+ // fallback: user manager not yet initialized or user mgt not supported
+ // -> check for AdminPrincipal being present in the subject.
+ return (subject != null && !subject.getPrincipals(AdminPrincipal.class).isEmpty());
+ }
+
+ /**
+ * Creates a new session with the same subject as this sessions but to a
+ * different workspace. The returned session is a newly logged in session,
+ * with the same subject but a different workspace. Even if the given
+ * workspace is the same as this sessions one, the implementation must
+ * return a new session object.
+ *
+ * @param workspaceName name of the workspace to acquire a session for.
+ * @return A session to the requested workspace for the same authenticated
+ * subject.
+ * @throws AccessDeniedException in case the current Subject is not allowed
+ * to access the requested Workspace
+ * @throws NoSuchWorkspaceException If the named workspace does not exist.
+ * @throws RepositoryException in any other exceptional state
+ */
+ public Session createSession(String workspaceName)
+ throws AccessDeniedException, NoSuchWorkspaceException, RepositoryException {
+ if (workspaceName == null) {
+ workspaceName =
+ repositoryContext.getWorkspaceManager().getDefaultWorkspaceName();
+ }
+ Subject newSubject = new Subject(subject.isReadOnly(), subject.getPrincipals(), subject.getPublicCredentials(), subject.getPrivateCredentials());
+ return repositoryContext.getWorkspaceManager().createSession(
+ newSubject, workspaceName);
+ }
+
+ /**
+ * Returns the AccessManager associated with this session.
+ *
+ * @return the AccessManager associated with this session
+ */
+ public AccessManager getAccessManager() {
+ return context.getAccessManager();
+ }
+
+ /**
+ * Returns the NodeTypeManager.
+ *
+ * @return the NodeTypeManager
+ */
+ public NodeTypeManagerImpl getNodeTypeManager() {
+ return context.getNodeTypeManager();
+ }
+
+ /**
+ * Returns the ItemManager of this session.
+ *
+ * @return the ItemManager
+ */
+ public ItemManager getItemManager() {
+ return context.getItemManager();
+ }
+
+ /**
+ * Returns the HierarchyManager associated with this session.
+ *
+ * @return the HierarchyManager associated with this session
+ */
+ public HierarchyManager getHierarchyManager() {
+ return context.getHierarchyManager();
+ }
+
+ /**
+ * Returns the InternalVersionManager associated with this session.
+ *
+ * @return the InternalVersionManager associated with this session
+ */
+ public InternalVersionManager getInternalVersionManager() {
+ return versionMgr;
+ }
+
+
+ /**
+ * Returns the internal retention manager used for evaluation of effective
+ * retention policies and holds.
+ *
+ * @return internal retention manager
+ * @throws RepositoryException
+ */
+ protected RetentionRegistry getRetentionRegistry() throws RepositoryException {
+ return context.getWorkspace().getRetentionRegistry();
+ }
+
+ /**
+ * Sets the named attribute. If the value is null, then
+ * the named attribute is removed.
+ *
+ * @see JCR-1932
+ * @param name attribute name
+ * @param value attribute value
+ * @since Apache Jackrabbit 1.6
+ */
+ public void setAttribute(String name, Object value) {
+ if (value != null) {
+ attributes.put(name, value);
+ } else {
+ attributes.remove(name);
+ }
+ }
+
+ /**
+ * Retrieves the Node with the given id.
+ *
+ * @param id id of node to be retrieved
+ * @return node with the given NodeId.
+ * @throws ItemNotFoundException if no such node exists or if this
+ * Session does not have permission to access the node.
+ * @throws RepositoryException if another error occurs.
+ */
+ public NodeImpl getNodeById(NodeId id) throws ItemNotFoundException, RepositoryException {
+ // check sanity of this session
+ sanityCheck();
+
+ try {
+ return (NodeImpl) getItemManager().getItem(id);
+ } catch (AccessDeniedException ade) {
+ throw new ItemNotFoundException(id.toString());
+ }
+ }
+
+ /**
+ * Notify the listeners that this session is about to be closed.
+ */
+ protected void notifyLoggingOut() {
+ // copy listeners to array to avoid ConcurrentModificationException
+ List copy =
+ new ArrayList(listeners.values());
+ for (SessionListener listener : copy) {
+ if (listener != null) {
+ listener.loggingOut(this);
+ }
+ }
+ }
+
+ /**
+ * Notify the listeners that this session has been closed.
+ */
+ protected void notifyLoggedOut() {
+ // copy listeners to array to avoid ConcurrentModificationException
+ List copy =
+ new ArrayList(listeners.values());
+ for (SessionListener listener : copy) {
+ if (listener != null) {
+ listener.loggedOut(this);
+ }
+ }
+ }
+
+ /**
+ * Add a SessionListener
+ *
+ * @param listener the new listener to be informed on modifications
+ */
+ public void addListener(SessionListener listener) {
+ if (!listeners.containsKey(listener)) {
+ listeners.put(listener, listener);
+ }
+ }
+
+ /**
+ * Remove a SessionListener
+ *
+ * @param listener an existing listener
+ */
+ public void removeListener(SessionListener listener) {
+ listeners.remove(listener);
+ }
+
+ /**
+ * Create a data store garbage collector for this repository.
+ *
+ * @throws RepositoryException
+ */
+ public GarbageCollector createDataStoreGarbageCollector() throws RepositoryException {
+ final GarbageCollector gc =
+ repositoryContext.getRepository().createDataStoreGarbageCollector();
+ // Auto-close if the main session logs out
+ addListener(new SessionListener() {
+ public void loggedOut(SessionImpl session) {
+ }
+ public void loggingOut(SessionImpl session) {
+ gc.close();
+ }
+ });
+ return gc;
+ }
+
+ //---------------------------------------------------< NamespaceResolver >
+
+ public String getPrefix(String uri) throws NamespaceException {
+ try {
+ return getNamespacePrefix(uri);
+ } catch (NamespaceException e) {
+ throw e;
+ } catch (RepositoryException e) {
+ throw new NamespaceException("Namespace not found: " + uri, e);
+ }
+ }
+
+ public String getURI(String prefix) throws NamespaceException {
+ try {
+ return getNamespaceURI(prefix);
+ } catch (NamespaceException e) {
+ throw e;
+ } catch (RepositoryException e) {
+ throw new NamespaceException("Namespace not found: " + prefix, e);
+ }
+ }
+
+ //--------------------------------------------------------< NameResolver >
+
+ public String getJCRName(Name name) throws NamespaceException {
+ return namePathResolver.getJCRName(name);
+ }
+
+ public Name getQName(String name) throws IllegalNameException, NamespaceException {
+ return namePathResolver.getQName(name);
+ }
+
+ //--------------------------------------------------------< PathResolver >
+
+ public String getJCRPath(Path path) throws NamespaceException {
+ return namePathResolver.getJCRPath(path);
+ }
+
+ public Path getQPath(String path) throws MalformedPathException, IllegalNameException, NamespaceException {
+ return namePathResolver.getQPath(path);
+ }
+
+ public Path getQPath(String path, boolean normalizeIdentifier) throws MalformedPathException, IllegalNameException, NamespaceException {
+ return namePathResolver.getQPath(path, normalizeIdentifier);
+ }
+
+ //---------------------------------------------------< IdentifierResolver >
+ /**
+ * @see IdentifierResolver#getPath(String)
+ */
+ public Path getPath(String identifier) throws MalformedPathException {
+ try {
+ return context.getHierarchyManager().getPath(NodeId.valueOf(identifier));
+ } catch (RepositoryException e) {
+ throw new MalformedPathException("Identifier '" + identifier + "' cannot be resolved.");
+ }
+ }
+
+ /**
+ * @see IdentifierResolver#checkFormat(String)
+ */
+ public void checkFormat(String identifier) throws MalformedPathException {
+ try {
+ NodeId.valueOf(identifier);
+ } catch (IllegalArgumentException e) {
+ throw new MalformedPathException("Invalid identifier: " + identifier);
+ }
+ }
+
+ //----------------------------------------------------< JackrabbitSession >
+ /**
+ * @see JackrabbitSession#hasPermission(String, String...)
+ */
+ @Override
+ public boolean hasPermission(String absPath, String... actions) throws RepositoryException {
+ return hasPermission(absPath, Text.implode(actions, ","));
+ }
+
+ /**
+ * @see JackrabbitSession#getPrincipalManager()
+ */
+ public PrincipalManager getPrincipalManager() throws RepositoryException, AccessDeniedException {
+ if (principalManager == null) {
+ principalManager =
+ repositoryContext.getSecurityManager().getPrincipalManager(this);
+ }
+ return principalManager;
+ }
+
+ /**
+ * @see JackrabbitSession#getUserManager()
+ */
+ public UserManager getUserManager() throws AccessDeniedException, RepositoryException {
+ if (userManager == null) {
+ userManager =
+ repositoryContext.getSecurityManager().getUserManager(this);
+ }
+ return userManager;
+ }
+
+ @Override
+ public Item getItemOrNull(String absPath) throws RepositoryException {
+ // TODO optimise, reduce to a single read operation
+ if (itemExists(absPath)) {
+ return getItem(absPath);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public Property getPropertyOrNull(String absPath) throws RepositoryException {
+ // TODO optimise, reduce to a single read operation
+ if (propertyExists(absPath)) {
+ return getProperty(absPath);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public Node getNodeOrNull(String absPath) throws RepositoryException {
+ // TODO optimise, reduce to a single read operation
+ if (nodeExists(absPath)) {
+ return getNode(absPath);
+ } else {
+ return null;
+ }
+ }
+
+ //--------------------------------------------------------------< Session >
+ /**
+ * {@inheritDoc}
+ */
+ public void checkPermission(String absPath, String actions)
+ throws AccessControlException, RepositoryException {
+ if (!hasPermission(absPath, actions)) {
+ throw new AccessControlException(actions);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Workspace getWorkspace() {
+ return context.getWorkspace();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Session impersonate(Credentials otherCredentials)
+ throws LoginException, RepositoryException {
+ // check sanity of this session
+ sanityCheck();
+
+ if (!(otherCredentials instanceof SimpleCredentials)) {
+ String msg = "impersonate failed: incompatible credentials, SimpleCredentials expected";
+ log.debug(msg);
+ throw new RepositoryException(msg);
+ }
+
+ // set IMPERSONATOR_ATTRIBUTE attribute of given credentials
+ // with subject of current session
+ SimpleCredentials creds = (SimpleCredentials) otherCredentials;
+ creds.setAttribute(SecurityConstants.IMPERSONATOR_ATTRIBUTE, subject);
+
+ try {
+ return getRepository().login(
+ otherCredentials, getWorkspace().getName());
+ } catch (NoSuchWorkspaceException nswe) {
+ // should never get here...
+ String msg = "impersonate failed";
+ log.error(msg, nswe);
+ throw new RepositoryException(msg, nswe);
+ } finally {
+ // make sure IMPERSONATOR_ATTRIBUTE is removed
+ creds.removeAttribute(SecurityConstants.IMPERSONATOR_ATTRIBUTE);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Node getRootNode() throws RepositoryException {
+ // check sanity of this session
+ sanityCheck();
+
+ return getItemManager().getRootNode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Node getNodeByUUID(String uuid) throws ItemNotFoundException, RepositoryException {
+ try {
+ NodeImpl node = getNodeById(new NodeId(uuid));
+ if (node.isNodeType(NameConstants.MIX_REFERENCEABLE)) {
+ return node;
+ } else {
+ // there is a node with that uuid but the node does not expose it
+ throw new ItemNotFoundException(uuid);
+ }
+ } catch (IllegalArgumentException e) {
+ // Assuming the exception is from UUID.fromString()
+ throw new RepositoryException("Invalid UUID: " + uuid, e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Item getItem(String absPath) throws RepositoryException {
+ return perform(SessionItemOperation.getItem(absPath));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean itemExists(String absPath) throws RepositoryException {
+ if (absPath != null && absPath.startsWith("[") && absPath.endsWith("]")) {
+ // an identifier segment has been specified (JCR-3014)
+ try {
+ NodeId id = NodeId.valueOf(absPath.substring(1, absPath.length() - 1));
+ return getItemManager().itemExists(id);
+ } catch (IllegalArgumentException e) {
+ throw new MalformedPathException(absPath);
+ }
+ }
+ return perform(SessionItemOperation.itemExists(absPath));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void save() throws RepositoryException {
+ // JCR-3131: no need to perform save op when there's nothing to save...
+ if (context.getItemStateManager().hasAnyTransientItemStates()) {
+ perform(new SessionSaveOperation());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void refresh(boolean keepChanges) throws RepositoryException {
+ perform(new SessionRefreshOperation(
+ keepChanges, clusterSyncOnRefresh()));
+ }
+
+ /**
+ * Checks whether the {@link #refresh(boolean)} method should cause
+ * cluster synchronization.
+ *
+ * Subclasses can override this method to implement alternative
+ * rules on when cluster synchronization should be done.
+ *
+ * @return true if the {@link #DISABLE_CLUSTER_SYNC_ON_REFRESH}
+ * attribute is not set, false otherwise
+ * @since Apache Jackrabbit 1.6
+ * @see JCR-1753
+ */
+ protected boolean clusterSyncOnRefresh() {
+ return getAttribute(DISABLE_CLUSTER_SYNC_ON_REFRESH) == null;
+ }
+
+ /**
+ * Checks whether repository inconsistencies should be automatically fixed
+ * when traversing over child nodes, when trying to add a child node, or
+ * when removing a child node.
+ *
+ * @return true if the {@link #AUTO_FIX_CORRUPTIONS}
+ * attribute is set, false otherwise
+ * @since Apache Jackrabbit 2.2
+ * @see JCR-2740
+ */
+ protected boolean autoFixCorruptions() {
+ return getAttribute(AUTO_FIX_CORRUPTIONS) != null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasPendingChanges() throws RepositoryException {
+ // check sanity of this session
+ sanityCheck();
+
+ return context.getItemStateManager().hasAnyTransientItemStates();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void move(String srcAbsPath, String destAbsPath)
+ throws RepositoryException {
+ perform(new SessionMoveOperation(this, srcAbsPath, destAbsPath));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ContentHandler getImportContentHandler(String parentAbsPath,
+ int uuidBehavior)
+ throws PathNotFoundException, ConstraintViolationException,
+ VersionException, LockException, RepositoryException {
+ // check sanity of this session
+ sanityCheck();
+
+ NodeImpl parent;
+ try {
+ Path p = getQPath(parentAbsPath).getNormalizedPath();
+ if (!p.isAbsolute()) {
+ throw new RepositoryException("not an absolute path: " + parentAbsPath);
+ }
+ parent = getItemManager().getNode(p);
+ } catch (NameException e) {
+ String msg = parentAbsPath + ": invalid path";
+ log.debug(msg);
+ throw new RepositoryException(msg, e);
+ } catch (AccessDeniedException ade) {
+ throw new PathNotFoundException(parentAbsPath);
+ }
+
+ // verify that parent node is checked-out, not locked and not protected
+ // by either node type constraints nor by some retention or hold.
+ int options = ItemValidator.CHECK_LOCK | ItemValidator.CHECK_CHECKED_OUT |
+ ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD | ItemValidator.CHECK_RETENTION;
+ context.getItemValidator().checkModify(parent, options, Permission.NONE);
+
+ SessionImporter importer = new SessionImporter(
+ parent, this, uuidBehavior,
+ context.getWorkspace().getConfig().getImportConfig());
+ return new ImportHandler(importer, this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isLive() {
+ return context.getSessionState().isAlive();
+ }
+
+ /**
+ * Utility method that removes all registered event listeners.
+ */
+ private void removeRegisteredEventListeners() {
+ try {
+ ObservationManager manager = getWorkspace().getObservationManager();
+ // Use a copy to avoid modifying the set of registered listeners
+ // while iterating over it
+ Collection listeners =
+ IteratorUtils.toList(manager.getRegisteredEventListeners());
+ for (EventListener listener : listeners) {
+ try {
+ manager.removeEventListener(listener);
+ } catch (RepositoryException e) {
+ log.warn("Error removing event listener: " + listener, e);
+ }
+ }
+ } catch (RepositoryException e) {
+ log.warn("Error removing event listeners", e);
+ }
+ }
+
+ /**
+ * Invalidates this session and releases all associated resources.
+ */
+ @Override
+ public void logout() {
+ if (context.getSessionState().close()) {
+ // JCR-798: Remove all registered event listeners to avoid concurrent
+ // access to session internals by the event delivery or even listeners
+ removeRegisteredEventListeners();
+
+ // discard any pending changes first as those might
+ // interfere with subsequent operations
+ context.getItemStateManager().disposeAllTransientItemStates();
+
+ // notify listeners that session is about to be closed
+ notifyLoggingOut();
+
+ context.getPrivilegeManager().dispose();
+ context.getNodeTypeManager().dispose();
+ // dispose session item state manager
+ context.getItemStateManager().dispose();
+ // dispose item manager
+ context.getItemManager().dispose();
+ // dispose workspace
+ context.getWorkspace().dispose();
+
+ // logout JAAS subject
+ if (loginContext != null) {
+ try {
+ loginContext.logout();
+ } catch (javax.security.auth.login.LoginException le) {
+ log.warn("failed to logout current subject: " + le.getMessage());
+ }
+ loginContext = null;
+ }
+
+ try {
+ context.getAccessManager().close();
+ } catch (Exception e) {
+ log.warn("error while closing AccessManager", e);
+ }
+
+ // finally notify listeners that session has been closed
+ notifyLoggedOut();
+ }
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public Repository getRepository() {
+ return repositoryContext.getRepository();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ValueFactory getValueFactory() {
+ return context.getValueFactory();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String getUserID() {
+ return userId;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Object getAttribute(String name) {
+ return attributes.get(name);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String[] getAttributeNames() {
+ return attributes.keySet().toArray(new String[attributes.size()]);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setNamespacePrefix(String prefix, String uri)
+ throws NamespaceException, RepositoryException {
+ super.setNamespacePrefix(prefix, uri);
+ // Clear name and path caches
+ namePathResolver = new DefaultNamePathResolver(this, true);
+ }
+
+
+ //------------------------------------------------------< locking support >
+ /**
+ * {@inheritDoc}
+ */
+ public void addLockToken(String lt) {
+ try {
+ getWorkspace().getLockManager().addLockToken(lt);
+ } catch (RepositoryException e) {
+ log.debug("Error while adding lock token.");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public String[] getLockTokens() {
+ try {
+ return getWorkspace().getLockManager().getLockTokens();
+ } catch (RepositoryException e) {
+ log.debug("Error while accessing lock tokens.");
+ return new String[0];
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void removeLockToken(String lt) {
+ try {
+ getWorkspace().getLockManager().removeLockToken(lt);
+ } catch (RepositoryException e) {
+ log.debug("Error while removing lock token.");
+ }
+ }
+
+ /**
+ * Returns all locks owned by this session.
+ *
+ * @return an array of Locks
+ */
+ public Lock[] getLocks() {
+ // check sanity of this session
+ //sanityCheck();
+ if (!isLive()) {
+ log.error("failed to retrieve locks: session has been closed");
+ return new Lock[0];
+ }
+
+ try {
+ return context.getWorkspace().getInternalLockManager().getLocks(this);
+ } catch (RepositoryException e) {
+ log.error("Lock manager not available.", e);
+ return new Lock[0];
+ }
+ }
+
+ //--------------------------------------------------< new JSR 283 methods >
+ /**
+ * @see javax.jcr.Session#getNodeByIdentifier(String)
+ * @since JCR 2.0
+ */
+ public Node getNodeByIdentifier(String id)
+ throws ItemNotFoundException, RepositoryException {
+ NodeId nodeId;
+ try {
+ nodeId = NodeId.valueOf(id);
+ } catch (IllegalArgumentException iae) {
+ throw new RepositoryException("invalid identifier: " + id,iae);
+ }
+ return getNodeById(nodeId);
+ }
+
+ /**
+ * @see javax.jcr.Session#getNode(String)
+ * @since JCR 2.0
+ */
+ @Override
+ public Node getNode(String absPath) throws RepositoryException {
+ return perform(SessionItemOperation.getNode(absPath));
+ }
+
+ /**
+ * @see javax.jcr.Session#getProperty(String)
+ * @since JCR 2.0
+ */
+ @Override
+ public Property getProperty(String absPath) throws RepositoryException {
+ return perform(SessionItemOperation.getProperty(absPath));
+ }
+
+ /**
+ * @see javax.jcr.Session#nodeExists(String)
+ * @since JCR 2.0
+ */
+ @Override
+ public boolean nodeExists(String absPath) throws RepositoryException {
+ if (absPath != null && absPath.startsWith("[") && absPath.endsWith("]")) {
+ // an identifier segment has been specified (JCR-3014)
+ try {
+ NodeId id = NodeId.valueOf(absPath.substring(1, absPath.length() - 1));
+ return getItemManager().itemExists(id);
+ } catch (IllegalArgumentException e) {
+ throw new MalformedPathException(absPath);
+ }
+ }
+ return perform(SessionItemOperation.nodeExists(absPath));
+ }
+
+ /**
+ * @see javax.jcr.Session#propertyExists(String)
+ * @since JCR 2.0
+ */
+ @Override
+ public boolean propertyExists(String absPath) throws RepositoryException {
+ return perform(SessionItemOperation.propertyExists(absPath));
+ }
+
+ /**
+ * @see javax.jcr.Session#removeItem(String)
+ * @since JCR 2.0
+ */
+ @Override
+ public void removeItem(String absPath) throws RepositoryException {
+ perform(SessionItemOperation.remove(absPath));
+ }
+
+ /**
+ * @see javax.jcr.Session#hasPermission(String, String)
+ * @since 2.0
+ */
+ public boolean hasPermission(String absPath, String actions) throws RepositoryException {
+ // check sanity of this session
+ sanityCheck();
+ Path path = getQPath(absPath).getNormalizedPath();
+ // test if path is absolute
+ if (!path.isAbsolute()) {
+ throw new RepositoryException("Absolute path expected. Was:" + absPath);
+ }
+
+ Set s = new HashSet(Arrays.asList(actions.split(",")));
+ int permissions = 0;
+ if (s.remove(ACTION_READ)) {
+ permissions |= Permission.READ;
+ }
+ if (s.remove(ACTION_ADD_NODE)) {
+ permissions |= Permission.ADD_NODE;
+ }
+ if (s.remove(ACTION_SET_PROPERTY)) {
+ permissions |= Permission.SET_PROPERTY;
+ }
+ if (s.remove(ACTION_REMOVE)) {
+ if (nodeExists(absPath)) {
+ permissions |= (propertyExists(absPath)) ?
+ (Permission.REMOVE_NODE | Permission.REMOVE_PROPERTY) :
+ Permission.REMOVE_NODE;
+ } else if (propertyExists(absPath)) {
+ permissions |= Permission.REMOVE_PROPERTY;
+ } else {
+ // item doesn't exist -> check both permissions
+ permissions = Permission.REMOVE_NODE | Permission.REMOVE_PROPERTY;
+ }
+ }
+ if (!s.isEmpty()) {
+ throw new IllegalArgumentException("Unknown actions: " + s);
+ }
+ try {
+ return context.getAccessManager().isGranted(path, permissions);
+ } catch (AccessDeniedException e) {
+ return false;
+ }
+ }
+
+ /**
+ * @see javax.jcr.Session#hasCapability(String, Object, Object[])
+ * @since JCR 2.0
+ */
+ public boolean hasCapability(String methodName, Object target, Object[] arguments)
+ throws RepositoryException {
+ // value of this method (as currently spec'ed) to jcr api clients
+ // is rather limited...
+
+ // here's therefore a minimal rather than best effort implementation;
+ // returning true is always fine according to the spec...
+ ItemValidator validator = context.getItemValidator();
+ int options =
+ CHECK_CHECKED_OUT | CHECK_LOCK | CHECK_CONSTRAINTS
+ | CHECK_HOLD | CHECK_RETENTION;
+ if (target instanceof Node) {
+ if (methodName.equals("addNode")
+ || methodName.equals("addMixin")
+ || methodName.equals("orderBefore")
+ || methodName.equals("removeMixin")
+ || methodName.equals("removeShare")
+ || methodName.equals("removeSharedSet")
+ || methodName.equals("setPrimaryType")
+ || methodName.equals("setProperty")
+ || methodName.equals("update")) {
+ return validator.canModify((ItemImpl) target, options, Permission.NONE);
+ } else if (methodName.equals("remove")) {
+ try {
+ validator.checkRemove((ItemImpl) target, options, Permission.NONE);
+ } catch (RepositoryException e) {
+ return false;
+ }
+ }
+ } else if (target instanceof Property) {
+ if (methodName.equals("setValue")
+ || methodName.equals("save")) {
+ return validator.canModify((ItemImpl) target, options, Permission.NONE);
+ } else if (methodName.equals("remove")) {
+ try {
+ validator.checkRemove((ItemImpl) target, options, Permission.NONE);
+ } catch (RepositoryException e) {
+ return false;
+ }
+ }
+// TODO: Add minimal, best effort checks for Workspace and Session operations
+// } else if (target instanceof Workspace) {
+// if (methodName.equals("clone")
+// || methodName.equals("copy")
+// || methodName.equals("createWorkspace")
+// || methodName.equals("deleteWorkspace")
+// || methodName.equals("getImportContentHandler")
+// || methodName.equals("importXML")
+// || methodName.equals("move")) {
+// // TODO minimal, best effort checks (e.g. permissions for write methods etc)
+// }
+// } else if (target instanceof Session) {
+// if (methodName.equals("clone")
+// || methodName.equals("removeItem")
+// || methodName.equals("getImportContentHandler")
+// || methodName.equals("importXML")
+// || methodName.equals("save")) {
+// // TODO minimal, best effort checks (e.g. permissions for write methods etc)
+// }
+ }
+
+ // we're unable to evaluate capability, return true (staying on the safe side)
+ return true;
+ }
+
+ /**
+ * @see javax.jcr.Session#getAccessControlManager()
+ * @since JCR 2.0
+ */
+ public AccessControlManager getAccessControlManager()
+ throws UnsupportedRepositoryOperationException, RepositoryException {
+ AccessManager accessMgr = context.getAccessManager();
+ if (accessMgr instanceof AccessControlManager) {
+ return (AccessControlManager) accessMgr;
+ } else {
+ throw new UnsupportedRepositoryOperationException(
+ "Access control discovery is not supported.");
+ }
+ }
+
+ /**
+ * @see javax.jcr.Session#getRetentionManager()
+ * @since JCR 2.0
+ */
+ public RetentionManager getRetentionManager()
+ throws UnsupportedRepositoryOperationException, RepositoryException {
+ // check sanity of this session
+ sanityCheck();
+ if (retentionManager == null) {
+ // make sure the internal retention manager exists.
+ getRetentionRegistry();
+ // create the api level retention manager.
+ retentionManager = new RetentionManagerImpl(this);
+ }
+ return retentionManager;
+ }
+
+ //--------------------------------------------------------------< Object >
+
+ /**
+ * Returns the unique internal name of this session. The returned name
+ * is especially useful for debugging and logging purposes.
+ *
+ * @see #sessionName
+ * @return session name
+ */
+ @Override
+ public String toString() {
+ return sessionName;
+ }
+
+ /**
+ * Finalize the session. If the application doesn't call Session.logout(),
+ * the session is closed automatically; however a warning is written to the log file,
+ * together with the stack trace of where the session was opened.
+ */
+ @Override
+ public void finalize() {
+ if (isLive()) {
+ log.warn("Unclosed session detected. The session was opened here: ", openStackTrace);
+ logout();
+ }
+ }
+
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionListener.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionListener.java
new file mode 100644
index 00000000000..3a0ff4fceec
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionListener.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.jackrabbit.core;
+
+/**
+ * The SessionListener interface allows an implementing
+ * object to be informed about changes on a Session.
+ *
+ * @see SessionImpl#addListener
+ */
+public interface SessionListener {
+
+ /**
+ * Called when a Session is about to be 'closed' by
+ * calling {@link javax.jcr.Session#logout()}Session that is about to be 'closed'
+ */
+ void loggingOut(SessionImpl session);
+
+ /**
+ * Called when a Session has been 'closed' by
+ * calling {@link javax.jcr.Session#logout()}Session that has been 'closed'
+ */
+ void loggedOut(SessionImpl session);
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionMoveOperation.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionMoveOperation.java
new file mode 100644
index 00000000000..314ca02130c
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SessionMoveOperation.java
@@ -0,0 +1,220 @@
+/*
+ * 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.jackrabbit.core;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.ItemExistsException;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.nodetype.ConstraintViolationException;
+
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.nodetype.NodeTypeImpl;
+import org.apache.jackrabbit.core.security.AccessManager;
+import org.apache.jackrabbit.core.security.authorization.Permission;
+import org.apache.jackrabbit.core.session.SessionContext;
+import org.apache.jackrabbit.core.session.SessionWriteOperation;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.commons.conversion.NameException;
+import org.apache.jackrabbit.spi.commons.conversion.PathResolver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SessionMoveOperation implements SessionWriteOperation {
+
+ private final Logger log =
+ LoggerFactory.getLogger(SessionMoveOperation.class);
+
+ private final String srcAbsPath;
+
+ private final Path srcPath;
+
+ private final String destAbsPath;
+
+ private final Path destPath;
+
+ public SessionMoveOperation(
+ PathResolver resolver, String srcAbsPath, String destAbsPath)
+ throws RepositoryException {
+ this.srcAbsPath = srcAbsPath;
+ this.srcPath = getAbsolutePath(resolver, srcAbsPath);
+
+ this.destAbsPath = destAbsPath;
+ this.destPath = getAbsolutePath(resolver, destAbsPath);
+ if (destPath.getIndex() != Path.INDEX_UNDEFINED) {
+ // subscript in name element
+ String msg = destAbsPath + ": invalid destination path (subscript in name element is not allowed)";
+ log.debug(msg);
+ throw new RepositoryException(msg);
+ }
+
+
+ if (srcPath.isAncestorOf(destPath)) {
+ throw new RepositoryException(
+ "Destination path " + destAbsPath
+ + " cannot be descendant of source path " + srcAbsPath
+ + " in a move operation.");
+ }
+ }
+
+ private Path getAbsolutePath(PathResolver resolver, String path)
+ throws RepositoryException {
+ try {
+ Path qpath = resolver.getQPath(path).getNormalizedPath();
+ if (!qpath.isAbsolute()) {
+ throw new RepositoryException("Path is not absolute: " + path);
+ }
+ return qpath;
+ } catch (NameException e) {
+ throw new RepositoryException("Path is invalid: " + path, e);
+ }
+ }
+
+ private NodeImpl getNode(
+ SessionContext context, Path path, String absPath)
+ throws RepositoryException {
+ try {
+ return context.getItemManager().getNode(path);
+ } catch (AccessDeniedException e) {
+ throw new PathNotFoundException("Path not found: " + absPath);
+ }
+ }
+
+ public Object perform(SessionContext context) throws RepositoryException {
+ // Get node instances
+ NodeImpl targetNode = getNode(context, srcPath, srcAbsPath);
+ NodeImpl srcParentNode =
+ getNode(context, srcPath.getAncestor(1), srcAbsPath);
+ NodeImpl destParentNode =
+ getNode(context, destPath.getAncestor(1), destAbsPath);
+
+ if (context.getHierarchyManager().isShareAncestor(
+ targetNode.getNodeId(), destParentNode.getNodeId())) {
+ throw new RepositoryException(
+ "Move not possible because of a share cycle between "
+ + srcAbsPath + " and " + destAbsPath);
+ }
+
+ // check for name collisions
+ NodeImpl existing = null;
+ try {
+ existing = context.getItemManager().getNode(destPath);
+ // there's already a node with that name:
+ // check same-name sibling setting of existing node
+ if (!existing.getDefinition().allowsSameNameSiblings()) {
+ throw new ItemExistsException(
+ "Same name siblings are not allowed: " + existing);
+ }
+ } catch (AccessDeniedException ade) {
+ // FIXME by throwing ItemExistsException we're disclosing too much information
+ throw new ItemExistsException(destAbsPath);
+ } catch (PathNotFoundException pnfe) {
+ // no name collision, fall through
+ }
+
+ // verify that the targetNode can be removed
+ int options = ItemValidator.CHECK_HOLD | ItemValidator.CHECK_RETENTION;
+ context.getItemValidator().checkRemove(targetNode, options, Permission.NONE);
+
+ // verify for both source and destination parent nodes that
+ // - they are checked-out
+ // - are not protected neither by node type constraints nor by retention/hold
+ options = ItemValidator.CHECK_CHECKED_OUT | ItemValidator.CHECK_LOCK |
+ ItemValidator.CHECK_CONSTRAINTS | ItemValidator.CHECK_HOLD | ItemValidator.CHECK_RETENTION;
+ context.getItemValidator().checkModify(srcParentNode, options, Permission.NONE);
+ context.getItemValidator().checkModify(destParentNode, options, Permission.NONE);
+
+ // check constraints
+ // get applicable definition of target node at new location
+ NodeTypeImpl nt = (NodeTypeImpl) targetNode.getPrimaryNodeType();
+ org.apache.jackrabbit.spi.commons.nodetype.NodeDefinitionImpl newTargetDef;
+ try {
+ newTargetDef = destParentNode.getApplicableChildNodeDefinition(destPath.getName(), nt.getQName());
+ } catch (RepositoryException re) {
+ String msg = destAbsPath + ": no definition found in parent node's node type for new node";
+ log.debug(msg);
+ throw new ConstraintViolationException(msg, re);
+ }
+ // if there's already a node with that name also check same-name sibling
+ // setting of new node; just checking same-name sibling setting on
+ // existing node is not sufficient since same-name sibling nodes don't
+ // necessarily have identical definitions
+ if (existing != null && !newTargetDef.allowsSameNameSiblings()) {
+ throw new ItemExistsException(
+ "Same name siblings not allowed: " + existing);
+ }
+
+ NodeId targetId = targetNode.getNodeId();
+
+ // check permissions
+ AccessManager acMgr = context.getAccessManager();
+ if (!(acMgr.isGranted(srcPath, Permission.REMOVE_NODE) &&
+ acMgr.isGranted(destPath, Permission.ADD_NODE | Permission.NODE_TYPE_MNGMT))) {
+ String msg = "Not allowed to move node " + srcAbsPath + " to " + destAbsPath;
+ log.debug(msg);
+ throw new AccessDeniedException(msg);
+ }
+
+ if (srcParentNode.isSame(destParentNode)) {
+ // change definition of target
+ targetNode.onRedefine(newTargetDef.unwrap());
+ // do rename
+ destParentNode.renameChildNode(targetId, destPath.getName(), false);
+ } else {
+ // check shareable case
+ if (targetNode.getNodeState().isShareable()) {
+ String msg = "Moving a shareable node is not supported.";
+ log.debug(msg);
+ throw new UnsupportedRepositoryOperationException(msg);
+ }
+ // change definition of target
+ targetNode.onRedefine(newTargetDef.unwrap());
+
+ // Get the transient states
+ NodeState srcParentState =
+ (NodeState) srcParentNode.getOrCreateTransientItemState();
+ NodeState targetState =
+ (NodeState) targetNode.getOrCreateTransientItemState();
+ NodeState destParentState =
+ (NodeState) destParentNode.getOrCreateTransientItemState();
+
+ // do move:
+ // 1. remove child node entry from old parent
+ if (srcParentState.removeChildNodeEntry(targetId)) {
+ // 2. re-parent target node
+ targetState.setParentId(destParentNode.getNodeId());
+ // 3. add child node entry to new parent
+ destParentState.addChildNodeEntry(destPath.getName(), targetId);
+ }
+ }
+
+ return this;
+ }
+
+
+ //--------------------------------------------------------------< Object >
+
+ /**
+ * Returns a string representation of this operation.
+ */
+ public String toString() {
+ return "session.move(" + srcAbsPath + ", " + destAbsPath + ")";
+ }
+
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java
new file mode 100644
index 00000000000..b181d814f94
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/SystemSession.java
@@ -0,0 +1,326 @@
+/*
+ * 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.jackrabbit.core;
+
+import java.util.Collections;
+import java.util.Set;
+import java.security.Principal;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.security.AccessControlException;
+import javax.jcr.security.AccessControlPolicy;
+import javax.jcr.security.Privilege;
+import javax.security.auth.Subject;
+
+import org.apache.jackrabbit.api.security.authorization.PrivilegeManager;
+import org.apache.jackrabbit.core.config.WorkspaceConfig;
+import org.apache.jackrabbit.core.id.ItemId;
+import org.apache.jackrabbit.core.security.AMContext;
+import org.apache.jackrabbit.core.security.AbstractAccessControlManager;
+import org.apache.jackrabbit.core.security.AccessManager;
+import org.apache.jackrabbit.core.security.SystemPrincipal;
+import org.apache.jackrabbit.core.security.authorization.AccessControlProvider;
+import org.apache.jackrabbit.core.security.authorization.WorkspaceAccessManager;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+
+/**
+ * A SystemSession ...
+ */
+class SystemSession extends SessionImpl {
+
+ /**
+ * Package private factory method
+ *
+ * @param repositoryContext The repository context
+ * @param wspConfig The workspace configuration
+ * @return A new instance of SystemSession
+ * @throws RepositoryException If an error occurs
+ */
+ static SystemSession create(
+ RepositoryContext repositoryContext, WorkspaceConfig wspConfig)
+ throws RepositoryException {
+ // create subject with SystemPrincipal
+ Set principals = Collections.singleton(new SystemPrincipal());
+ Subject subject = new Subject(true, principals, Collections.emptySet(), Collections.emptySet());
+ return new SystemSession(repositoryContext, subject, wspConfig);
+ }
+
+ /**
+ * private constructor
+ *
+ * @param repositoryContext repository context
+ * @param subject The subject
+ * @param wspConfig The workspace configuration
+ * @throws javax.jcr.RepositoryException If an error occurs.
+ */
+ private SystemSession(
+ RepositoryContext repositoryContext, Subject subject,
+ WorkspaceConfig wspConfig) throws RepositoryException {
+ super(repositoryContext, subject, wspConfig);
+ }
+
+ /**
+ * Always returns the name of the SystemPrincipal.
+ *
+ * @return the name of SystemPrincipal.
+ */
+ @Override
+ protected String retrieveUserId(Subject subject, String workspaceName) throws RepositoryException {
+ return new SystemPrincipal().getName();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Overridden in order to create custom access manager
+ *
+ * @return access manager for system session
+ */
+ @Override
+ protected AccessManager createAccessManager(Subject subject) {
+ // use own AccessManager implementation rather than relying on
+ // configurable AccessManager to handle SystemPrincipal privileges
+ // correctly
+ return new SystemAccessManager();
+ }
+
+ /**
+ * Always returns true.
+ *
+ * @return true as this is an system session instance.
+ */
+ @Override
+ public boolean isSystem() {
+ return true;
+ }
+
+ /**
+ * Always returns false.
+ *
+ * @return false as this is an system session instance.
+ */
+ @Override
+ public boolean isAdmin() {
+ return false;
+ }
+
+ //--------------------------------------------------------< inner classes >
+ /**
+ * An access manager that grants access to everything.
+ */
+ private class SystemAccessManager extends AbstractAccessControlManager implements AccessManager {
+
+ SystemAccessManager() {
+ }
+
+ //----------------------------------------------------< AccessManager >
+ /**
+ * {@inheritDoc}
+ *
+ * @throws AccessDeniedException is never thrown
+ * @throws Exception is never thrown
+ */
+ public void init(AMContext context)
+ throws AccessDeniedException, Exception {
+ // nop
+ }
+
+ public void init(AMContext context, AccessControlProvider acProvider, WorkspaceAccessManager wspAccessMgr) throws AccessDeniedException, Exception {
+ // nop
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void close() throws Exception {
+ // nop
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws AccessDeniedException is never thrown
+ * @throws RepositoryException is never thrown
+ */
+ public void checkPermission(ItemId id, int permissions)
+ throws AccessDeniedException, RepositoryException {
+ // allow everything
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void checkPermission(Path absPath, int permissions) throws AccessDeniedException, RepositoryException {
+ // allow everything
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void checkRepositoryPermission(int permissions) throws AccessDeniedException, RepositoryException {
+ // allow everything
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return always true
+ * @throws RepositoryException is never thrown
+ */
+ public boolean isGranted(ItemId id, int permissions) throws RepositoryException {
+ // allow everything
+ return true;
+ }
+
+ /**
+ * Always returns true.
+ *
+ * @see AccessManager#isGranted(Path, int)
+ */
+ public boolean isGranted(Path absPath, int permissions) throws RepositoryException {
+ // allow everything
+ return true;
+ }
+
+ /**
+ * Always returns true.
+ *
+ * @see AccessManager#isGranted(Path, Name, int)
+ */
+ public boolean isGranted(Path parentPath, Name childName, int permissions) throws RepositoryException {
+ // allow everything
+ return true;
+ }
+
+ /**
+ * Always returns true.
+ *
+ * @see AccessManager#canRead(org.apache.jackrabbit.spi.Path,org.apache.jackrabbit.core.id.ItemId)
+ */
+ public boolean canRead(Path itemPath, ItemId itemId) throws RepositoryException {
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return always true
+ * @throws RepositoryException is never thrown
+ */
+ public boolean canAccess(String workspaceName) throws RepositoryException {
+ return true;
+ }
+
+ //-----------------------------------< AbstractAccessControlManager >---
+ /**
+ * @see AbstractAccessControlManager#checkInitialized()
+ */
+ @Override
+ protected void checkInitialized() throws IllegalStateException {
+ // nop
+ }
+
+ /**
+ * @see AbstractAccessControlManager#checkPermission(String,int)
+ */
+ @Override
+ protected void checkPermission(String absPath, int permission) throws
+ AccessDeniedException, PathNotFoundException, RepositoryException {
+ // allow everything
+ }
+
+ /**
+ * @see AbstractAccessControlManager#getPrivilegeManager()
+ */
+ @Override
+ protected PrivilegeManager getPrivilegeManager() throws RepositoryException {
+ return context.getPrivilegeManager();
+ }
+
+ /**
+ * @see AbstractAccessControlManager#checkValidNodePath(String)
+ */
+ @Override
+ protected void checkValidNodePath(String absPath)
+ throws PathNotFoundException, RepositoryException {
+ if (absPath != null) {
+ Path p = getQPath(absPath);
+ if (!p.isAbsolute()) {
+ throw new RepositoryException("Absolute path expected.");
+ }
+ if (context.getHierarchyManager().resolveNodePath(p) == null) {
+ throw new PathNotFoundException("No such node " + absPath);
+ }
+ }
+ }
+
+ //-------------------------------------------< AccessControlManager >---
+ /**
+ * @see javax.jcr.security.AccessControlManager#hasPrivileges(String, Privilege[])
+ */
+ public boolean hasPrivileges(String absPath, Privilege[] privileges)
+ throws PathNotFoundException, RepositoryException {
+ checkValidNodePath(absPath);
+ // allow everything
+ return true;
+ }
+
+ /**
+ * @see javax.jcr.security.AccessControlManager#getPrivileges(String)
+ */
+ public Privilege[] getPrivileges(String absPath)
+ throws PathNotFoundException, RepositoryException {
+ checkValidNodePath(absPath);
+ return new Privilege[] {privilegeFromName(Privilege.JCR_ALL)};
+ }
+
+ /**
+ * @see javax.jcr.security.AccessControlManager#getEffectivePolicies(String)
+ */
+ public AccessControlPolicy[] getEffectivePolicies(String absPath) throws
+ PathNotFoundException, AccessDeniedException, RepositoryException {
+ // cannot determine the effective policies for the system session.
+ return new AccessControlPolicy[0];
+ }
+
+ /**
+ * @see org.apache.jackrabbit.api.security.JackrabbitAccessControlManager#getEffectivePolicies(Set)
+ */
+ public AccessControlPolicy[] getEffectivePolicies(Set principal) throws AccessDeniedException, AccessControlException, UnsupportedRepositoryOperationException, RepositoryException {
+ // cannot determine the effective policies for the system session.
+ return new AccessControlPolicy[0];
+ }
+
+ /**
+ * @see org.apache.jackrabbit.api.security.JackrabbitAccessControlManager#hasPrivileges(String, Set, Privilege[])
+ */
+ public boolean hasPrivileges(String absPath, Set principals, Privilege[] privileges) throws PathNotFoundException, RepositoryException {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ /**
+ * @see org.apache.jackrabbit.api.security.JackrabbitAccessControlManager#getPrivileges(String, Set)
+ */
+ public Privilege[] getPrivileges(String absPath, Set principals) throws PathNotFoundException, RepositoryException {
+ throw new UnsupportedOperationException("not implemented");
+ }
+ }
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/TestContentLoader.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/TestContentLoader.java
new file mode 100644
index 00000000000..6d35d3f1b37
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/TestContentLoader.java
@@ -0,0 +1,263 @@
+/*
+ * 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.jackrabbit.core;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+
+import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.retention.RetentionPolicy;
+
+import org.apache.jackrabbit.api.JackrabbitNodeTypeManager;
+import org.apache.jackrabbit.api.JackrabbitWorkspace;
+import org.apache.jackrabbit.commons.JcrUtils;
+import org.apache.jackrabbit.core.retention.RetentionPolicyImpl;
+
+/**
+ * Test Content Loader.
+ */
+public class TestContentLoader {
+
+ /**
+ * The encoding of the test resources.
+ */
+ private static final String ENCODING = "UTF-8";
+
+ public void loadTestContent(Session session) throws RepositoryException, IOException {
+ JackrabbitWorkspace workspace =
+ (JackrabbitWorkspace) session.getWorkspace();
+ Collection workspaces =
+ Arrays.asList(workspace.getAccessibleWorkspaceNames());
+ if (!workspaces.contains("test")) {
+ workspace.createWorkspace("test");
+ }
+
+ JackrabbitNodeTypeManager manager =
+ (JackrabbitNodeTypeManager) workspace.getNodeTypeManager();
+ if (!manager.hasNodeType("test:versionable")) {
+ InputStream xml =
+ TestContentLoader.class.getResourceAsStream("test-nodetypes.xml");
+ try {
+ manager.registerNodeTypes(xml, JackrabbitNodeTypeManager.TEXT_XML);
+ } finally {
+ xml.close();
+ }
+ }
+
+ Node data = getOrAddNode(session.getRootNode(), "testdata");
+ addPropertyTestData(getOrAddNode(data, "property"));
+ addQueryTestData(getOrAddNode(data, "query"));
+ addNodeTestData(getOrAddNode(data, "node"));
+ addLifecycleTestData(getOrAddNode(data, "lifecycle"));
+ addExportTestData(getOrAddNode(data, "docViewTest"));
+
+ Node conf = getOrAddNode(session.getRootNode(), "testconf");
+ addRetentionTestData(getOrAddNode(conf, "retentionTest"));
+
+ session.save();
+ }
+
+
+
+ private Node getOrAddNode(Node node, String name)
+ throws RepositoryException {
+ try {
+ return node.getNode(name);
+ } catch (PathNotFoundException e) {
+ return node.addNode(name);
+ }
+ }
+
+ /**
+ * Creates a boolean, double, long, calendar and a path property at the
+ * given node.
+ */
+ private void addPropertyTestData(Node node) throws RepositoryException {
+ node.setProperty("boolean", true);
+ node.setProperty("double", Math.PI);
+ node.setProperty("long", 90834953485278298l);
+ Calendar c = Calendar.getInstance();
+ c.set(2005, 6, 18, 17, 30);
+ node.setProperty("calendar", c);
+ ValueFactory factory = node.getSession().getValueFactory();
+ node.setProperty("path", factory.createValue("/", PropertyType.PATH));
+ node.setProperty("multi", new String[] { "one", "two", "three" });
+ }
+
+ /**
+ * Creates a node with a RetentionPolicy
+ */
+ private void addRetentionTestData(Node node) throws RepositoryException {
+ RetentionPolicy rp = RetentionPolicyImpl.createRetentionPolicy("testRetentionPolicy", node.getSession());
+ node.getSession().getRetentionManager().setRetentionPolicy(node.getPath(), rp);
+ }
+
+ /**
+ * Creates four nodes under the given node. Each node has a String
+ * property named "prop1" with some content set.
+ */
+ private void addQueryTestData(Node node) throws RepositoryException {
+ while (node.hasNode("node1")) {
+ node.getNode("node1").remove();
+ }
+ getOrAddNode(node, "node1").setProperty(
+ "prop1", "You can have it good, cheap, or fast. Any two.");
+ getOrAddNode(node, "node1").setProperty("prop1", "foo bar");
+ getOrAddNode(node, "node1").setProperty("prop1", "Hello world!");
+ getOrAddNode(node, "node2").setProperty("prop1", "Apache Jackrabbit");
+ }
+
+
+ /**
+ * Creates three nodes under the given node: one of type nt:resource
+ * and the other nodes referencing it.
+ */
+ private void addNodeTestData(Node node) throws RepositoryException, IOException {
+ if (node.hasNode("multiReference")) {
+ node.getNode("multiReference").remove();
+ }
+ if (node.hasNode("resReference")) {
+ node.getNode("resReference").remove();
+ }
+ if (node.hasNode("myResource")) {
+ node.getNode("myResource").remove();
+ }
+
+ Node resource = node.addNode("myResource", "nt:resource");
+ // nt:resource not longer referenceable since JCR 2.0
+ resource.addMixin("mix:referenceable");
+ resource.setProperty("jcr:encoding", ENCODING);
+ resource.setProperty("jcr:mimeType", "text/plain");
+ resource.setProperty(
+ "jcr:data",
+ new ByteArrayInputStream("Hello w\u00F6rld.".getBytes(ENCODING)));
+ resource.setProperty("jcr:lastModified", Calendar.getInstance());
+
+ Node resReference = getOrAddNode(node, "reference");
+ resReference.setProperty("ref", resource);
+ // make this node itself referenceable
+ resReference.addMixin("mix:referenceable");
+
+ Node multiReference = node.addNode("multiReference");
+ ValueFactory factory = node.getSession().getValueFactory();
+ multiReference.setProperty("ref", new Value[] {
+ factory.createValue(resource),
+ factory.createValue(resReference)
+ });
+
+ // NodeDefTest requires a test node with a mandatory child node
+ JcrUtils.putFile(
+ node, "testFile", "text/plain",
+ new ByteArrayInputStream("Hello, World!".getBytes("UTF-8")));
+ }
+
+ /**
+ * Creates a lifecycle policy node and another node with a lifecycle
+ * referencing that policy.
+ */
+ private void addLifecycleTestData(Node node) throws RepositoryException {
+ Node policy = getOrAddNode(node, "policy");
+ policy.addMixin(NodeType.MIX_REFERENCEABLE);
+ Node transitions = getOrAddNode(policy, "transitions");
+ Node transition = getOrAddNode(transitions, "identity");
+ transition.setProperty("from", "identity");
+ transition.setProperty("to", "identity");
+
+ Node lifecycle = getOrAddNode(node, "node");
+ ((NodeImpl) lifecycle).assignLifecyclePolicy(policy, "identity");
+ }
+
+ private void addExportTestData(Node node) throws RepositoryException, IOException {
+ getOrAddNode(node, "invalidXmlName").setProperty("propName", "some text");
+
+ // three nodes which should be serialized as xml text in docView export
+ // separated with spaces
+ getOrAddNode(node, "jcr:xmltext").setProperty(
+ "jcr:xmlcharacters", "A text without any special character.");
+ getOrAddNode(node, "some-element");
+ getOrAddNode(node, "jcr:xmltext").setProperty(
+ "jcr:xmlcharacters",
+ " The entity reference characters: <, ', ,&, >, \" should"
+ + " be escaped in xml export. ");
+ getOrAddNode(node, "some-element");
+ getOrAddNode(node, "jcr:xmltext").setProperty(
+ "jcr:xmlcharacters", "A text without any special character.");
+
+ Node big = getOrAddNode(node, "bigNode");
+ big.setProperty(
+ "propName0",
+ "SGVsbG8gd8O2cmxkLg==;SGVsbG8gd8O2cmxkLg==".split(";"),
+ PropertyType.BINARY);
+ big.setProperty("propName1", "text 1");
+ big.setProperty(
+ "propName2",
+ "multival text 1;multival text 2;multival text 3".split(";"));
+ big.setProperty("propName3", "text 1");
+
+ addExportValues(node, "propName");
+ addExportValues(node, "Prop<>prop");
+ }
+
+ /**
+ * create nodes with following properties
+ * binary & single
+ * binary & multival
+ * notbinary & single
+ * notbinary & multival
+ */
+ private void addExportValues(Node node, String name)
+ throws RepositoryException, IOException {
+ String prefix = "valid";
+ if (name.indexOf('<') != -1) {
+ prefix = "invalid";
+ }
+ node = getOrAddNode(node, prefix + "Names");
+
+ String[] texts = new String[] {
+ "multival text 1", "multival text 2", "multival text 3" };
+ getOrAddNode(node, prefix + "MultiNoBin").setProperty(name, texts);
+
+ Node resource = getOrAddNode(node, prefix + "MultiBin");
+ resource.setProperty("jcr:encoding", ENCODING);
+ resource.setProperty("jcr:mimeType", "text/plain");
+ String[] values =
+ new String[] { "SGVsbG8gd8O2cmxkLg==", "SGVsbG8gd8O2cmxkLg==" };
+ resource.setProperty(name, values, PropertyType.BINARY);
+ resource.setProperty("jcr:lastModified", Calendar.getInstance());
+
+ getOrAddNode(node, prefix + "NoBin").setProperty(name, "text 1");
+
+ resource = getOrAddNode(node, "invalidBin");
+ resource.setProperty("jcr:encoding", ENCODING);
+ resource.setProperty("jcr:mimeType", "text/plain");
+ byte[] bytes = "Hello w\u00F6rld.".getBytes(ENCODING);
+ resource.setProperty(name, new ByteArrayInputStream(bytes));
+ resource.setProperty("jcr:lastModified", Calendar.getInstance());
+ }
+
+}
\ No newline at end of file
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/TransientRepository.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/TransientRepository.java
new file mode 100644
index 00000000000..8f60577353c
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/TransientRepository.java
@@ -0,0 +1,451 @@
+/*
+ * 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.jackrabbit.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.jcr.Credentials;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+
+import org.apache.commons.collections.map.ReferenceMap;
+import org.apache.jackrabbit.api.JackrabbitRepository;
+import org.apache.jackrabbit.commons.AbstractRepository;
+import org.apache.jackrabbit.core.config.ConfigurationException;
+import org.apache.jackrabbit.core.config.RepositoryConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A repository proxy that automatically initializes and shuts down the
+ * underlying repository instance when the first session is opened
+ * or the last one closed. As long as all sessions are properly closed
+ * when no longer used, this class can be used to avoid having to explicitly
+ * shut down the repository.
+ */
+public class TransientRepository extends AbstractRepository
+ implements JackrabbitRepository, SessionListener {
+
+ /**
+ * The logger instance used to log the repository and session lifecycles.
+ */
+ private static final Logger logger =
+ LoggerFactory.getLogger(TransientRepository.class);
+
+ /**
+ * Name of the repository configuration file property.
+ */
+ private static final String CONF_PROPERTY =
+ "org.apache.jackrabbit.repository.conf";
+
+ /**
+ * Default value of the repository configuration file property.
+ */
+ private static final String CONF_DEFAULT = "repository.xml";
+
+ /**
+ * Name of the repository home directory property.
+ */
+ private static final String HOME_PROPERTY =
+ "org.apache.jackrabbit.repository.home";
+
+ /**
+ * Default value of the repository home directory property.
+ */
+ private static final String HOME_DEFAULT = "repository";
+
+ /**
+ * Factory interface for creating {@link RepositoryImpl} instances.
+ * Used to give greater control of the repository initialization process
+ * to users of the TransientRepository class.
+ */
+ public interface RepositoryFactory {
+
+ /**
+ * Creates and initializes a repository instance. The returned instance
+ * will be used and finally shut down by the caller of this method.
+ *
+ * @return initialized repository instance
+ * @throws RepositoryException if an instance can not be created
+ */
+ RepositoryImpl getRepository() throws RepositoryException;
+
+ }
+
+ /**
+ * The repository configuration. Set in the constructor and used to
+ * initialize the repository instance when the first session is opened.
+ */
+ private final RepositoryFactory factory;
+
+ /**
+ * The initialized repository instance. Set when the first session is
+ * opened and cleared when the last one is closed.
+ */
+ private RepositoryImpl repository;
+
+ /**
+ * The set of open sessions. When no more open sessions remain, the
+ * repository instance is automatically shut down until a new session
+ * is opened.
+ */
+ private final Map sessions =
+ new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK);
+
+ /**
+ * The static repository descriptors. The default {@link RepositoryImpl}
+ * descriptors are loaded as the static descriptors and used whenever a
+ * live repository instance is not available (no open sessions).
+ */
+ private final Properties descriptors;
+
+ /**
+ * The path to the repository home directory.
+ */
+ private final String home;
+
+ /**
+ * Creates a transient repository proxy that will use the given repository
+ * factory to initialize the underlying repository instances.
+ *
+ * @param factory repository factory
+ * @param home the path to the repository home directory.
+ */
+ public TransientRepository(RepositoryFactory factory, String home) {
+ this.factory = factory;
+ this.home = home;
+ this.repository = null;
+ this.descriptors = new Properties();
+
+ // FIXME: The current RepositoryImpl class does not allow static
+ // access to the repository descriptors, so we need to load them
+ // directly from the underlying property file.
+ try {
+ InputStream in = RepositoryImpl.class.getResourceAsStream(
+ "repository.properties");
+ try {
+ descriptors.load(in);
+ } finally {
+ in.close();
+ }
+ } catch (IOException e) {
+ logger.warn("Unable to load static repository descriptors", e);
+ }
+ }
+
+ /**
+ * Creates a transient repository proxy that will use the repository
+ * configuration file and home directory specified in system properties
+ * org.apache.jackrabbit.repository.conf and
+ * org.apache.jackrabbit.repository.home. If these properties
+ * are not found, then the default values "repository.xml"
+ * and "repository" are used.
+ */
+ public TransientRepository() {
+ this(System.getProperty(CONF_PROPERTY, CONF_DEFAULT),
+ System.getProperty(HOME_PROPERTY, HOME_DEFAULT));
+ }
+
+ /**
+ * Creates a transient repository proxy that will use a copy of the given
+ * repository configuration to initialize the underlying repository
+ * instance.
+ *
+ * @param config repository configuration
+ */
+ public TransientRepository(final RepositoryConfig config) {
+ this(new RepositoryFactory() {
+ public RepositoryImpl getRepository() throws RepositoryException {
+ return RepositoryImpl.create(RepositoryConfig.create(config));
+ }
+ }, config.getHomeDir());
+ }
+
+ /**
+ * Creates a transient repository proxy that will use the given repository
+ * configuration file and home directory paths to initialize the underlying
+ * repository instances.
+ *
+ * @see #TransientRepository(File, File)
+ * @param config repository configuration file
+ * @param home repository home directory
+ */
+ public TransientRepository(String config, String home) {
+ this(new File(config), new File(home));
+ }
+
+ /**
+ * Creates a transient repository proxy based on the given repository
+ * home directory and the repository configuration file "repository.xml"
+ * contained in that directory.
+ *
+ * @since Apache Jackrabbit 1.6
+ * @param dir repository home directory
+ */
+ public TransientRepository(File dir) {
+ this(new File(dir, "repository.xml"), dir);
+ }
+
+ /**
+ * Creates a transient repository proxy that will use the given repository
+ * configuration file and home directory paths to initialize the underlying
+ * repository instances. The repository configuration file is reloaded
+ * whenever the repository is restarted, so it is safe to modify the
+ * configuration when all sessions have been closed.
+ *
+ * If the given repository configuration file does not exist, then a
+ * default configuration file is copied to the given location when the
+ * first session starts. Similarly, if the given repository home
+ * directory does not exist, it is automatically created when the first
+ * session starts. This is a convenience feature designed to reduce the
+ * need for manual configuration.
+ *
+ * @since Apache Jackrabbit 1.6
+ * @param xml repository configuration file
+ * @param dir repository home directory
+ */
+ public TransientRepository(final File xml, final File dir) {
+ this(new RepositoryFactory() {
+ public RepositoryImpl getRepository() throws RepositoryException {
+ try {
+ return RepositoryImpl.create(
+ RepositoryConfig.install(xml, dir));
+ } catch (IOException e) {
+ throw new RepositoryException(
+ "Automatic repository configuration failed", e);
+ } catch (ConfigurationException e) {
+ throw new RepositoryException(
+ "Invalid repository configuration file: " + xml, e);
+ }
+ }
+ }, dir.getAbsolutePath());
+ }
+
+ public TransientRepository(final Properties properties)
+ throws ConfigurationException, IOException {
+ this(new RepositoryFactory() {
+ public RepositoryImpl getRepository() throws RepositoryException {
+ try {
+ return RepositoryImpl.create(
+ RepositoryConfig.install(properties));
+ } catch (IOException e) {
+ throw new RepositoryException(
+ "Automatic repository configuration failed: "
+ + properties, e);
+ } catch (ConfigurationException e) {
+ throw new RepositoryException(
+ "Invalid repository configuration: "
+ + properties, e);
+ }
+ }
+ }, RepositoryConfig.getRepositoryHome(properties).getAbsolutePath());
+ }
+
+ /**
+ * @return the path to the repository home directory.
+ */
+ public String getHomeDir() {
+ return home;
+ }
+
+ /**
+ * Starts the underlying repository.
+ *
+ * @throws RepositoryException if the repository cannot be started
+ */
+ private synchronized void startRepository() throws RepositoryException {
+ assert repository == null && sessions.isEmpty();
+ logger.debug("Initializing transient repository");
+ repository = factory.getRepository();
+ logger.info("Transient repository initialized");
+ }
+
+ /**
+ * Stops the underlying repository.
+ */
+ private synchronized void stopRepository() {
+ assert repository != null && sessions.isEmpty();
+ logger.debug("Shutting down transient repository");
+ repository.shutdown();
+ logger.info("Transient repository shut down");
+ repository = null;
+ }
+
+ //------------------------------------------------------------
+
+ /**
+ * Returns the available descriptor keys. If the underlying repository
+ * is initialized, then the call is proxied to it, otherwise the static
+ * descriptor keys are returned.
+ *
+ * @return descriptor keys
+ */
+ public synchronized String[] getDescriptorKeys() {
+ if (repository != null) {
+ return repository.getDescriptorKeys();
+ } else {
+ String[] keys = Collections.list(
+ descriptors.propertyNames()).toArray(new String[0]);
+ Arrays.sort(keys);
+ return keys;
+ }
+ }
+
+ /**
+ * Returns the identified repository descriptor. If the underlying
+ * repository is initialized, then the call is proxied to it, otherwise
+ * the static descriptors are used.
+ *
+ * @param key descriptor key
+ * @return descriptor value
+ * @see javax.jcr.Repository#getDescriptor(String)
+ */
+ public synchronized String getDescriptor(String key) {
+ if (repository != null) {
+ return repository.getDescriptor(key);
+ } else {
+ return descriptors.getProperty(key);
+ }
+ }
+
+ public Value getDescriptorValue(String key) {
+ if (repository != null) {
+ return repository.getDescriptorValue(key);
+ } else {
+ throw new UnsupportedOperationException(
+ "not implemented yet - see JCR-2062");
+ }
+ }
+
+ public Value[] getDescriptorValues(String key) {
+ if (repository != null) {
+ return repository.getDescriptorValues(key);
+ } else {
+ throw new UnsupportedOperationException(
+ "not implemented yet - see JCR-2062");
+ }
+ }
+
+ public boolean isSingleValueDescriptor(String key) {
+ if (repository != null) {
+ return repository.isSingleValueDescriptor(key);
+ } else {
+ throw new UnsupportedOperationException(
+ "not implemented yet - see JCR-2062");
+ }
+ }
+
+ /**
+ * Logs in to the content repository. Initializes the underlying repository
+ * instance if needed. The opened session is added to the set of open
+ * sessions and a session listener is added to track when the session gets
+ * closed.
+ *
+ * @param credentials login credentials
+ * @param workspaceName workspace name
+ * @return new session
+ * @throws RepositoryException if the session could not be created
+ * @see javax.jcr.Repository#login(Credentials,String)
+ */
+ public synchronized Session login(
+ Credentials credentials, String workspaceName)
+ throws RepositoryException {
+ // Start the repository if this is the first login
+ if (repository == null) {
+ startRepository();
+ }
+
+ try {
+ logger.debug("Opening a new session");
+ SessionImpl session = (SessionImpl) repository.login(
+ credentials, workspaceName);
+ sessions.put(session, session);
+ session.addListener(this);
+ logger.info("Session opened");
+
+ return session;
+ } finally {
+ // Stop the repository if the login failed
+ // and no other sessions are active
+ if (sessions.isEmpty()) {
+ stopRepository();
+ }
+ }
+ }
+
+ //--------------------------------------------------
+
+ /**
+ * Forces all active sessions to logout. Once the last session has logged
+ * out, the underlying repository instance will automatically be shut down.
+ *
+ * @see Session#logout()
+ */
+ public synchronized void shutdown() {
+ Session[] copy = sessions.keySet().toArray(new Session[0]);
+ for (Session session : copy) {
+ session.logout();
+ }
+ }
+
+ //-------------------------------------------------------
+
+ /**
+ * Removes the given session from the set of open sessions. If no open
+ * sessions remain, then the underlying repository instance is shut down.
+ *
+ * @param session closed session
+ * @see SessionListener#loggedOut(SessionImpl)
+ */
+ public synchronized void loggedOut(SessionImpl session) {
+ assert sessions.containsKey(session);
+ sessions.remove(session);
+ logger.info("Session closed");
+ if (sessions.isEmpty()) {
+ // FIXME: This is an ugly hack to avoid an infinite loop when
+ // RepositoryImpl.shutdown() repeatedly calls logout() on all
+ // remaining active sessions including the one that just emitted
+ // the loggedOut() message to us!
+ repository.loggedOut(session);
+
+ stopRepository();
+ }
+ }
+
+ /**
+ * Ignored. {@inheritDoc}
+ */
+ public void loggingOut(SessionImpl session) {
+ }
+
+ /**
+ * Get the current repository.
+ *
+ * @return the repository
+ */
+ RepositoryImpl getRepository() {
+ return repository;
+ }
+
+}
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/UserPerWorkspaceSecurityManager.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/UserPerWorkspaceSecurityManager.java
new file mode 100644
index 00000000000..bb253d7bed8
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/UserPerWorkspaceSecurityManager.java
@@ -0,0 +1,376 @@
+/*
+ * 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.jackrabbit.core;
+
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.core.config.LoginModuleConfig;
+import org.apache.jackrabbit.core.config.UserManagerConfig;
+import org.apache.jackrabbit.core.security.authentication.AuthContext;
+import org.apache.jackrabbit.core.security.authentication.AuthContextProvider;
+import org.apache.jackrabbit.core.security.authorization.WorkspaceAccessManager;
+import org.apache.jackrabbit.core.security.principal.AbstractPrincipalProvider;
+import org.apache.jackrabbit.core.security.principal.DefaultPrincipalProvider;
+import org.apache.jackrabbit.core.security.principal.PrincipalManagerImpl;
+import org.apache.jackrabbit.core.security.principal.PrincipalProvider;
+import org.apache.jackrabbit.core.security.principal.PrincipalProviderRegistry;
+import org.apache.jackrabbit.core.security.simple.SimpleWorkspaceAccessManager;
+import org.apache.jackrabbit.core.security.user.MembershipCache;
+import org.apache.jackrabbit.core.security.user.UserPerWorkspaceUserManager;
+import org.apache.jackrabbit.core.security.user.UserManagerImpl;
+import org.apache.jackrabbit.core.security.user.action.AuthorizableAction;
+
+import javax.jcr.Credentials;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.security.auth.Subject;
+import java.security.Principal;
+import java.security.acl.Group;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+/**
+ * Derived security manager implementation that expects that users information
+ * is present in each workspace instead of having a single, dedicated
+ * "security-workspace" that provides user information. Consequently, the
+ * UserManager used to retrieve and manipulate user content is always
+ * bound to the Session passed to {@link #getUserManager(Session)}.
+ *
In addition the default (user-based) principal provider created by
+ * {@link org.apache.jackrabbit.core.DefaultSecurityManager}
+ * cannot be used to retrieve principals. Instead this implementation keeps
+ * a distinct pp-registry for each workspace.
+ *
+ * NOTE: While this security manager asserts that a minimal set of system
+ * users (admin and anonymous) is present in each workspace
+ * it doesn't make any attempt to set or define the access permissions on the
+ * tree containing user related information.
+ */
+public class UserPerWorkspaceSecurityManager extends DefaultSecurityManager {
+
+ private final Map ppRegistries = new HashMap();
+ private final Object monitor = new Object();
+
+ /**
+ * List of workspace names for which {@link #createSystemUsers} has already
+ * been called.
+ */
+ private final List systemUsersInitialized = new ArrayList();
+
+ private PrincipalProviderRegistry getPrincipalProviderRegistry(SessionImpl s) throws RepositoryException {
+ String wspName = s.getWorkspace().getName();
+ synchronized (monitor) {
+ PrincipalProviderRegistry p = ppRegistries.get(wspName);
+ if (p == null) {
+ SystemSession systemSession;
+ if (s instanceof SystemSession) {
+ systemSession = (SystemSession) s;
+ } else {
+ RepositoryImpl repo = (RepositoryImpl) getRepository();
+ systemSession = repo.getSystemSession(wspName);
+ // TODO: review again... this workaround is used in several places.
+ repo.markWorkspaceActive(wspName);
+ }
+
+ Properties[] moduleConfig = new AuthContextProvider("", ((RepositoryImpl) getRepository()).getConfig().getSecurityConfig().getLoginModuleConfig()).getModuleConfig();
+
+ PrincipalProvider defaultPP = new DefaultPrincipalProvider(systemSession, (UserManagerImpl) getUserManager(systemSession));
+
+ boolean initialized = false;
+ for (Properties props : moduleConfig) {
+ //GRANITE-4470: apply config to DefaultPrincipalProvider if there is no explicit PrincipalProvider configured
+ if (!props.containsKey(LoginModuleConfig.PARAM_PRINCIPAL_PROVIDER_CLASS) && props.containsKey(AbstractPrincipalProvider.MAXSIZE_KEY)) {
+ defaultPP.init(props);
+ initialized = true;
+ break;
+ }
+ }
+ if (!initialized) {
+ defaultPP.init(new Properties());
+ }
+
+ p = new WorkspaceBasedPrincipalProviderRegistry(defaultPP);
+ ppRegistries.put(wspName, p);
+ }
+ return p;
+ }
+ }
+
+ //------------------------------------------< JackrabbitSecurityManager >---
+ /**
+ * @see org.apache.jackrabbit.core.security.JackrabbitSecurityManager#init(Repository, Session)
+ */
+ @Override
+ public void init(Repository repository, Session systemSession) throws RepositoryException {
+ super.init(repository, systemSession);
+
+ systemUsersInitialized.add(systemSession.getWorkspace().getName());
+ }
+
+ /**
+ * @see org.apache.jackrabbit.core.security.JackrabbitSecurityManager#dispose(String)
+ */
+ @Override
+ public void dispose(String workspaceName) {
+ super.dispose(workspaceName);
+ synchronized (monitor) {
+ PrincipalProviderRegistry reg = ppRegistries.remove(workspaceName);
+ if (reg != null) {
+ reg.getDefault().close();
+ }
+ }
+ }
+
+ /**
+ * @see org.apache.jackrabbit.core.security.JackrabbitSecurityManager#close()
+ */
+ @Override
+ public void close() {
+ super.close();
+ synchronized (monitor) {
+ for (PrincipalProviderRegistry registry : ppRegistries.values()) {
+ registry.getDefault().close();
+ }
+ ppRegistries.clear();
+ }
+ }
+
+ /**
+ * As this implementation expects that users information in present in
+ * every workspace, the UserManager is always created with the given
+ * session.
+ *
+ * @see org.apache.jackrabbit.core.security.JackrabbitSecurityManager#getUserManager(javax.jcr.Session)
+ */
+ @Override
+ public UserManager getUserManager(Session session) throws RepositoryException {
+ checkInitialized();
+ if (session == getSystemSession()) {
+ return super.getUserManager(session);
+ } else if (session instanceof SessionImpl) {
+ UserManager uMgr = createUserManager((SessionImpl) session);
+ // Since users are not stored in a dedicated security workspace:
+ // make sure the system users are present. this is always the case
+ // for the configured security-workspace (or if missing the default
+ // workspace) but not for other workspaces.
+ // However, the check is only executed if the given session is a
+ // SystemSession (see also #getPrincipalProviderRegistry(Session)
+ // that initializes a SystemSession based UserManager for each workspace).
+ String wspName = session.getWorkspace().getName();
+ if (session instanceof SystemSession && !systemUsersInitialized.contains(wspName)) {
+ createSystemUsers(uMgr, (SystemSession) session, adminId, anonymousId);
+ systemUsersInitialized.add(wspName);
+ }
+ return uMgr;
+ } else {
+ throw new RepositoryException("Internal error: SessionImpl expected.");
+ }
+ }
+
+ /**
+ * Creates an AuthContext for the given {@link javax.jcr.Credentials} and
+ * {@link javax.security.auth.Subject}.
+ * This includes selection of application specific LoginModules and
+ * initialization with credentials and Session to System-Workspace
+ *
+ * @return an {@link org.apache.jackrabbit.core.security.authentication.AuthContext} for the given Credentials, Subject
+ * @throws javax.jcr.RepositoryException in other exceptional repository states
+ */
+ @Override
+ public AuthContext getAuthContext(Credentials creds, Subject subject, String workspaceName)
+ throws RepositoryException {
+ checkInitialized();
+ SystemSession systemSession = ((RepositoryImpl) getRepository()).getSystemSession(workspaceName);
+ return getAuthContextProvider().getAuthContext(creds, subject, systemSession,
+ getPrincipalProviderRegistry(systemSession), adminId, anonymousId);
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ * Always returns null. The default principal provider is
+ * workspace depending as users are expected to exist in every workspace.
+ *
+ * @return null
+ * @throws RepositoryException
+ */
+ @Override
+ protected PrincipalProvider createDefaultPrincipalProvider(Properties[] moduleConfig) throws RepositoryException {
+ return null;
+ }
+
+ @Override
+ protected UserManager getSystemUserManager(String workspaceName) throws RepositoryException {
+ if (workspaceName.equals(getSystemSession().getWorkspace().getName())) {
+ return super.getSystemUserManager(workspaceName);
+ } else {
+ return ((RepositoryImpl) getRepository()).getWorkspaceInfo(workspaceName).getSystemSession().getUserManager();
+ }
+ }
+
+ /**
+ * Creates a new instanceof TransientChangeUserManagerImpl.
+ *
+ * @param session session
+ * @return an instanceof TransientChangeUserManagerImpl
+ * @throws RepositoryException
+ */
+ @Override
+ protected UserManagerImpl createUserManager(SessionImpl session) throws RepositoryException {
+ UserManagerConfig umc = getConfig().getUserManagerConfig();
+ UserManagerImpl umgr;
+ // in contrast to the DefaultSecurityManager users are not retrieved
+ // from a dedicated workspace: the system session of each workspace must
+ // get a system user manager that asserts the existence of the admin user.
+ if (umc != null) {
+ Class>[] paramTypes = new Class[] {
+ SessionImpl.class,
+ String.class,
+ Properties.class,
+ MembershipCache.class};
+ umgr = (UserPerWorkspaceUserManager) umc.getUserManager(UserPerWorkspaceUserManager.class,
+ paramTypes, session, adminId, umc.getParameters(), getMembershipCache(session));
+ } else {
+ umgr = new UserPerWorkspaceUserManager(session, adminId, null, getMembershipCache(session));
+ }
+
+ if (umc != null && !(session instanceof SystemSession)) {
+ AuthorizableAction[] actions = umc.getAuthorizableActions();
+ umgr.setAuthorizableActions(actions);
+ }
+ return umgr;
+ }
+
+ /**
+ * @param session Session for the principal manager must be created.
+ * @return A new instance of PrincipalManagerImpl. Note that this implementation
+ * uses a workspace specific principal provider registry, that retrieves
+ * the configured providers from the registry obtained through
+ * {@link #getPrincipalProviderRegistry()} but has a workspace specific
+ * default provider.
+ * @throws RepositoryException
+ */
+ @Override
+ protected PrincipalManager createPrincipalManager(SessionImpl session) throws RepositoryException {
+ return new PrincipalManagerImpl(session, getPrincipalProviderRegistry(session).getProviders());
+ }
+
+ /**
+ * Returns a new instance of SimpleWorkspaceAccessManager, since
+ * with the DefaultLoginModule the existence of the user
+ * is checked in order to successfully complete the login. Since with this
+ * SecurityManager users are stored separately in each workspace, a user
+ * may only login to a workspace if the corresponding user node exists.
+ * Consequently a lazy workspace access manager is sufficient.
+ *
+ * If this SecurityManager is used with a distinct LoginModule
+ * implementation, the {@link org.apache.jackrabbit.core.config.SecurityManagerConfig#getWorkspaceAccessConfig() configuration}
+ * for WorkspaceAccessManager should be adjusted as well.
+ *
+ * @return An new instance of {@link SimpleWorkspaceAccessManager}.
+ */
+ @Override
+ protected WorkspaceAccessManager createDefaultWorkspaceAccessManager() {
+ return new WorkspaceAccessManagerImpl();
+ }
+
+ //--------------------------------------------------------------------------
+ /**
+ * Workaround to get a default (user-based) principal provider depending
+ * on the workspace being accessed. This is required for this security
+ * manager as users aren't stored in a single, dedicated workspace.
+ */
+ private final class WorkspaceBasedPrincipalProviderRegistry implements PrincipalProviderRegistry {
+
+ private final PrincipalProvider defaultPrincipalProvider;
+
+ public WorkspaceBasedPrincipalProviderRegistry(PrincipalProvider defaultPrincipalProvider) {
+ this.defaultPrincipalProvider = defaultPrincipalProvider;
+ }
+
+ public PrincipalProvider registerProvider(Properties configuration) throws RepositoryException {
+ return getPrincipalProviderRegistry().registerProvider(configuration);
+ }
+
+ public PrincipalProvider getDefault() {
+ return defaultPrincipalProvider;
+ }
+
+ public PrincipalProvider getProvider(String className) {
+ PrincipalProvider p = getPrincipalProviderRegistry().getProvider(className);
+ if (p == null && defaultPrincipalProvider.getClass().getName().equals(className)) {
+ p = defaultPrincipalProvider;
+ }
+ return p;
+ }
+
+ public PrincipalProvider[] getProviders() {
+ List l = new ArrayList();
+ l.addAll(Arrays.asList(getPrincipalProviderRegistry().getProviders()));
+ l.add(defaultPrincipalProvider);
+ return l.toArray(new PrincipalProvider[l.size()]);
+ }
+ }
+
+ private final class WorkspaceAccessManagerImpl implements WorkspaceAccessManager {
+ /**
+ * Does nothing.
+ * @see WorkspaceAccessManager#init(javax.jcr.Session)
+ */
+ public void init(Session systemSession) throws RepositoryException {
+ // nothing to do.
+ }
+
+ /**
+ * Does nothing.
+ * @see org.apache.jackrabbit.core.security.authorization.WorkspaceAccessManager#close()
+ */
+ public void close() throws RepositoryException {
+ // nothing to do.
+ }
+
+ /**
+ * Returns true if a workspace with the given
+ * workspaceName exists and if that workspace defines a
+ * user that matches any of the given principals;
+ * false otherwise.
+ *
+ * @see WorkspaceAccessManager#grants(java.util.Set, String)
+ */
+ public boolean grants(Set principals, String workspaceName) throws RepositoryException {
+ if (!(Arrays.asList(((RepositoryImpl) getRepository()).getWorkspaceNames())).contains(workspaceName)) {
+ return false;
+ } else {
+ UserManager umgr = UserPerWorkspaceSecurityManager.this.getSystemUserManager(workspaceName);
+ for (Principal principal : principals) {
+ if (!(principal instanceof Group)) {
+ // check if the workspace identified by the given workspace
+ // name contains a user with this principal
+ if (umgr.getAuthorizable(principal) != null) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/VersionManagerImpl.java b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/VersionManagerImpl.java
new file mode 100644
index 00000000000..b5af9b8f2fc
--- /dev/null
+++ b/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/VersionManagerImpl.java
@@ -0,0 +1,649 @@
+/*
+ * 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.jackrabbit.core;
+
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_HOLD;
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_LOCK;
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_PENDING_CHANGES;
+import static org.apache.jackrabbit.core.ItemValidator.CHECK_PENDING_CHANGES_ON_NODE;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.version.Version;
+import javax.jcr.version.VersionException;
+import javax.jcr.version.VersionHistory;
+import javax.jcr.version.VersionManager;
+
+import org.apache.jackrabbit.core.id.ItemId;
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.security.authorization.Permission;
+import org.apache.jackrabbit.core.session.SessionContext;
+import org.apache.jackrabbit.core.session.SessionOperation;
+import org.apache.jackrabbit.core.session.SessionWriteOperation;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.UpdatableItemStateManager;
+import org.apache.jackrabbit.core.version.InconsistentVersioningState;
+import org.apache.jackrabbit.core.version.InternalActivity;
+import org.apache.jackrabbit.core.version.InternalBaseline;
+import org.apache.jackrabbit.core.version.InternalVersion;
+import org.apache.jackrabbit.core.version.InternalVersionHistory;
+import org.apache.jackrabbit.core.version.NodeStateEx;
+import org.apache.jackrabbit.core.version.VersionImpl;
+import org.apache.jackrabbit.core.version.VersionManagerImplConfig;
+import org.apache.jackrabbit.core.version.VersionSet;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.Path;
+import org.apache.jackrabbit.spi.commons.name.NameConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation of the {@link javax.jcr.version.VersionManager}.
+ *
+ * This class implements the JCR Version Manager interface but most of the
+ * operations are performed in the super classes. this is only cosmetic to
+ * avoid huge source files.
+ */
+public class VersionManagerImpl extends VersionManagerImplConfig
+ implements VersionManager {
+
+ /**
+ * default logger
+ */
+ private static final Logger log = LoggerFactory.getLogger(VersionManagerImpl.class);
+
+ /**
+ * Creates a new version manager
+ *
+ * @param context component context of the current session
+ * @param stateMgr the underlying state manager
+ * @param hierMgr local hierarchy manager
+ */
+ public VersionManagerImpl(
+ SessionContext context, UpdatableItemStateManager stateMgr,
+ HierarchyManager hierMgr) {
+ super(context, stateMgr, hierMgr);
+ }
+
+ private T perform(SessionOperation operation)
+ throws RepositoryException {
+ return context.getSessionState().perform(operation);
+ }
+
+ /** Wrapper around {@link #checkin(String, Calendar)}. */
+ public Version checkin(String absPath) throws RepositoryException {
+ return checkin(absPath, null);
+ }
+
+ /**
+ * Creates a new version of the node at the given path.
+ *
+ * @param absPath node path
+ * @param created create time of the new version,
+ * or null for the current time
+ * @return new version
+ * @throws RepositoryException if the version can not be created
+ */
+ public Version checkin(final String absPath, final Calendar created)
+ throws RepositoryException {
+ return perform(new SessionWriteOperation () {
+ public Version perform(SessionContext context)
+ throws RepositoryException {
+ NodeStateEx state = getNodeState(
+ absPath,
+ CHECK_LOCK | CHECK_HOLD | CHECK_PENDING_CHANGES_ON_NODE,
+ Permission.VERSION_MNGMT);
+ NodeId baseId = checkoutCheckin(state, true, false, created);
+ return (Version) session.getNodeById(baseId);
+ }
+ public String toString() {
+ return "versionManager.checkin(" + absPath + ", " + created + ")";
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void checkout(final String absPath) throws RepositoryException {
+ perform(new SessionWriteOperation () {
+ public NodeId perform(SessionContext context)
+ throws RepositoryException {
+ NodeStateEx state = getNodeState(
+ absPath,
+ CHECK_LOCK | CHECK_HOLD,
+ Permission.VERSION_MNGMT);
+ return checkoutCheckin(state, false, true, null);
+ }
+ public String toString() {
+ return "versionManager.checkout(" + absPath + ")";
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Version checkpoint(final String absPath) throws RepositoryException {
+ return perform(new SessionWriteOperation () {
+ public Version perform(SessionContext context)
+ throws RepositoryException {
+ NodeStateEx state = getNodeState(
+ absPath,
+ CHECK_LOCK | CHECK_HOLD | CHECK_PENDING_CHANGES_ON_NODE,
+ Permission.VERSION_MNGMT);
+ NodeId baseId = checkoutCheckin(state, true, true, null);
+ return (Version) session.getNodeById(baseId);
+ }
+ public String toString() {
+ return "versionManager.checkpoint(" + absPath + ")";
+ }
+ });
+ }
+
+ /** Wrapper around {@link Node#isCheckedOut()}. */
+ public boolean isCheckedOut(String absPath) throws RepositoryException {
+ return session.getNode(absPath).isCheckedOut();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public VersionHistory getVersionHistory(final String absPath)
+ throws RepositoryException {
+ return perform(new SessionOperation () {
+ public VersionHistory perform(SessionContext context)
+ throws RepositoryException {
+ NodeStateEx state = getNodeState(absPath);
+ InternalVersionHistory vh = getVersionHistory(state);
+ if (vh == null) {
+ throw new InconsistentVersioningState("Couldn't get version history for node " + state.getNodeId());
+ }
+ return (VersionHistory) session.getNodeById(vh.getId());
+ }
+ public String toString() {
+ return "versionManager.getVersionHistory(" + absPath + ")";
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Version getBaseVersion(final String absPath)
+ throws RepositoryException {
+ return perform(new SessionOperation () {
+ public Version perform(SessionContext context)
+ throws RepositoryException {
+ NodeStateEx state = getNodeState(absPath);
+ InternalVersion v = getBaseVersion(state);
+ return (Version) session.getNodeById(v.getId());
+ }
+ public String toString() {
+ return "versionManager.getBaseVersion(" + absPath + ")";
+ }
+ });
+ }
+
+ /** Wrapper around {@link #restore(Version[], boolean)}. */
+ public void restore(Version version, boolean removeExisting)
+ throws RepositoryException {
+ restore(new Version[]{version}, removeExisting);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void restore(final Version[] versions, final boolean removeExisting)
+ throws RepositoryException {
+ perform(new SessionWriteOperation () {
+ public Object perform(SessionContext context)
+ throws RepositoryException {
+ // check for pending changes
+ if (session.hasPendingChanges()) {
+ throw new InvalidItemStateException(
+ "Unable to restore version. Session has pending changes.");
+ }
+
+ // add all versions to map of versions to restore
+ Map toRestore =
+ new HashMap();
+ for (Version version : versions) {
+ InternalVersion v =
+ vMgr.getVersion(((VersionImpl) version).getNodeId());
+ // check for collision
+ NodeId historyId = v.getVersionHistory().getId();
+ if (toRestore.containsKey(historyId)) {
+ throw new VersionException(
+ "Unable to restore. Two or more versions have same version history.");
+ }
+ toRestore.put(historyId, v);
+ }
+
+ WriteOperation ops = startWriteOperation();
+ try {
+ internalRestore(
+ new VersionSet(toRestore, true), removeExisting);
+ ops.save();
+ } catch (ItemStateException e) {
+ throw new RepositoryException(e);
+ } finally {
+ ops.close();
+ }
+
+ return this;
+ }
+ public String toString() {
+ return "versionManager.restore(versions, " + removeExisting + ")";
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void restore(
+ final String absPath, final String versionName,
+ final boolean removeExisting) throws RepositoryException {
+ perform(new SessionWriteOperation () {
+ public Object perform(SessionContext context)
+ throws RepositoryException {
+ NodeStateEx state = getNodeState(
+ absPath,
+ CHECK_PENDING_CHANGES | CHECK_LOCK | CHECK_HOLD,
+ Permission.NONE);
+ restore(state, context.getQName(versionName), removeExisting);
+ return this;
+ }
+ public String toString() {
+ return "versionManager.restore("
+ + absPath + ", " + versionName + ", "
+ + removeExisting + ")";
+ }
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void restore(
+ final String absPath, final Version version, final boolean removeExisting)
+ throws RepositoryException {
+ perform(new SessionWriteOperation