Merge remote-tracking branch 'xmlpers/develop' into develop
This commit is contained in:
commit
4ff74ccfdd
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
|
@ -0,0 +1,38 @@
|
||||||
|
ch.eitchnet.java.xmlpers
|
||||||
|
========================
|
||||||
|
|
||||||
|
[![Build Status](http://jenkins.eitchnet.ch/buildStatus/icon?job=ch.eitchnet.xmlpers)](http://jenkins.eitchnet.ch/view/ch.eitchnet/job/ch.eitchnet.xmlpers/)
|
||||||
|
|
||||||
|
Generic Java XML persistence layer. Implemented to be light-weight and simple to use
|
||||||
|
|
||||||
|
Dependencies
|
||||||
|
------------------------
|
||||||
|
XmlPers is built by Maven3 and has very few external dependencies. The current dependencies are:
|
||||||
|
* the Java Runtime Environment 6
|
||||||
|
* ch.eitchnet.utils
|
||||||
|
* slf4j 1.7.2
|
||||||
|
* slf4j-log4j bindings (only during tests)
|
||||||
|
* JUnit 4.10 (only during tests)
|
||||||
|
|
||||||
|
Features
|
||||||
|
------------------------
|
||||||
|
The idea behind XmlPers is to have a very lightweight database where each object is saved in its own XML file.
|
||||||
|
|
||||||
|
The model for XmlPers is that for each persistable class the following information is available:
|
||||||
|
* Type (e.g. the class name)
|
||||||
|
* Optional Sub Type (e.g. some type in your class)
|
||||||
|
* Id
|
||||||
|
|
||||||
|
This is not forced on the model itself, but in the DAO. Persisting changes is done by delegating to XmlFilePersister and the DAO must convert the object to a XML Document.
|
||||||
|
|
||||||
|
See the tests for a reference implementation.
|
||||||
|
|
||||||
|
Building
|
||||||
|
------------------------
|
||||||
|
*Prerequisites:
|
||||||
|
* JDK 6 is installed and JAVA_HOME is properly set and ../bin is in path
|
||||||
|
* Maven 3 is installed and MAVEN_HOME is properly set and ../bin is in path
|
||||||
|
* ch.eitchnet.utils is installed in your local Maven Repository
|
||||||
|
* Clone repository and change path to root
|
||||||
|
* Run maven:
|
||||||
|
* mvn clean install
|
|
@ -0,0 +1,71 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>ch.eitchnet</groupId>
|
||||||
|
<artifactId>ch.eitchnet.parent</artifactId>
|
||||||
|
<version>1.1.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../ch.eitchnet.parent/pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>ch.eitchnet.xmlpers</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<name>ch.eitchnet.xmlpers</name>
|
||||||
|
<url>https://github.com/eitchnet/ch.eitchnet.xmlpers</url>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<eitchnet.utils.version>1.1.0-SNAPSHOT</eitchnet.utils.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<!-- POM Reference: http://maven.apache.org/pom.html#Licenses -->
|
||||||
|
|
||||||
|
<inceptionYear>2011</inceptionYear>
|
||||||
|
|
||||||
|
<issueManagement>
|
||||||
|
<system>Github Issues</system>
|
||||||
|
<url>https://github.com/eitchnet/ch.eitchnet.xmlpers/issues</url>
|
||||||
|
</issueManagement>
|
||||||
|
|
||||||
|
<scm>
|
||||||
|
<connection>scm:git:https://github.com/eitchnet/ch.eitchnet.xmlpers.git</connection>
|
||||||
|
<developerConnection>scm:git:git@github.com:eitchnet/ch.eitchnet.xmlpers.git</developerConnection>
|
||||||
|
<url>https://github.com/eitchnet/ch.eitchnet.xmlpers</url>
|
||||||
|
<tag>HEAD</tag>
|
||||||
|
</scm>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.eitchnet</groupId>
|
||||||
|
<artifactId>ch.eitchnet.utils</artifactId>
|
||||||
|
<version>${eitchnet.utils.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-eclipse-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-site-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.api;
|
||||||
|
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
|
||||||
|
public interface DomParser<T> {
|
||||||
|
|
||||||
|
public T getObject();
|
||||||
|
|
||||||
|
public void setObject(T object);
|
||||||
|
|
||||||
|
public Document toDom();
|
||||||
|
|
||||||
|
public void fromDom(Document document);
|
||||||
|
}
|
|
@ -0,0 +1,199 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.api;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.impl.PathBuilder;
|
||||||
|
import ch.eitchnet.xmlpers.objref.ObjectRef;
|
||||||
|
|
||||||
|
public class FileDao {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(FileDao.class);
|
||||||
|
|
||||||
|
private final PersistenceTransaction tx;
|
||||||
|
private final boolean verbose;
|
||||||
|
private final PathBuilder pathBuilder;
|
||||||
|
|
||||||
|
public FileDao(PersistenceTransaction tx, PathBuilder pathBuilder, boolean verbose) {
|
||||||
|
this.tx = tx;
|
||||||
|
this.pathBuilder = pathBuilder;
|
||||||
|
this.verbose = verbose;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertIsIdRef(IoOperation ioOperation, ObjectRef objectRef) {
|
||||||
|
if (!objectRef.isLeaf()) {
|
||||||
|
String msg = "A {0} operation can only be performed with IdRefs!"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, ioOperation);
|
||||||
|
throw new XmlPersistenceException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> boolean exists(PersistenceContext<T> ctx) {
|
||||||
|
ObjectRef objectRef = ctx.getObjectRef();
|
||||||
|
assertIsIdRef(IoOperation.READ, objectRef);
|
||||||
|
File path = objectRef.getPath(this.pathBuilder);
|
||||||
|
return path.exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void performCreate(PersistenceContext<T> ctx) {
|
||||||
|
ObjectRef objectRef = ctx.getObjectRef();
|
||||||
|
assertIsIdRef(IoOperation.CREATE, objectRef);
|
||||||
|
File path = objectRef.getPath(this.pathBuilder);
|
||||||
|
logPath(IoOperation.CREATE, path, objectRef);
|
||||||
|
assertPathNotExists(path, objectRef);
|
||||||
|
createMissingParents(path, objectRef);
|
||||||
|
FileIo fileIo = new FileIo(path);
|
||||||
|
this.tx.getIoMode().write(ctx, fileIo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void performRead(PersistenceContext<T> ctx) {
|
||||||
|
ObjectRef objectRef = ctx.getObjectRef();
|
||||||
|
assertIsIdRef(IoOperation.READ, objectRef);
|
||||||
|
File path = objectRef.getPath(this.pathBuilder);
|
||||||
|
if (!path.exists()) {
|
||||||
|
ctx.setObject(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logPath(IoOperation.READ, path, objectRef);
|
||||||
|
FileIo fileIo = new FileIo(path);
|
||||||
|
this.tx.getIoMode().read(ctx, fileIo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void performUpdate(PersistenceContext<T> ctx) {
|
||||||
|
ObjectRef objectRef = ctx.getObjectRef();
|
||||||
|
assertIsIdRef(IoOperation.UPDATE, objectRef);
|
||||||
|
File path = objectRef.getPath(this.pathBuilder);
|
||||||
|
logPath(IoOperation.UPDATE, path, objectRef);
|
||||||
|
assertPathIsFileAndWritable(path, objectRef);
|
||||||
|
FileIo fileIo = new FileIo(path);
|
||||||
|
this.tx.getIoMode().write(ctx, fileIo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void performDelete(PersistenceContext<T> ctx) {
|
||||||
|
ObjectRef objectRef = ctx.getObjectRef();
|
||||||
|
assertIsIdRef(IoOperation.DELETE, objectRef);
|
||||||
|
File path = objectRef.getPath(this.pathBuilder);
|
||||||
|
logPath(IoOperation.DELETE, path, objectRef);
|
||||||
|
assertPathIsFileAndWritable(path, objectRef);
|
||||||
|
if (!path.delete()) {
|
||||||
|
String msg = "Failed to delete file {0}"; //$NON-NLS-1$
|
||||||
|
throw new RuntimeException(MessageFormat.format(msg, path.getAbsolutePath()));
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectRef parentRef = objectRef.getParent(this.tx);
|
||||||
|
deleteEmptyDirectories(parentRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteEmptyDirectories(ObjectRef objectRef) {
|
||||||
|
|
||||||
|
// root can't be deleted
|
||||||
|
if (objectRef.isRoot())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (objectRef.isLeaf()) {
|
||||||
|
throw new IllegalArgumentException("IdRefs don't reference directories!"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
objectRef.lock();
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
File directoryPath = objectRef.getPath(this.pathBuilder);
|
||||||
|
if (!directoryPath.isDirectory()) {
|
||||||
|
String msg = "The path for {0} is not a directory: {1}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, objectRef.getName(), directoryPath.getAbsolutePath());
|
||||||
|
throw new IllegalArgumentException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop if empty
|
||||||
|
if (directoryPath.list().length != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// delete
|
||||||
|
if (!directoryPath.delete()) {
|
||||||
|
String msg = "Deletion of empty directory for {0} at {1} failed! Check file permissions!"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, objectRef.getName(), directoryPath.getAbsolutePath());
|
||||||
|
throw new XmlPersistenceException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// log
|
||||||
|
if (this.verbose) {
|
||||||
|
String msg = "Deleted empty directory for {0} at {1}"; //$NON-NLS-1$
|
||||||
|
logger.info(MessageFormat.format(msg, objectRef.getName(), directoryPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
// recursively delete
|
||||||
|
ObjectRef parent = objectRef.getParent(this.tx);
|
||||||
|
deleteEmptyDirectories(parent);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
objectRef.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logPath(IoOperation operation, File path, ObjectRef objectRef) {
|
||||||
|
if (this.verbose) {
|
||||||
|
String msg = "Path for operation {0} for {1} is at {2}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, operation, objectRef.getName(), path.getAbsolutePath());
|
||||||
|
logger.info(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createMissingParents(File path, ObjectRef objectRef) {
|
||||||
|
ObjectRef parentRef = objectRef.getParent(this.tx);
|
||||||
|
parentRef.lock();
|
||||||
|
try {
|
||||||
|
File parentFile = parentRef.getPath(this.pathBuilder);
|
||||||
|
if (!parentFile.exists() && !parentFile.mkdirs()) {
|
||||||
|
String msg = "Could not create parent path for {0} at {1}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, objectRef.getName(), path.getAbsolutePath());
|
||||||
|
throw new XmlPersistenceException(msg);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
parentRef.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertPathIsFileAndWritable(File path, ObjectRef objectRef) {
|
||||||
|
if (!path.exists()) {
|
||||||
|
String msg = "Persistence unit does not exist for {0} at {1}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, objectRef.getName(), path.getAbsolutePath());
|
||||||
|
throw new XmlPersistenceException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!path.isFile() || !path.canWrite()) {
|
||||||
|
String msg;
|
||||||
|
msg = "Persistence unit is not a file or is not readable for {0} at {1}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, objectRef.getName(), path.getAbsolutePath());
|
||||||
|
throw new XmlPersistenceException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertPathNotExists(File path, ObjectRef objectRef) {
|
||||||
|
if (path.exists()) {
|
||||||
|
String msg = "Persistence unit already exists for {0} at {1}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, objectRef.getName(), path.getAbsolutePath());
|
||||||
|
throw new XmlPersistenceException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,205 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.api;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
|
||||||
|
import javanet.staxutils.IndentingXMLStreamWriter;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
import javax.xml.parsers.SAXParser;
|
||||||
|
import javax.xml.parsers.SAXParserFactory;
|
||||||
|
import javax.xml.stream.FactoryConfigurationError;
|
||||||
|
import javax.xml.stream.XMLOutputFactory;
|
||||||
|
import javax.xml.stream.XMLStreamException;
|
||||||
|
import javax.xml.stream.XMLStreamWriter;
|
||||||
|
import javax.xml.transform.OutputKeys;
|
||||||
|
import javax.xml.transform.Source;
|
||||||
|
import javax.xml.transform.Transformer;
|
||||||
|
import javax.xml.transform.TransformerException;
|
||||||
|
import javax.xml.transform.TransformerFactory;
|
||||||
|
import javax.xml.transform.TransformerFactoryConfigurationError;
|
||||||
|
import javax.xml.transform.dom.DOMSource;
|
||||||
|
import javax.xml.transform.stream.StreamResult;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
import org.xml.sax.helpers.DefaultHandler;
|
||||||
|
|
||||||
|
import ch.eitchnet.utils.exceptions.XmlException;
|
||||||
|
import ch.eitchnet.utils.helper.StringHelper;
|
||||||
|
import ch.eitchnet.utils.helper.XmlHelper;
|
||||||
|
import ch.eitchnet.xmlpers.util.DomUtil;
|
||||||
|
|
||||||
|
public class FileIo {
|
||||||
|
|
||||||
|
public static final String DEFAULT_XML_VERSION = "1.0"; //$NON-NLS-1$
|
||||||
|
public static final String DEFAULT_ENCODING = "utf-8"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(FileIo.class);
|
||||||
|
|
||||||
|
private final File path;
|
||||||
|
|
||||||
|
public FileIo(File path) {
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void writeSax(PersistenceContext<T> ctx) {
|
||||||
|
|
||||||
|
XMLStreamWriter writer = null;
|
||||||
|
try {
|
||||||
|
try (FileWriter fileWriter = new FileWriter(this.path);) {
|
||||||
|
|
||||||
|
XMLOutputFactory factory = XMLOutputFactory.newInstance();
|
||||||
|
writer = factory.createXMLStreamWriter(fileWriter);
|
||||||
|
writer = new IndentingXMLStreamWriter(writer);
|
||||||
|
|
||||||
|
// start document
|
||||||
|
writer.writeStartDocument(DEFAULT_ENCODING, DEFAULT_XML_VERSION);
|
||||||
|
|
||||||
|
// then delegate object writing to caller
|
||||||
|
SaxParser<T> saxParser = ctx.getParserFactor().getSaxParser();
|
||||||
|
saxParser.setObject(ctx.getObject());
|
||||||
|
saxParser.write(writer);
|
||||||
|
|
||||||
|
// and now end
|
||||||
|
writer.writeEndDocument();
|
||||||
|
writer.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (FactoryConfigurationError | XMLStreamException | IOException e) {
|
||||||
|
if (this.path.exists())
|
||||||
|
this.path.delete();
|
||||||
|
String msg = "Writing to file failed due to internal error: {0}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, e.getMessage());
|
||||||
|
throw new XmlException(msg, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
String msg = "Wrote SAX to {0}"; //$NON-NLS-1$
|
||||||
|
logger.info(MessageFormat.format(msg, this.path.getAbsolutePath()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void readSax(PersistenceContext<T> ctx) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
SAXParserFactory spf = SAXParserFactory.newInstance();
|
||||||
|
SAXParser sp = spf.newSAXParser();
|
||||||
|
|
||||||
|
SaxParser<T> saxParser = ctx.getParserFactor().getSaxParser();
|
||||||
|
DefaultHandler defaultHandler = saxParser.getDefaultHandler();
|
||||||
|
sp.parse(this.path, defaultHandler);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
String msg = "SAX parsed file {0}"; //$NON-NLS-1$
|
||||||
|
logger.info(MessageFormat.format(msg, this.path.getAbsolutePath()));
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.setObject(saxParser.getObject());
|
||||||
|
|
||||||
|
} catch (ParserConfigurationException | SAXException | IOException e) {
|
||||||
|
|
||||||
|
String msg = "Parsing failed due to internal error: {0}"; //$NON-NLS-1$
|
||||||
|
throw new XmlPersistenceException(MessageFormat.format(msg, e.getMessage()), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void writeDom(PersistenceContext<T> ctx) {
|
||||||
|
|
||||||
|
String lineSep = System.getProperty(XmlHelper.PROP_LINE_SEPARATOR);
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
DomParser<T> domParser = ctx.getParserFactor().getDomParser();
|
||||||
|
domParser.setObject(ctx.getObject());
|
||||||
|
Document document = domParser.toDom();
|
||||||
|
String encoding = document.getInputEncoding();
|
||||||
|
if (encoding == null || encoding.isEmpty()) {
|
||||||
|
// logger.info("No encoding passed. Using default encoding " + XmlHelper.DEFAULT_ENCODING);
|
||||||
|
encoding = XmlHelper.DEFAULT_ENCODING;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lineSep.equals(StringHelper.NEW_LINE)) {
|
||||||
|
logger.info("Overriding line separator to \\n"); //$NON-NLS-1$
|
||||||
|
System.setProperty(XmlHelper.PROP_LINE_SEPARATOR, StringHelper.NEW_LINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up a transformer
|
||||||
|
TransformerFactory transfac = TransformerFactory.newInstance();
|
||||||
|
Transformer transformer = transfac.newTransformer();
|
||||||
|
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); //$NON-NLS-1$
|
||||||
|
transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$
|
||||||
|
transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$
|
||||||
|
transformer.setOutputProperty(OutputKeys.ENCODING, encoding);
|
||||||
|
transformer.setOutputProperty("{http://xml.apache.org/xalan}indent-amount", "2"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
// transformer.setOutputProperty("{http://xml.apache.org/xalan}line-separator", "\t");
|
||||||
|
|
||||||
|
// Transform to file
|
||||||
|
StreamResult result = new StreamResult(this.path);
|
||||||
|
Source xmlSource = new DOMSource(document);
|
||||||
|
transformer.transform(xmlSource, result);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
String msg = MessageFormat.format("Wrote DOM to {0}", this.path.getAbsolutePath()); //$NON-NLS-1$
|
||||||
|
logger.info(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (TransformerFactoryConfigurationError | TransformerException e) {
|
||||||
|
|
||||||
|
if (this.path.exists())
|
||||||
|
this.path.delete();
|
||||||
|
|
||||||
|
String msg = "Writing to file failed due to internal error: {0}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, e.getMessage());
|
||||||
|
throw new XmlException(msg, e);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
System.setProperty(XmlHelper.PROP_LINE_SEPARATOR, lineSep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void readDom(PersistenceContext<T> ctx) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
DocumentBuilder docBuilder = DomUtil.createDocumentBuilder();
|
||||||
|
Document document = docBuilder.parse(this.path);
|
||||||
|
DomParser<T> domParser = ctx.getParserFactor().getDomParser();
|
||||||
|
domParser.fromDom(document);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
String msg = "DOM parsed file {0}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, this.path.getAbsolutePath());
|
||||||
|
logger.info(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.setObject(domParser.getObject());
|
||||||
|
|
||||||
|
} catch (SAXException | IOException e) {
|
||||||
|
String msg = "Parsing failed due to internal error: {0}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, e.getMessage());
|
||||||
|
throw new XmlPersistenceException(msg, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum IoMode {
|
||||||
|
|
||||||
|
DOM {
|
||||||
|
@Override
|
||||||
|
public <T> void write(PersistenceContext<T> ctx, FileIo fileIo) {
|
||||||
|
fileIo.writeDom(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> void read(PersistenceContext<T> ctx, FileIo fileIo) {
|
||||||
|
fileIo.readDom(ctx);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SAX {
|
||||||
|
@Override
|
||||||
|
public <T> void write(PersistenceContext<T> ctx, FileIo fileIo) {
|
||||||
|
fileIo.writeSax(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> void read(PersistenceContext<T> ctx, FileIo fileIo) {
|
||||||
|
fileIo.readSax(ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ctx
|
||||||
|
* @param fileIo
|
||||||
|
*/
|
||||||
|
public <T> void write(PersistenceContext<T> ctx, FileIo fileIo) {
|
||||||
|
throw new UnsupportedOperationException("Override me!"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ctx
|
||||||
|
* @param fileIo
|
||||||
|
*/
|
||||||
|
public <T> void read(PersistenceContext<T> ctx, FileIo fileIo) {
|
||||||
|
throw new UnsupportedOperationException("Override me!"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.api;
|
||||||
|
|
||||||
|
public enum IoOperation {
|
||||||
|
|
||||||
|
CREATE, READ, UPDATE, DELETE;
|
||||||
|
}
|
|
@ -0,0 +1,276 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.api;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.impl.PathBuilder;
|
||||||
|
import ch.eitchnet.xmlpers.objref.ObjectRef;
|
||||||
|
import ch.eitchnet.xmlpers.util.FilenameUtility;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class MetadataDao {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(MetadataDao.class);
|
||||||
|
|
||||||
|
private final PersistenceTransaction tx;
|
||||||
|
private final PathBuilder pathBuilder;
|
||||||
|
private final boolean verbose;
|
||||||
|
|
||||||
|
public MetadataDao(PathBuilder pathBuilder, PersistenceTransaction tx, boolean verbose) {
|
||||||
|
this.tx = tx;
|
||||||
|
this.pathBuilder = pathBuilder;
|
||||||
|
this.verbose = verbose;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> queryTypeSet(ObjectRef parentRef) {
|
||||||
|
assertNotClosed(this.tx);
|
||||||
|
assertNotIdRef(parentRef);
|
||||||
|
|
||||||
|
parentRef.lock();
|
||||||
|
try {
|
||||||
|
File queryPath = parentRef.getPath(this.pathBuilder);
|
||||||
|
Set<String> keySet = queryTypeSet(queryPath);
|
||||||
|
|
||||||
|
if (this.verbose) {
|
||||||
|
String msg = "Found {0} types for {1}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, keySet.size(), parentRef.getName());
|
||||||
|
logger.info(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return keySet;
|
||||||
|
} finally {
|
||||||
|
parentRef.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> queryKeySet(ObjectRef parentRef) {
|
||||||
|
assertNotClosed(this.tx);
|
||||||
|
assertNotRootRef(parentRef);
|
||||||
|
assertNotIdRef(parentRef);
|
||||||
|
|
||||||
|
parentRef.lock();
|
||||||
|
try {
|
||||||
|
File queryPath = parentRef.getPath(this.pathBuilder);
|
||||||
|
Set<String> keySet = queryKeySet(queryPath);
|
||||||
|
|
||||||
|
if (this.verbose) {
|
||||||
|
String msg = "Found {0} objects for {1}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, keySet.size(), parentRef.getName());
|
||||||
|
logger.info(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return keySet;
|
||||||
|
} finally {
|
||||||
|
parentRef.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long queryTypeSize(ObjectRef parentRef) {
|
||||||
|
assertNotClosed(this.tx);
|
||||||
|
assertNotRootRef(parentRef);
|
||||||
|
assertNotIdRef(parentRef);
|
||||||
|
|
||||||
|
parentRef.lock();
|
||||||
|
try {
|
||||||
|
File queryPath = parentRef.getPath(this.pathBuilder);
|
||||||
|
long numberOfFiles = queryTypeSize(queryPath);
|
||||||
|
|
||||||
|
if (this.verbose) {
|
||||||
|
String msg = "Found {0} types for {1}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, numberOfFiles, parentRef.getName());
|
||||||
|
logger.info(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return numberOfFiles;
|
||||||
|
} finally {
|
||||||
|
parentRef.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long querySize(ObjectRef parentRef) {
|
||||||
|
assertNotClosed(this.tx);
|
||||||
|
|
||||||
|
parentRef.lock();
|
||||||
|
try {
|
||||||
|
File queryPath = parentRef.getPath(this.pathBuilder);
|
||||||
|
long numberOfFiles = querySize(queryPath);
|
||||||
|
|
||||||
|
if (this.verbose) {
|
||||||
|
String msg = "Found {0} objects for {1}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, numberOfFiles, parentRef.getName());
|
||||||
|
logger.info(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return numberOfFiles;
|
||||||
|
} finally {
|
||||||
|
parentRef.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the types, i.e. directories in the given query path
|
||||||
|
*
|
||||||
|
* @param queryPath
|
||||||
|
* the path for which the types should be gathered
|
||||||
|
*
|
||||||
|
* @return a set of types in the given query path
|
||||||
|
*/
|
||||||
|
private Set<String> queryTypeSet(File queryPath) {
|
||||||
|
if (!queryPath.exists())
|
||||||
|
return Collections.emptySet();
|
||||||
|
|
||||||
|
if (!queryPath.isDirectory()) {
|
||||||
|
String msg = "The path is not a directory, thus can not query type set for it: {0}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, queryPath.getAbsolutePath());
|
||||||
|
throw new IllegalArgumentException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> keySet = new HashSet<>();
|
||||||
|
File[] subTypeFiles = queryPath.listFiles();
|
||||||
|
for (File subTypeFile : subTypeFiles) {
|
||||||
|
if (subTypeFile.isDirectory()) {
|
||||||
|
String type = subTypeFile.getName();
|
||||||
|
keySet.add(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return keySet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ids of all objects in the given query path, i.e. the id part of all the files in the given query path
|
||||||
|
*
|
||||||
|
* @param queryPath
|
||||||
|
* the path for which the ids should be gathered
|
||||||
|
*
|
||||||
|
* @return a set of ids for the objects in the given query path
|
||||||
|
*/
|
||||||
|
private Set<String> queryKeySet(File queryPath) {
|
||||||
|
if (!queryPath.exists())
|
||||||
|
return Collections.emptySet();
|
||||||
|
|
||||||
|
if (!queryPath.isDirectory()) {
|
||||||
|
String msg = "The path is not a directory, thus can not query key set for it: {0}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, queryPath.getAbsolutePath());
|
||||||
|
throw new IllegalArgumentException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> keySet = new HashSet<>();
|
||||||
|
|
||||||
|
File[] subTypeFiles = queryPath.listFiles();
|
||||||
|
for (File subTypeFile : subTypeFiles) {
|
||||||
|
if (subTypeFile.isFile()) {
|
||||||
|
String filename = subTypeFile.getName();
|
||||||
|
String id = FilenameUtility.getId(filename);
|
||||||
|
keySet.add(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return keySet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of all types, i.e. directories in the given query path
|
||||||
|
*
|
||||||
|
* @param queryPath
|
||||||
|
* the path in which to count the types
|
||||||
|
*
|
||||||
|
* @return the number of types in the given query path
|
||||||
|
*/
|
||||||
|
private long queryTypeSize(File queryPath) {
|
||||||
|
if (!queryPath.exists())
|
||||||
|
return 0L;
|
||||||
|
|
||||||
|
if (!queryPath.isDirectory()) {
|
||||||
|
String msg = "The path is not a directory, thus can not query type size for it: {0}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, queryPath.getAbsolutePath());
|
||||||
|
throw new IllegalArgumentException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
long numberOfFiles = 0l;
|
||||||
|
|
||||||
|
File[] subTypeFiles = queryPath.listFiles();
|
||||||
|
for (File subTypeFile : subTypeFiles) {
|
||||||
|
|
||||||
|
if (subTypeFile.isDirectory())
|
||||||
|
numberOfFiles++;
|
||||||
|
}
|
||||||
|
return numberOfFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of all objects in the given query path
|
||||||
|
*
|
||||||
|
* @param queryPath
|
||||||
|
* the path in which to count the objects
|
||||||
|
*
|
||||||
|
* @return the number of objects in the given query path
|
||||||
|
*/
|
||||||
|
private long querySize(File queryPath) {
|
||||||
|
if (!queryPath.exists())
|
||||||
|
return 0L;
|
||||||
|
|
||||||
|
if (!queryPath.isDirectory()) {
|
||||||
|
String msg = "The path is not a directory, thus can not query key size for it: {0}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, queryPath.getAbsolutePath());
|
||||||
|
throw new IllegalArgumentException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
long numberOfFiles = 0l;
|
||||||
|
|
||||||
|
File[] subTypeFiles = queryPath.listFiles();
|
||||||
|
for (File subTypeFile : subTypeFiles) {
|
||||||
|
|
||||||
|
if (subTypeFile.isFile())
|
||||||
|
numberOfFiles++;
|
||||||
|
}
|
||||||
|
return numberOfFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertNotClosed(PersistenceTransaction tx) {
|
||||||
|
if (!tx.isOpen()) {
|
||||||
|
String msg = "Transaction has been closed and thus no operation can be performed!"; //$NON-NLS-1$
|
||||||
|
throw new IllegalStateException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertNotIdRef(ObjectRef objectRef) {
|
||||||
|
if (objectRef.isLeaf()) {
|
||||||
|
String msg = "IdRef not allowed: {0}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, objectRef.getName());
|
||||||
|
throw new IllegalArgumentException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertNotRootRef(ObjectRef objectRef) {
|
||||||
|
if (objectRef.isRoot()) {
|
||||||
|
String msg = "RootRef not allowed: {0}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, objectRef.getName());
|
||||||
|
throw new IllegalArgumentException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.api;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ModificationResult {
|
||||||
|
|
||||||
|
private final String key;
|
||||||
|
private final List<?> created;
|
||||||
|
private final List<?> updated;
|
||||||
|
private final List<?> deleted;
|
||||||
|
|
||||||
|
public ModificationResult(String key) {
|
||||||
|
this.key = key;
|
||||||
|
this.created = new ArrayList<>();
|
||||||
|
this.updated = new ArrayList<>();
|
||||||
|
this.deleted = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModificationResult(String key, List<?> created, List<?> updated, List<?> deleted) {
|
||||||
|
this.key = key;
|
||||||
|
this.created = created;
|
||||||
|
this.updated = updated;
|
||||||
|
this.deleted = deleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKey() {
|
||||||
|
return this.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> List<T> getCreated() {
|
||||||
|
return (List<T>) this.created;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> List<T> getUpdated() {
|
||||||
|
return (List<T>) this.updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> List<T> getDeleted() {
|
||||||
|
return (List<T>) this.deleted;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,305 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.api;
|
||||||
|
|
||||||
|
import static ch.eitchnet.xmlpers.util.AssertionUtil.assertIsIdRef;
|
||||||
|
import static ch.eitchnet.xmlpers.util.AssertionUtil.assertIsNotIdRef;
|
||||||
|
import static ch.eitchnet.xmlpers.util.AssertionUtil.assertIsNotRootRef;
|
||||||
|
import static ch.eitchnet.xmlpers.util.AssertionUtil.assertNotNull;
|
||||||
|
import static ch.eitchnet.xmlpers.util.AssertionUtil.assertObjectRead;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import ch.eitchnet.utils.objectfilter.ObjectFilter;
|
||||||
|
import ch.eitchnet.xmlpers.objref.ObjectRef;
|
||||||
|
import ch.eitchnet.xmlpers.objref.SubTypeRef;
|
||||||
|
import ch.eitchnet.xmlpers.objref.TypeRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ObjectDao {
|
||||||
|
|
||||||
|
private final ObjectFilter objectFilter;
|
||||||
|
private final FileDao fileDao;
|
||||||
|
private final PersistenceTransaction tx;
|
||||||
|
private PersistenceContextFactoryDelegator ctxFactoryDelegator;
|
||||||
|
|
||||||
|
public ObjectDao(PersistenceTransaction tx, FileDao fileDao, ObjectFilter objectFilter) {
|
||||||
|
this.tx = tx;
|
||||||
|
this.fileDao = fileDao;
|
||||||
|
this.objectFilter = objectFilter;
|
||||||
|
this.ctxFactoryDelegator = this.tx.getRealm().getCtxFactoryDelegator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void add(T object) {
|
||||||
|
assertNotClosed();
|
||||||
|
assertNotNull(object);
|
||||||
|
PersistenceContext<T> ctx = createCtx(object);
|
||||||
|
ctx.getObjectRef().lock();
|
||||||
|
this.objectFilter.add(ctx.getObjectRef().getType(), ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void addAll(List<T> objects) {
|
||||||
|
assertNotClosed();
|
||||||
|
assertNotNull(objects);
|
||||||
|
if (!objects.isEmpty()) {
|
||||||
|
for (T object : objects) {
|
||||||
|
PersistenceContext<T> ctx = createCtx(object);
|
||||||
|
ctx.getObjectRef().lock();
|
||||||
|
this.objectFilter.add(ctx.getObjectRef().getType(), ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void update(T object) {
|
||||||
|
assertNotClosed();
|
||||||
|
assertNotNull(object);
|
||||||
|
PersistenceContext<T> ctx = createCtx(object);
|
||||||
|
ctx.getObjectRef().lock();
|
||||||
|
this.objectFilter.update(ctx.getObjectRef().getType(), ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void updateAll(List<T> objects) {
|
||||||
|
assertNotClosed();
|
||||||
|
assertNotNull(objects);
|
||||||
|
if (!objects.isEmpty()) {
|
||||||
|
for (T object : objects) {
|
||||||
|
PersistenceContext<T> ctx = createCtx(object);
|
||||||
|
ctx.getObjectRef().lock();
|
||||||
|
this.objectFilter.update(ctx.getObjectRef().getType(), ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void remove(T object) {
|
||||||
|
assertNotClosed();
|
||||||
|
assertNotNull(object);
|
||||||
|
PersistenceContext<T> ctx = createCtx(object);
|
||||||
|
ctx.getObjectRef().lock();
|
||||||
|
this.objectFilter.remove(ctx.getObjectRef().getType(), ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void removeAll(List<T> objects) {
|
||||||
|
assertNotClosed();
|
||||||
|
assertNotNull(objects);
|
||||||
|
if (!objects.isEmpty()) {
|
||||||
|
for (T object : objects) {
|
||||||
|
PersistenceContext<T> ctx = createCtx(object);
|
||||||
|
ctx.getObjectRef().lock();
|
||||||
|
this.objectFilter.remove(ctx.getObjectRef().getType(), ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> long removeAllBy(TypeRef typeRef) {
|
||||||
|
assertNotClosed();
|
||||||
|
|
||||||
|
long removed = 0;
|
||||||
|
|
||||||
|
Set<ObjectRef> refs = new HashSet<>();
|
||||||
|
typeRef.lock();
|
||||||
|
refs.add(typeRef);
|
||||||
|
try {
|
||||||
|
|
||||||
|
Set<String> types = this.tx.getMetadataDao().queryTypeSet(typeRef);
|
||||||
|
for (String type : types) {
|
||||||
|
ObjectRef childTypeRef = typeRef.getChildTypeRef(this.tx, type);
|
||||||
|
childTypeRef.lock();
|
||||||
|
refs.add(childTypeRef);
|
||||||
|
|
||||||
|
Set<String> ids = queryKeySet(childTypeRef);
|
||||||
|
for (String id : ids) {
|
||||||
|
|
||||||
|
ObjectRef idRef = childTypeRef.getChildIdRef(this.tx, id);
|
||||||
|
|
||||||
|
PersistenceContext<T> ctx = createCtx(idRef);
|
||||||
|
ctx.getObjectRef().lock();
|
||||||
|
this.objectFilter.remove(ctx.getObjectRef().getType(), ctx);
|
||||||
|
removed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
for (ObjectRef ref : refs) {
|
||||||
|
ref.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> long removeAllBy(SubTypeRef subTypeRef) {
|
||||||
|
assertNotClosed();
|
||||||
|
assertIsNotRootRef(subTypeRef);
|
||||||
|
assertIsNotIdRef(subTypeRef);
|
||||||
|
|
||||||
|
long removed = 0;
|
||||||
|
|
||||||
|
subTypeRef.lock();
|
||||||
|
try {
|
||||||
|
Set<String> ids = queryKeySet(subTypeRef);
|
||||||
|
for (String id : ids) {
|
||||||
|
|
||||||
|
ObjectRef idRef = subTypeRef.getChildIdRef(this.tx, id);
|
||||||
|
|
||||||
|
PersistenceContext<T> ctx = createCtx(idRef);
|
||||||
|
ctx.getObjectRef().lock();
|
||||||
|
this.objectFilter.remove(ctx.getObjectRef().getType(), ctx);
|
||||||
|
removed++;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
subTypeRef.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void removeById(ObjectRef objectRef) {
|
||||||
|
assertNotClosed();
|
||||||
|
assertIsIdRef(objectRef);
|
||||||
|
PersistenceContext<T> ctx = createCtx(objectRef);
|
||||||
|
ctx.getObjectRef().lock();
|
||||||
|
this.objectFilter.remove(objectRef.getType(), ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void removeAll(ObjectRef parentRef) {
|
||||||
|
assertNotClosed();
|
||||||
|
assertIsNotIdRef(parentRef);
|
||||||
|
assertIsNotRootRef(parentRef);
|
||||||
|
|
||||||
|
parentRef.lock();
|
||||||
|
try {
|
||||||
|
|
||||||
|
Set<String> keySet = queryKeySet(parentRef);
|
||||||
|
for (String id : keySet) {
|
||||||
|
|
||||||
|
ObjectRef childRef = parentRef.getChildIdRef(this.tx, id);
|
||||||
|
PersistenceContext<T> ctx = createCtx(childRef);
|
||||||
|
ctx.getObjectRef().lock();
|
||||||
|
this.objectFilter.remove(childRef.getType(), ctx);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
parentRef.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> boolean hasElement(ObjectRef objectRef) {
|
||||||
|
assertNotClosed();
|
||||||
|
assertIsIdRef(objectRef);
|
||||||
|
|
||||||
|
objectRef.lock();
|
||||||
|
try {
|
||||||
|
PersistenceContext<T> ctx = objectRef.<T> createPersistenceContext(this.tx);
|
||||||
|
return this.fileDao.exists(ctx);
|
||||||
|
} finally {
|
||||||
|
objectRef.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T queryById(ObjectRef objectRef) {
|
||||||
|
assertNotClosed();
|
||||||
|
assertIsIdRef(objectRef);
|
||||||
|
|
||||||
|
objectRef.lock();
|
||||||
|
try {
|
||||||
|
PersistenceContext<T> ctx = objectRef.<T> createPersistenceContext(this.tx);
|
||||||
|
this.fileDao.performRead(ctx);
|
||||||
|
return ctx.getObject();
|
||||||
|
} finally {
|
||||||
|
objectRef.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> List<T> queryAll(ObjectRef parentRef) {
|
||||||
|
assertNotClosed();
|
||||||
|
assertIsNotIdRef(parentRef);
|
||||||
|
|
||||||
|
parentRef.lock();
|
||||||
|
try {
|
||||||
|
|
||||||
|
MetadataDao metadataDao = this.tx.getMetadataDao();
|
||||||
|
Set<String> keySet = metadataDao.queryKeySet(parentRef);
|
||||||
|
|
||||||
|
List<T> result = new ArrayList<>();
|
||||||
|
for (String id : keySet) {
|
||||||
|
|
||||||
|
ObjectRef childRef = parentRef.getChildIdRef(this.tx, id);
|
||||||
|
PersistenceContext<T> childCtx = childRef.createPersistenceContext(this.tx);
|
||||||
|
childCtx.getObjectRef().lock();
|
||||||
|
try {
|
||||||
|
this.fileDao.performRead(childCtx);
|
||||||
|
assertObjectRead(childCtx);
|
||||||
|
result.add(childCtx.getObject());
|
||||||
|
} finally {
|
||||||
|
childCtx.getObjectRef().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
parentRef.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> queryKeySet(ObjectRef parentRef) {
|
||||||
|
assertNotClosed();
|
||||||
|
assertIsNotIdRef(parentRef);
|
||||||
|
|
||||||
|
parentRef.lock();
|
||||||
|
try {
|
||||||
|
MetadataDao metadataDao = this.tx.getMetadataDao();
|
||||||
|
Set<String> keySet = metadataDao.queryKeySet(parentRef);
|
||||||
|
return keySet;
|
||||||
|
} finally {
|
||||||
|
parentRef.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long querySize(ObjectRef parentRef) {
|
||||||
|
assertNotClosed();
|
||||||
|
assertIsNotIdRef(parentRef);
|
||||||
|
|
||||||
|
parentRef.lock();
|
||||||
|
try {
|
||||||
|
MetadataDao metadataDao = this.tx.getMetadataDao();
|
||||||
|
long size = metadataDao.querySize(parentRef);
|
||||||
|
return size;
|
||||||
|
} finally {
|
||||||
|
parentRef.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> PersistenceContext<T> createCtx(T object) {
|
||||||
|
return this.ctxFactoryDelegator.<T> getCtxFactory(object.getClass()).createCtx(this.tx.getObjectRefCache(),
|
||||||
|
object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> PersistenceContext<T> createCtx(ObjectRef objectRef) {
|
||||||
|
String type = objectRef.getType();
|
||||||
|
PersistenceContextFactory<T> ctxFactory = this.ctxFactoryDelegator.<T> getCtxFactory(type);
|
||||||
|
return ctxFactory.createCtx(objectRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertNotClosed() {
|
||||||
|
if (!this.tx.isOpen())
|
||||||
|
throw new IllegalStateException("Transaction has been closed and thus no operation can be performed!"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.api;
|
||||||
|
|
||||||
|
public interface ParserFactory<T> {
|
||||||
|
|
||||||
|
public DomParser<T> getDomParser();
|
||||||
|
|
||||||
|
public SaxParser<T> getSaxParser();
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
public class PersistenceConstants {
|
||||||
|
|
||||||
|
private static final String PROP_PREFIX = "ch.eitchnet.xmlpers.";
|
||||||
|
public static final String PROP_VERBOSE = PROP_PREFIX + "verbose";
|
||||||
|
public static final String PROP_BASEPATH = PROP_PREFIX + "basePath";
|
||||||
|
public static final String PROP_DAO_FACTORY_CLASS = PROP_PREFIX + "daoFactoryClass";
|
||||||
|
public static final String PROP_XML_IO_MOD = PROP_PREFIX + "ioMode";
|
||||||
|
public static final String PROP_LOCK_TIME_MILLIS = PROP_PREFIX + "lockTimeSeconds";
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.api;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.objref.ObjectRef;
|
||||||
|
|
||||||
|
public class PersistenceContext<T> {
|
||||||
|
|
||||||
|
private final ObjectRef objectRef;
|
||||||
|
private T object;
|
||||||
|
private ParserFactory<T> parserFactory;
|
||||||
|
|
||||||
|
public PersistenceContext(ObjectRef objectRef) {
|
||||||
|
this.objectRef = objectRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjectRef getObjectRef() {
|
||||||
|
return this.objectRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getObject() {
|
||||||
|
return this.object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setObject(T object) {
|
||||||
|
this.object = object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParserFactory<T> getParserFactor() {
|
||||||
|
return this.parserFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParserFactory(ParserFactory<T> parserFactory) {
|
||||||
|
this.parserFactory = parserFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((this.objectRef == null) ? 0 : this.objectRef.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
PersistenceContext<?> other = (PersistenceContext<?>) obj;
|
||||||
|
if (this.objectRef == null) {
|
||||||
|
if (other.objectRef != null)
|
||||||
|
return false;
|
||||||
|
} else if (!this.objectRef.equals(other.objectRef))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append("PersistenceContext [objectRef=");
|
||||||
|
builder.append(this.objectRef);
|
||||||
|
builder.append(", object=");
|
||||||
|
builder.append(this.object);
|
||||||
|
builder.append(", parserFactory=");
|
||||||
|
builder.append(this.parserFactory);
|
||||||
|
builder.append("]");
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.api;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.objref.ObjectRef;
|
||||||
|
import ch.eitchnet.xmlpers.objref.ObjectReferenceCache;
|
||||||
|
|
||||||
|
public interface PersistenceContextFactory<T> {
|
||||||
|
|
||||||
|
public PersistenceContext<T> createCtx(ObjectRef objectRef);
|
||||||
|
|
||||||
|
public PersistenceContext<T> createCtx(ObjectReferenceCache objectRefCache, T t);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.api;
|
||||||
|
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class PersistenceContextFactoryDelegator {
|
||||||
|
|
||||||
|
private Map<String, PersistenceContextFactory<?>> contextFactoryCacheByType;
|
||||||
|
private Map<Class<?>, PersistenceContextFactory<?>> contextFactoryCacheByClass;
|
||||||
|
|
||||||
|
public PersistenceContextFactoryDelegator() {
|
||||||
|
this.contextFactoryCacheByType = new HashMap<>();
|
||||||
|
this.contextFactoryCacheByClass = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerPersistenceContextFactory(Class<?> classType, String type,
|
||||||
|
PersistenceContextFactory<?> ctxFactory) {
|
||||||
|
|
||||||
|
this.contextFactoryCacheByClass.put(classType, ctxFactory);
|
||||||
|
this.contextFactoryCacheByType.put(type, ctxFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> PersistenceContextFactory<T> getCtxFactory(Class<?> classType) {
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
PersistenceContextFactory<T> ctxFactory = (PersistenceContextFactory<T>) this.contextFactoryCacheByClass
|
||||||
|
.get(classType);
|
||||||
|
if (ctxFactory != null)
|
||||||
|
return ctxFactory;
|
||||||
|
|
||||||
|
String msg = "No context factory is registered for {0}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, classType);
|
||||||
|
throw new IllegalArgumentException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> PersistenceContextFactory<T> getCtxFactory(String type) {
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
PersistenceContextFactory<T> ctxFactory = (PersistenceContextFactory<T>) this.contextFactoryCacheByType
|
||||||
|
.get(type);
|
||||||
|
if (ctxFactory != null)
|
||||||
|
return ctxFactory;
|
||||||
|
|
||||||
|
String msg = "No context factory is registered for type {0}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, type);
|
||||||
|
throw new IllegalArgumentException(msg);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface PersistenceManager {
|
||||||
|
|
||||||
|
public static final String DEFAULT_REALM = "defaultRealm"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
public PersistenceContextFactoryDelegator getCtxFactory();
|
||||||
|
|
||||||
|
public PersistenceTransaction openTx();
|
||||||
|
|
||||||
|
public PersistenceTransaction openTx(String realm);
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.api;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.impl.DefaultPersistenceManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class PersistenceManagerLoader {
|
||||||
|
|
||||||
|
public static PersistenceManager load(Properties properties) {
|
||||||
|
|
||||||
|
DefaultPersistenceManager persistenceManager = new DefaultPersistenceManager();
|
||||||
|
persistenceManager.initialize(properties);
|
||||||
|
return persistenceManager;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.api;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.objref.ObjectReferenceCache;
|
||||||
|
|
||||||
|
public interface PersistenceRealm {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the realm
|
||||||
|
*/
|
||||||
|
public abstract String getRealmName();
|
||||||
|
|
||||||
|
public abstract PersistenceContextFactoryDelegator getCtxFactoryDelegator();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the objectRefCache
|
||||||
|
*/
|
||||||
|
public abstract ObjectReferenceCache getObjectRefCache();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the persistenceManager
|
||||||
|
*/
|
||||||
|
public abstract PersistenceManager getPersistenceManager();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.api;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.objref.ObjectReferenceCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface PersistenceTransaction extends AutoCloseable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link TransactionResult} for this transaction
|
||||||
|
*
|
||||||
|
* @return the {@link TransactionResult}
|
||||||
|
*
|
||||||
|
* @throws IllegalStateException
|
||||||
|
* if the transaction has not yet been closed
|
||||||
|
*/
|
||||||
|
public TransactionResult getTransactionResult() throws IllegalStateException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws IllegalStateException
|
||||||
|
* if a result is already set
|
||||||
|
*/
|
||||||
|
public void setTransactionResult(TransactionResult txResult) throws IllegalStateException;
|
||||||
|
|
||||||
|
public void setCloseStrategy(TransactionCloseStrategy closeStrategy);
|
||||||
|
|
||||||
|
public void autoCloseableCommit();
|
||||||
|
|
||||||
|
public void autoCloseableRollback();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws XmlPersistenceException;
|
||||||
|
|
||||||
|
public boolean isOpen();
|
||||||
|
|
||||||
|
public ObjectDao getObjectDao();
|
||||||
|
|
||||||
|
public MetadataDao getMetadataDao();
|
||||||
|
|
||||||
|
public FileDao getFileDao();
|
||||||
|
|
||||||
|
public ObjectReferenceCache getObjectRefCache();
|
||||||
|
|
||||||
|
public PersistenceRealm getRealm();
|
||||||
|
|
||||||
|
public IoMode getIoMode();
|
||||||
|
|
||||||
|
public void setIoMode(IoMode ioMode);
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.api;
|
||||||
|
|
||||||
|
import javax.xml.stream.XMLStreamException;
|
||||||
|
import javax.xml.stream.XMLStreamWriter;
|
||||||
|
|
||||||
|
import org.xml.sax.helpers.DefaultHandler;
|
||||||
|
|
||||||
|
public interface SaxParser<T> {
|
||||||
|
|
||||||
|
public T getObject();
|
||||||
|
|
||||||
|
public void setObject(T object);
|
||||||
|
|
||||||
|
public DefaultHandler getDefaultHandler();
|
||||||
|
|
||||||
|
public void write(XMLStreamWriter xmlWriter) throws XMLStreamException;
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.api;
|
||||||
|
|
||||||
|
public enum TransactionCloseStrategy {
|
||||||
|
COMMIT() {
|
||||||
|
@Override
|
||||||
|
public void close(PersistenceTransaction tx) {
|
||||||
|
tx.autoCloseableCommit();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
ROLLBACK() {
|
||||||
|
@Override
|
||||||
|
public void close(PersistenceTransaction tx) {
|
||||||
|
tx.autoCloseableRollback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tx
|
||||||
|
*/
|
||||||
|
public void close(PersistenceTransaction tx) {
|
||||||
|
throw new UnsupportedOperationException("Override in enum!"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,218 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.api;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import ch.eitchnet.utils.helper.StringHelper;
|
||||||
|
|
||||||
|
public class TransactionResult {
|
||||||
|
|
||||||
|
private String realm;
|
||||||
|
private TransactionState state;
|
||||||
|
private Exception failCause;
|
||||||
|
|
||||||
|
private Date startTime;
|
||||||
|
private long txDuration;
|
||||||
|
private long closeDuration;
|
||||||
|
|
||||||
|
private Map<String, ModificationResult> modificationByKey;
|
||||||
|
|
||||||
|
public TransactionResult() {
|
||||||
|
this.state = TransactionState.OPEN;
|
||||||
|
this.modificationByKey = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the realm
|
||||||
|
*/
|
||||||
|
public String getRealm() {
|
||||||
|
return this.realm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param realm
|
||||||
|
* the realm to set
|
||||||
|
*/
|
||||||
|
public void setRealm(String realm) {
|
||||||
|
this.realm = realm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the state
|
||||||
|
*/
|
||||||
|
public TransactionState getState() {
|
||||||
|
return this.state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param state
|
||||||
|
* the state to set
|
||||||
|
*/
|
||||||
|
public void setState(TransactionState state) {
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The internal exception why the transaction failed
|
||||||
|
*
|
||||||
|
* @return the failCause
|
||||||
|
*/
|
||||||
|
public Exception getFailCause() {
|
||||||
|
return this.failCause;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param failCause
|
||||||
|
* the failCause to set
|
||||||
|
*/
|
||||||
|
public void setFailCause(Exception failCause) {
|
||||||
|
this.failCause = failCause;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start time of the transaction
|
||||||
|
*
|
||||||
|
* @return the startTime
|
||||||
|
*/
|
||||||
|
public Date getStartTime() {
|
||||||
|
return this.startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param startTime
|
||||||
|
* the startTime to set
|
||||||
|
*/
|
||||||
|
public void setStartTime(Date startTime) {
|
||||||
|
this.startTime = startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The duration the transaction was open in nanoseconds
|
||||||
|
*
|
||||||
|
* @return the txDuration
|
||||||
|
*/
|
||||||
|
public long getTxDuration() {
|
||||||
|
return this.txDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param txDuration
|
||||||
|
* the txDuration to set
|
||||||
|
*/
|
||||||
|
public void setTxDuration(long txDuration) {
|
||||||
|
this.txDuration = txDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The duration the transaction took to close in nanoseconds
|
||||||
|
*
|
||||||
|
* @return the closeDuration
|
||||||
|
*/
|
||||||
|
public long getCloseDuration() {
|
||||||
|
return this.closeDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param closeDuration
|
||||||
|
* the closeDuration to set
|
||||||
|
*/
|
||||||
|
public void setCloseDuration(long closeDuration) {
|
||||||
|
this.closeDuration = closeDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param modificationByKey
|
||||||
|
* the modificationByKey to set
|
||||||
|
*/
|
||||||
|
public void setModificationByKey(Map<String, ModificationResult> modificationByKey) {
|
||||||
|
this.modificationByKey = modificationByKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Set<String> getKeys() {
|
||||||
|
return this.modificationByKey.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ModificationResult getModificationResult(String key) {
|
||||||
|
return this.modificationByKey.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
public String getLogMessage() {
|
||||||
|
|
||||||
|
int nrOfObjects = 0;
|
||||||
|
for (ModificationResult result : this.modificationByKey.values()) {
|
||||||
|
nrOfObjects += result.getCreated().size();
|
||||||
|
nrOfObjects += result.getUpdated().size();
|
||||||
|
nrOfObjects += result.getDeleted().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("TX for realm ");
|
||||||
|
sb.append(getRealm());
|
||||||
|
switch (this.state) {
|
||||||
|
case OPEN:
|
||||||
|
sb.append(" is still open after ");
|
||||||
|
break;
|
||||||
|
case COMMITTED:
|
||||||
|
sb.append(" was completed after ");
|
||||||
|
break;
|
||||||
|
case ROLLED_BACK:
|
||||||
|
sb.append(" was rolled back after ");
|
||||||
|
break;
|
||||||
|
case FAILED:
|
||||||
|
sb.append(" has failed after ");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sb.append(" is in unhandled state ");
|
||||||
|
sb.append(this.state);
|
||||||
|
sb.append(" after ");
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.append(StringHelper.formatNanoDuration(this.txDuration));
|
||||||
|
sb.append(" with close operation taking ");
|
||||||
|
sb.append(StringHelper.formatNanoDuration(this.closeDuration));
|
||||||
|
sb.append(". ");
|
||||||
|
sb.append(nrOfObjects);
|
||||||
|
sb.append(" objects in ");
|
||||||
|
sb.append(this.modificationByKey.size());
|
||||||
|
sb.append(" types were modified.");
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all fields of this result, allowing it to be reused
|
||||||
|
*/
|
||||||
|
public void clear() {
|
||||||
|
this.realm = null;
|
||||||
|
this.state = null;
|
||||||
|
this.failCause = null;
|
||||||
|
this.startTime = null;
|
||||||
|
this.txDuration = 0L;
|
||||||
|
this.closeDuration = 0L;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.api;
|
||||||
|
|
||||||
|
public enum TransactionState {
|
||||||
|
OPEN, //
|
||||||
|
COMMITTED, //
|
||||||
|
ROLLED_BACK, //
|
||||||
|
FAILED;
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*/
|
||||||
|
public class XmlPersistenceException extends RuntimeException {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param message
|
||||||
|
* @param cause
|
||||||
|
*/
|
||||||
|
public XmlPersistenceException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param message
|
||||||
|
*/
|
||||||
|
public XmlPersistenceException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.impl;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import ch.eitchnet.utils.helper.PropertiesHelper;
|
||||||
|
import ch.eitchnet.utils.helper.StringHelper;
|
||||||
|
import ch.eitchnet.xmlpers.api.IoMode;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceConstants;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceContextFactoryDelegator;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceManager;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceTransaction;
|
||||||
|
import ch.eitchnet.xmlpers.api.XmlPersistenceException;
|
||||||
|
import ch.eitchnet.xmlpers.objref.LockableObject;
|
||||||
|
import ch.eitchnet.xmlpers.objref.ObjectReferenceCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DefaultPersistenceManager implements PersistenceManager {
|
||||||
|
|
||||||
|
protected static final Logger logger = LoggerFactory.getLogger(DefaultPersistenceManager.class);
|
||||||
|
|
||||||
|
protected boolean initialized;
|
||||||
|
protected boolean verbose;
|
||||||
|
protected IoMode defaultIoMode;
|
||||||
|
protected Properties properties;
|
||||||
|
protected Map<String, DefaultPersistenceRealm> realmMap;
|
||||||
|
private PersistenceContextFactoryDelegator ctxFactory;
|
||||||
|
|
||||||
|
public void initialize(Properties properties) {
|
||||||
|
if (this.initialized)
|
||||||
|
throw new IllegalStateException("Already initialized!"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
String context = DefaultPersistenceManager.class.getSimpleName();
|
||||||
|
|
||||||
|
// get properties
|
||||||
|
boolean verbose = PropertiesHelper.getPropertyBool(properties, context, PersistenceConstants.PROP_VERBOSE,
|
||||||
|
Boolean.FALSE).booleanValue();
|
||||||
|
String ioModeS = PropertiesHelper.getProperty(properties, context, PersistenceConstants.PROP_XML_IO_MOD,
|
||||||
|
IoMode.DOM.name());
|
||||||
|
IoMode ioMode = IoMode.valueOf(ioModeS);
|
||||||
|
long lockTime = PropertiesHelper.getPropertyLong(properties, context,
|
||||||
|
PersistenceConstants.PROP_LOCK_TIME_MILLIS, 10000L);
|
||||||
|
|
||||||
|
// set lock time on LockableObject
|
||||||
|
try {
|
||||||
|
Field lockTimeField = LockableObject.class.getDeclaredField("tryLockTime");//$NON-NLS-1$
|
||||||
|
lockTimeField.setAccessible(true);
|
||||||
|
lockTimeField.setLong(null, lockTime);
|
||||||
|
logger.info("Using a max lock acquire time of " + StringHelper.formatMillisecondsDuration(lockTime)); //$NON-NLS-1$
|
||||||
|
} catch (SecurityException | NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) {
|
||||||
|
throw new RuntimeException("Failed to configure tryLockTime on LockableObject!", e); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate base path
|
||||||
|
validateBasePath(properties);
|
||||||
|
|
||||||
|
this.properties = properties;
|
||||||
|
this.verbose = verbose;
|
||||||
|
this.defaultIoMode = ioMode;
|
||||||
|
this.realmMap = new HashMap<>();
|
||||||
|
this.ctxFactory = new PersistenceContextFactoryDelegator();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateBasePath(Properties properties) {
|
||||||
|
String context = DefaultPersistenceManager.class.getSimpleName();
|
||||||
|
String basePath = PropertiesHelper.getProperty(properties, context, PersistenceConstants.PROP_BASEPATH, null);
|
||||||
|
|
||||||
|
// validate base path exists and is writable
|
||||||
|
File basePathF = new File(basePath);
|
||||||
|
if (!basePathF.exists())
|
||||||
|
throw new XmlPersistenceException(MessageFormat.format("The database store path does not exist at {0}", //$NON-NLS-1$
|
||||||
|
basePathF.getAbsolutePath()));
|
||||||
|
if (!basePathF.canWrite())
|
||||||
|
throw new XmlPersistenceException(MessageFormat.format("The database store path is not writeable at {0}", //$NON-NLS-1$
|
||||||
|
basePathF.getAbsolutePath()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PersistenceContextFactoryDelegator getCtxFactory() {
|
||||||
|
return this.ctxFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PersistenceTransaction openTx() {
|
||||||
|
return openTx(DEFAULT_REALM);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized PersistenceTransaction openTx(String realmName) {
|
||||||
|
|
||||||
|
DefaultPersistenceRealm persistenceRealm = this.realmMap.get(realmName);
|
||||||
|
if (persistenceRealm == null) {
|
||||||
|
|
||||||
|
PathBuilder pathBuilder = new PathBuilder(realmName, this.properties);
|
||||||
|
ObjectReferenceCache objectRefCache = new ObjectReferenceCache(realmName);
|
||||||
|
persistenceRealm = new DefaultPersistenceRealm(realmName, this, this.ctxFactory, pathBuilder,
|
||||||
|
objectRefCache);
|
||||||
|
|
||||||
|
this.realmMap.put(realmName, persistenceRealm);
|
||||||
|
}
|
||||||
|
|
||||||
|
PersistenceTransaction tx = new DefaultPersistenceTransaction(persistenceRealm, this.verbose);
|
||||||
|
tx.setIoMode(this.defaultIoMode);
|
||||||
|
return tx;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.impl;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceContextFactoryDelegator;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceManager;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceRealm;
|
||||||
|
import ch.eitchnet.xmlpers.objref.ObjectReferenceCache;
|
||||||
|
|
||||||
|
public class DefaultPersistenceRealm implements PersistenceRealm {
|
||||||
|
private final PersistenceManager persistenceManager;
|
||||||
|
private final PersistenceContextFactoryDelegator ctxFactory;
|
||||||
|
private final String realmName;
|
||||||
|
private final ObjectReferenceCache objectRefCache;
|
||||||
|
private final PathBuilder pathBuilder;
|
||||||
|
|
||||||
|
public DefaultPersistenceRealm(String realm, PersistenceManager persistenceManager,
|
||||||
|
PersistenceContextFactoryDelegator ctxFactory, PathBuilder pathBuilder, ObjectReferenceCache objectRefCache) {
|
||||||
|
this.ctxFactory = ctxFactory;
|
||||||
|
this.pathBuilder = pathBuilder;
|
||||||
|
this.realmName = realm;
|
||||||
|
this.persistenceManager = persistenceManager;
|
||||||
|
this.objectRefCache = objectRefCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the realm
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getRealmName() {
|
||||||
|
return this.realmName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PersistenceContextFactoryDelegator getCtxFactoryDelegator() {
|
||||||
|
return this.ctxFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the objectRefCache
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ObjectReferenceCache getObjectRefCache() {
|
||||||
|
return this.objectRefCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the persistenceManager
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public PersistenceManager getPersistenceManager() {
|
||||||
|
return this.persistenceManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pathBuilder
|
||||||
|
*/
|
||||||
|
PathBuilder getPathBuilder() {
|
||||||
|
return this.pathBuilder;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,324 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.impl;
|
||||||
|
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import ch.eitchnet.utils.helper.StringHelper;
|
||||||
|
import ch.eitchnet.utils.objectfilter.ObjectFilter;
|
||||||
|
import ch.eitchnet.xmlpers.api.FileDao;
|
||||||
|
import ch.eitchnet.xmlpers.api.IoMode;
|
||||||
|
import ch.eitchnet.xmlpers.api.MetadataDao;
|
||||||
|
import ch.eitchnet.xmlpers.api.ModificationResult;
|
||||||
|
import ch.eitchnet.xmlpers.api.ObjectDao;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceContext;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceRealm;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceTransaction;
|
||||||
|
import ch.eitchnet.xmlpers.api.TransactionCloseStrategy;
|
||||||
|
import ch.eitchnet.xmlpers.api.TransactionResult;
|
||||||
|
import ch.eitchnet.xmlpers.api.TransactionState;
|
||||||
|
import ch.eitchnet.xmlpers.api.XmlPersistenceException;
|
||||||
|
import ch.eitchnet.xmlpers.objref.ObjectReferenceCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DefaultPersistenceTransaction implements PersistenceTransaction {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(DefaultPersistenceTransaction.class);
|
||||||
|
|
||||||
|
private final DefaultPersistenceRealm realm;
|
||||||
|
private final boolean verbose;
|
||||||
|
|
||||||
|
private final ObjectFilter objectFilter;
|
||||||
|
private final ObjectDao objectDao;
|
||||||
|
private final MetadataDao metadataDao;
|
||||||
|
|
||||||
|
private FileDao fileDao;
|
||||||
|
private IoMode ioMode;
|
||||||
|
|
||||||
|
private TransactionCloseStrategy closeStrategy;
|
||||||
|
|
||||||
|
private TransactionState state;
|
||||||
|
private long startTime;
|
||||||
|
private Date startTimeDate;
|
||||||
|
private TransactionResult txResult;
|
||||||
|
|
||||||
|
public DefaultPersistenceTransaction(DefaultPersistenceRealm realm, boolean verbose) {
|
||||||
|
this.startTime = System.nanoTime();
|
||||||
|
this.startTimeDate = new Date();
|
||||||
|
this.realm = realm;
|
||||||
|
this.verbose = verbose;
|
||||||
|
this.objectFilter = new ObjectFilter();
|
||||||
|
this.fileDao = new FileDao(this, realm.getPathBuilder(), verbose);
|
||||||
|
this.objectDao = new ObjectDao(this, this.fileDao, this.objectFilter);
|
||||||
|
this.metadataDao = new MetadataDao(realm.getPathBuilder(), this, verbose);
|
||||||
|
|
||||||
|
this.closeStrategy = TransactionCloseStrategy.COMMIT;
|
||||||
|
this.state = TransactionState.OPEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTransactionResult(TransactionResult txResult) throws IllegalStateException {
|
||||||
|
if (this.txResult != null) {
|
||||||
|
String msg = "The transaction already has a result set!"; //$NON-NLS-1$
|
||||||
|
throw new IllegalStateException(msg);
|
||||||
|
}
|
||||||
|
this.txResult = txResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TransactionResult getTransactionResult() throws IllegalStateException {
|
||||||
|
if (isOpen()) {
|
||||||
|
String msg = "The transaction is still open thus has no result yet! Either commit or rollback before calling this method"; //$NON-NLS-1$
|
||||||
|
throw new IllegalStateException(msg);
|
||||||
|
}
|
||||||
|
return this.txResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PersistenceRealm getRealm() {
|
||||||
|
return this.realm;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectDao getObjectDao() {
|
||||||
|
return this.objectDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MetadataDao getMetadataDao() {
|
||||||
|
return this.metadataDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileDao getFileDao() {
|
||||||
|
return this.fileDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectReferenceCache getObjectRefCache() {
|
||||||
|
return this.realm.getObjectRefCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCloseStrategy(TransactionCloseStrategy closeStrategy) {
|
||||||
|
this.closeStrategy = closeStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws XmlPersistenceException {
|
||||||
|
this.closeStrategy.close(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void autoCloseableRollback() {
|
||||||
|
long start = System.nanoTime();
|
||||||
|
if (this.state == TransactionState.COMMITTED)
|
||||||
|
throw new IllegalStateException("Transaction has already been committed!"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
if (this.state != TransactionState.ROLLED_BACK) {
|
||||||
|
unlockObjectRefs();
|
||||||
|
this.state = TransactionState.ROLLED_BACK;
|
||||||
|
this.objectFilter.clearCache();
|
||||||
|
|
||||||
|
long end = System.nanoTime();
|
||||||
|
long txDuration = end - this.startTime;
|
||||||
|
long closeDuration = end - start;
|
||||||
|
|
||||||
|
if (this.txResult != null) {
|
||||||
|
this.txResult.clear();
|
||||||
|
this.txResult.setState(this.state);
|
||||||
|
this.txResult.setStartTime(this.startTimeDate);
|
||||||
|
this.txResult.setTxDuration(txDuration);
|
||||||
|
this.txResult.setCloseDuration(closeDuration);
|
||||||
|
this.txResult.setRealm(this.realm.getRealmName());
|
||||||
|
this.txResult.setModificationByKey(Collections.<String, ModificationResult> emptyMap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void autoCloseableCommit() throws XmlPersistenceException {
|
||||||
|
|
||||||
|
long start = System.nanoTime();
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (this.verbose) {
|
||||||
|
String msg = "Committing {0} operations in TX...";//$NON-NLS-1$
|
||||||
|
logger.info(MessageFormat.format(msg, this.objectFilter.sizeCache()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> keySet = this.objectFilter.keySet();
|
||||||
|
Map<String, ModificationResult> modifications;
|
||||||
|
if (this.txResult == null)
|
||||||
|
modifications = null;
|
||||||
|
else
|
||||||
|
modifications = new HashMap<>(keySet.size());
|
||||||
|
|
||||||
|
for (String key : keySet) {
|
||||||
|
|
||||||
|
List<Object> removed = this.objectFilter.getRemoved(key);
|
||||||
|
if (removed.isEmpty()) {
|
||||||
|
if (this.verbose)
|
||||||
|
logger.info("No objects removed in this tx."); //$NON-NLS-1$
|
||||||
|
} else {
|
||||||
|
if (this.verbose)
|
||||||
|
logger.info(removed.size() + " objects removed in this tx."); //$NON-NLS-1$
|
||||||
|
|
||||||
|
for (Object object : removed) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
PersistenceContext<Object> ctx = (PersistenceContext<Object>) object;
|
||||||
|
this.fileDao.performDelete(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Object> updated = this.objectFilter.getUpdated(key);
|
||||||
|
if (updated.isEmpty()) {
|
||||||
|
if (this.verbose)
|
||||||
|
logger.info("No objects updated in this tx."); //$NON-NLS-1$
|
||||||
|
} else {
|
||||||
|
if (this.verbose)
|
||||||
|
logger.info(updated.size() + " objects updated in this tx."); //$NON-NLS-1$
|
||||||
|
|
||||||
|
for (Object object : updated) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
PersistenceContext<Object> ctx = (PersistenceContext<Object>) object;
|
||||||
|
this.fileDao.performUpdate(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Object> added = this.objectFilter.getAdded(key);
|
||||||
|
if (added.isEmpty()) {
|
||||||
|
if (this.verbose)
|
||||||
|
logger.info("No objects added in this tx."); //$NON-NLS-1$
|
||||||
|
} else {
|
||||||
|
if (this.verbose)
|
||||||
|
logger.info(added.size() + " objects added in this tx."); //$NON-NLS-1$
|
||||||
|
|
||||||
|
for (Object object : added) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
PersistenceContext<Object> ctx = (PersistenceContext<Object>) object;
|
||||||
|
this.fileDao.performCreate(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modifications != null) {
|
||||||
|
ModificationResult result = new ModificationResult(key, added, updated, removed);
|
||||||
|
modifications.put(key, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.txResult != null) {
|
||||||
|
this.txResult.clear();
|
||||||
|
this.txResult.setState(TransactionState.COMMITTED);
|
||||||
|
this.txResult.setModificationByKey(modifications);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
if (this.txResult == null) {
|
||||||
|
|
||||||
|
long end = System.nanoTime();
|
||||||
|
long txDuration = end - this.startTime;
|
||||||
|
long closeDuration = end - start;
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("TX has failed after "); //$NON-NLS-1$
|
||||||
|
sb.append(StringHelper.formatNanoDuration(txDuration));
|
||||||
|
sb.append(" with close operation taking "); //$NON-NLS-1$
|
||||||
|
sb.append(StringHelper.formatNanoDuration(closeDuration));
|
||||||
|
logger.info(sb.toString());
|
||||||
|
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.txResult.clear();
|
||||||
|
this.txResult.setState(TransactionState.FAILED);
|
||||||
|
this.txResult.setModificationByKey(Collections.<String, ModificationResult> emptyMap());
|
||||||
|
this.txResult.setFailCause(e);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
|
||||||
|
// clean up
|
||||||
|
unlockObjectRefs();
|
||||||
|
this.objectFilter.clearCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
long end = System.nanoTime();
|
||||||
|
long txDuration = end - this.startTime;
|
||||||
|
long closeDuration = end - start;
|
||||||
|
|
||||||
|
if (this.txResult == null) {
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("TX was completed after "); //$NON-NLS-1$
|
||||||
|
sb.append(StringHelper.formatNanoDuration(txDuration));
|
||||||
|
sb.append(" with close operation taking "); //$NON-NLS-1$
|
||||||
|
sb.append(StringHelper.formatNanoDuration(closeDuration));
|
||||||
|
logger.info(sb.toString());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
this.txResult.setStartTime(this.startTimeDate);
|
||||||
|
this.txResult.setTxDuration(txDuration);
|
||||||
|
this.txResult.setCloseDuration(closeDuration);
|
||||||
|
this.txResult.setRealm(this.realm.getRealmName());
|
||||||
|
|
||||||
|
if (this.txResult.getState() == TransactionState.FAILED) {
|
||||||
|
String msg = "Failed to commit TX due to underlying exception: {0}"; //$NON-NLS-1$
|
||||||
|
String causeMsg = this.txResult.getFailCause() == null ? null : this.txResult.getFailCause()
|
||||||
|
.getMessage();
|
||||||
|
msg = MessageFormat.format(msg, causeMsg);
|
||||||
|
throw new XmlPersistenceException(msg, this.txResult.getFailCause());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
private void unlockObjectRefs() {
|
||||||
|
List<PersistenceContext> lockedObjects = this.objectFilter.getAll(PersistenceContext.class);
|
||||||
|
for (PersistenceContext lockedObject : lockedObjects) {
|
||||||
|
lockedObject.getObjectRef().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOpen() {
|
||||||
|
return this.state == TransactionState.OPEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setIoMode(IoMode ioMode) {
|
||||||
|
this.ioMode = ioMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IoMode getIoMode() {
|
||||||
|
return this.ioMode;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.impl;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import ch.eitchnet.utils.helper.PropertiesHelper;
|
||||||
|
import ch.eitchnet.utils.helper.StringHelper;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceConstants;
|
||||||
|
import ch.eitchnet.xmlpers.api.XmlPersistenceException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*/
|
||||||
|
public class PathBuilder {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(PathBuilder.class);
|
||||||
|
|
||||||
|
public static final String FILE_EXT = ".xml"; //$NON-NLS-1$
|
||||||
|
public static final int EXT_LENGTH = PathBuilder.FILE_EXT.length();
|
||||||
|
|
||||||
|
private final String basePath;
|
||||||
|
|
||||||
|
public PathBuilder(String realm, Properties properties) {
|
||||||
|
|
||||||
|
// get properties
|
||||||
|
String context = PathBuilder.class.getSimpleName();
|
||||||
|
String basePath = PropertiesHelper.getProperty(properties, context, PersistenceConstants.PROP_BASEPATH, null);
|
||||||
|
|
||||||
|
// validate base path exists and is writable
|
||||||
|
File basePathF = new File(basePath);
|
||||||
|
if (!basePathF.exists())
|
||||||
|
throw new XmlPersistenceException(MessageFormat.format("The database store path does not exist at {0}", //$NON-NLS-1$
|
||||||
|
basePathF.getAbsolutePath()));
|
||||||
|
if (!basePathF.canWrite())
|
||||||
|
throw new XmlPersistenceException(MessageFormat.format("The database store path is not writeable at {0}", //$NON-NLS-1$
|
||||||
|
basePathF.getAbsolutePath()));
|
||||||
|
|
||||||
|
File realmPathF = new File(basePathF, realm);
|
||||||
|
if (!realmPathF.exists() && !realmPathF.mkdir())
|
||||||
|
throw new XmlPersistenceException(MessageFormat.format("Could not create path for realm {0} at {1}", //$NON-NLS-1$
|
||||||
|
realm, basePathF.getAbsolutePath()));
|
||||||
|
|
||||||
|
// we want a clean base path
|
||||||
|
String canonicalBasePath;
|
||||||
|
try {
|
||||||
|
canonicalBasePath = realmPathF.getCanonicalPath();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new XmlPersistenceException(MessageFormat.format(
|
||||||
|
"Failed to build canonical path from {0}", realmPathF.getAbsolutePath()), e); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
// this.basePathF = basePathF;
|
||||||
|
this.basePath = canonicalBasePath;
|
||||||
|
logger.info(MessageFormat.format("Using base path {0}", this.basePath)); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
String getFilename(String id) {
|
||||||
|
return id.concat(PathBuilder.FILE_EXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
String getPathAsString(String type, String subType, String id) {
|
||||||
|
StringBuilder sb = new StringBuilder(this.basePath);
|
||||||
|
if (StringHelper.isNotEmpty(type)) {
|
||||||
|
sb.append(File.separatorChar);
|
||||||
|
sb.append(type);
|
||||||
|
}
|
||||||
|
if (StringHelper.isNotEmpty(subType)) {
|
||||||
|
sb.append(File.separatorChar);
|
||||||
|
sb.append(subType);
|
||||||
|
}
|
||||||
|
if (StringHelper.isNotEmpty(id)) {
|
||||||
|
sb.append(File.separatorChar);
|
||||||
|
sb.append(getFilename(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getRootPath() {
|
||||||
|
File path = new File(getPathAsString(null, null, null));
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getTypePath(String type) {
|
||||||
|
File path = new File(getPathAsString(type, null, null));
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getSubTypePath(String type, String subType) {
|
||||||
|
File path = new File(getPathAsString(type, subType, null));
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getIdOfTypePath(String type, String id) {
|
||||||
|
File path = new File(getPathAsString(type, null, id));
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getIdOfSubTypePath(String type, String subType, String id) {
|
||||||
|
File path = new File(getPathAsString(type, subType, id));
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,137 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.objref;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceContext;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceContextFactory;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceContextFactoryDelegator;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceTransaction;
|
||||||
|
import ch.eitchnet.xmlpers.impl.PathBuilder;
|
||||||
|
|
||||||
|
public class IdOfSubTypeRef extends ObjectRef {
|
||||||
|
|
||||||
|
private final String type;
|
||||||
|
private final String subType;
|
||||||
|
private final String id;
|
||||||
|
|
||||||
|
public IdOfSubTypeRef(String realmName, String type, String subType, String id) {
|
||||||
|
super(realmName, RefNameCreator.createIdOfSubTypeName(realmName, type, subType, id));
|
||||||
|
this.type = type;
|
||||||
|
this.subType = subType;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSubType() {
|
||||||
|
return this.subType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the id
|
||||||
|
*/
|
||||||
|
public String getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRoot() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeaf() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectRef getParent(PersistenceTransaction tx) {
|
||||||
|
return tx.getRealm().getObjectRefCache().getSubTypeRef(this.type, this.subType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectRef getChildIdRef(PersistenceTransaction tx, String id) {
|
||||||
|
String msg = MessageFormat.format("Already a leaf: {0}", getName()); //$NON-NLS-1$
|
||||||
|
throw new UnsupportedOperationException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectRef getChildTypeRef(PersistenceTransaction tx, String type) {
|
||||||
|
String msg = MessageFormat.format("Already a leaf: {0}", getName()); //$NON-NLS-1$
|
||||||
|
throw new UnsupportedOperationException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getPath(PathBuilder pathBuilder) {
|
||||||
|
return pathBuilder.getIdOfSubTypePath(this.type, this.subType, this.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> PersistenceContext<T> createPersistenceContext(PersistenceTransaction tx) {
|
||||||
|
PersistenceContextFactoryDelegator ctxFactoryDelegator = tx.getRealm().getCtxFactoryDelegator();
|
||||||
|
PersistenceContextFactory<T> persistenceContextFactory = ctxFactoryDelegator.<T> getCtxFactory(this.type);
|
||||||
|
return persistenceContextFactory.createCtx(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((this.id == null) ? 0 : this.id.hashCode());
|
||||||
|
result = prime * result + ((this.realmName == null) ? 0 : this.realmName.hashCode());
|
||||||
|
result = prime * result + ((this.subType == null) ? 0 : this.subType.hashCode());
|
||||||
|
result = prime * result + ((this.type == null) ? 0 : this.type.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
IdOfSubTypeRef other = (IdOfSubTypeRef) obj;
|
||||||
|
if (this.realmName == null) {
|
||||||
|
if (other.realmName != null)
|
||||||
|
return false;
|
||||||
|
} else if (!this.realmName.equals(other.realmName))
|
||||||
|
return false;
|
||||||
|
if (this.id == null) {
|
||||||
|
if (other.id != null)
|
||||||
|
return false;
|
||||||
|
} else if (!this.id.equals(other.id))
|
||||||
|
return false;
|
||||||
|
if (this.subType == null) {
|
||||||
|
if (other.subType != null)
|
||||||
|
return false;
|
||||||
|
} else if (!this.subType.equals(other.subType))
|
||||||
|
return false;
|
||||||
|
if (this.type == null) {
|
||||||
|
if (other.type != null)
|
||||||
|
return false;
|
||||||
|
} else if (!this.type.equals(other.type))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.objref;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceContext;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceContextFactory;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceContextFactoryDelegator;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceTransaction;
|
||||||
|
import ch.eitchnet.xmlpers.impl.PathBuilder;
|
||||||
|
|
||||||
|
public class IdOfTypeRef extends ObjectRef {
|
||||||
|
|
||||||
|
private final String type;
|
||||||
|
private final String id;
|
||||||
|
|
||||||
|
public IdOfTypeRef(String realmName, String type, String id) {
|
||||||
|
super(realmName, RefNameCreator.createIdOfTypeName(realmName, type, id));
|
||||||
|
this.type = type;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the id
|
||||||
|
*/
|
||||||
|
public String getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRoot() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeaf() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectRef getParent(PersistenceTransaction tx) {
|
||||||
|
return tx.getRealm().getObjectRefCache().getTypeRef(this.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectRef getChildIdRef(PersistenceTransaction tx, String id) {
|
||||||
|
String msg = MessageFormat.format("Already a leaf: {0}", getName()); //$NON-NLS-1$
|
||||||
|
throw new UnsupportedOperationException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectRef getChildTypeRef(PersistenceTransaction tx, String type) {
|
||||||
|
String msg = MessageFormat.format("Already a leaf: {0}", getName()); //$NON-NLS-1$
|
||||||
|
throw new UnsupportedOperationException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getPath(PathBuilder pathBuilder) {
|
||||||
|
return pathBuilder.getIdOfTypePath(this.type, this.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> PersistenceContext<T> createPersistenceContext(PersistenceTransaction tx) {
|
||||||
|
PersistenceContextFactoryDelegator ctxFactoryDelegator = tx.getRealm().getCtxFactoryDelegator();
|
||||||
|
PersistenceContextFactory<T> persistenceContextFactory = ctxFactoryDelegator.<T> getCtxFactory(this.type);
|
||||||
|
return persistenceContextFactory.createCtx(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((this.id == null) ? 0 : this.id.hashCode());
|
||||||
|
result = prime * result + ((this.realmName == null) ? 0 : this.realmName.hashCode());
|
||||||
|
result = prime * result + ((this.type == null) ? 0 : this.type.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
IdOfTypeRef other = (IdOfTypeRef) obj;
|
||||||
|
if (this.realmName == null) {
|
||||||
|
if (other.realmName != null)
|
||||||
|
return false;
|
||||||
|
} else if (!this.realmName.equals(other.realmName))
|
||||||
|
return false;
|
||||||
|
if (this.id == null) {
|
||||||
|
if (other.id != null)
|
||||||
|
return false;
|
||||||
|
} else if (!this.id.equals(other.id))
|
||||||
|
return false;
|
||||||
|
if (this.type == null) {
|
||||||
|
if (other.type != null)
|
||||||
|
return false;
|
||||||
|
} else if (!this.type.equals(other.type))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.objref;
|
||||||
|
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import ch.eitchnet.utils.helper.StringHelper;
|
||||||
|
import ch.eitchnet.xmlpers.api.XmlPersistenceException;
|
||||||
|
|
||||||
|
public class LockableObject {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(LockableObject.class);
|
||||||
|
private static long tryLockTime = 10000L;
|
||||||
|
|
||||||
|
private final ReentrantLock lock;
|
||||||
|
|
||||||
|
public LockableObject() {
|
||||||
|
this.lock = new ReentrantLock(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long getLockTime() {
|
||||||
|
return tryLockTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.util.concurrent.locks.ReentrantLock#tryLock(long, TimeUnit)
|
||||||
|
*/
|
||||||
|
public void lock() {
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (!this.lock.tryLock(tryLockTime, TimeUnit.MILLISECONDS)) {
|
||||||
|
String msg = "Failed to acquire lock after {0} for {1}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, StringHelper.formatMillisecondsDuration(tryLockTime), toString());
|
||||||
|
throw new XmlPersistenceException(msg);
|
||||||
|
}
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("locked " + toString()); //$NON-NLS-1$
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new XmlPersistenceException("Thread interrupted: " + e.getMessage(), e); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.util.concurrent.locks.ReentrantLock#unlock()
|
||||||
|
*/
|
||||||
|
public void unlock() {
|
||||||
|
this.lock.unlock();
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("unlocking " + toString()); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.objref;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceContext;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceTransaction;
|
||||||
|
import ch.eitchnet.xmlpers.impl.PathBuilder;
|
||||||
|
|
||||||
|
public abstract class ObjectRef extends LockableObject {
|
||||||
|
|
||||||
|
protected final String realmName;
|
||||||
|
protected final String name;
|
||||||
|
|
||||||
|
protected ObjectRef(String realmName, String name) {
|
||||||
|
this.realmName = realmName;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRealmName() {
|
||||||
|
return this.realmName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract boolean isRoot();
|
||||||
|
|
||||||
|
public abstract boolean isLeaf();
|
||||||
|
|
||||||
|
public abstract String getType();
|
||||||
|
|
||||||
|
public abstract ObjectRef getParent(PersistenceTransaction tx);
|
||||||
|
|
||||||
|
public abstract ObjectRef getChildIdRef(PersistenceTransaction tx, String id);
|
||||||
|
|
||||||
|
public abstract ObjectRef getChildTypeRef(PersistenceTransaction tx, String type);
|
||||||
|
|
||||||
|
public abstract File getPath(PathBuilder pathBuilder);
|
||||||
|
|
||||||
|
public abstract <T> PersistenceContext<T> createPersistenceContext(PersistenceTransaction tx);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract boolean equals(Object obj);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract int hashCode();
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.objref;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import ch.eitchnet.utils.helper.StringHelper;
|
||||||
|
|
||||||
|
public class ObjectReferenceCache {
|
||||||
|
|
||||||
|
private final String realmName;
|
||||||
|
private final RootRef rootRef;
|
||||||
|
private final Map<String, TypeRef> typeRefMap;
|
||||||
|
private final Map<String, SubTypeRef> subTypeRefMap;
|
||||||
|
private final Map<String, IdOfTypeRef> idOfTypeRefMap;
|
||||||
|
private final Map<String, IdOfSubTypeRef> idOfSubTypeRefMap;
|
||||||
|
|
||||||
|
public ObjectReferenceCache(String realmName) {
|
||||||
|
if (StringHelper.isEmpty(realmName))
|
||||||
|
throw new IllegalArgumentException("Realm name may not be empty!"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
this.realmName = realmName;
|
||||||
|
this.rootRef = new RootRef(this.realmName);
|
||||||
|
this.typeRefMap = new HashMap<>();
|
||||||
|
this.subTypeRefMap = new HashMap<>();
|
||||||
|
this.idOfTypeRefMap = new HashMap<>();
|
||||||
|
this.idOfSubTypeRefMap = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRealmName() {
|
||||||
|
return this.realmName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized RootRef getRootRef() {
|
||||||
|
return this.rootRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized TypeRef getTypeRef(String type) {
|
||||||
|
String key = RefNameCreator.createTypeName(this.realmName, type);
|
||||||
|
TypeRef ref = this.typeRefMap.get(key);
|
||||||
|
if (ref == null) {
|
||||||
|
ref = new TypeRef(this.realmName, type);
|
||||||
|
this.typeRefMap.put(key, ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized SubTypeRef getSubTypeRef(String type, String subType) {
|
||||||
|
String key = RefNameCreator.createSubTypeName(this.realmName, type, subType);
|
||||||
|
SubTypeRef ref = this.subTypeRefMap.get(key);
|
||||||
|
if (ref == null) {
|
||||||
|
ref = new SubTypeRef(this.realmName, type, subType);
|
||||||
|
this.subTypeRefMap.put(key, ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized IdOfTypeRef getIdOfTypeRef(String type, String id) {
|
||||||
|
String key = RefNameCreator.createIdOfTypeName(this.realmName, type, id);
|
||||||
|
IdOfTypeRef idRef = this.idOfTypeRefMap.get(key);
|
||||||
|
if (idRef == null) {
|
||||||
|
idRef = new IdOfTypeRef(this.realmName, type, id);
|
||||||
|
this.idOfTypeRefMap.put(key, idRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
return idRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized IdOfSubTypeRef getIdOfSubTypeRef(String type, String subType, String id) {
|
||||||
|
String key = RefNameCreator.createIdOfSubTypeName(this.realmName, type, subType, id);
|
||||||
|
IdOfSubTypeRef idRef = this.idOfSubTypeRefMap.get(key);
|
||||||
|
if (idRef == null) {
|
||||||
|
idRef = new IdOfSubTypeRef(this.realmName, type, subType, id);
|
||||||
|
this.idOfSubTypeRefMap.put(key, idRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
return idRef;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.objref;
|
||||||
|
|
||||||
|
import ch.eitchnet.utils.helper.StringHelper;
|
||||||
|
|
||||||
|
public class RefNameCreator {
|
||||||
|
|
||||||
|
protected static final String SLASH = "/"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
// FIXME validate each name part that it is a valid literal for file names...
|
||||||
|
|
||||||
|
public static String createRootName(String realmName) {
|
||||||
|
assertRealmName(realmName);
|
||||||
|
return SLASH + realmName + SLASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String createTypeName(String realmName, String type) {
|
||||||
|
assertRealmName(realmName);
|
||||||
|
assertType(type);
|
||||||
|
return SLASH + realmName + SLASH + type + SLASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String createIdOfTypeName(String realmName, String type, String id) {
|
||||||
|
assertRealmName(realmName);
|
||||||
|
assertType(type);
|
||||||
|
assertId(id);
|
||||||
|
return SLASH + realmName + SLASH + type + SLASH + id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String createSubTypeName(String realmName, String type, String subType) {
|
||||||
|
assertRealmName(realmName);
|
||||||
|
assertType(type);
|
||||||
|
assertSubType(subType);
|
||||||
|
return SLASH + realmName + SLASH + type + SLASH + subType + SLASH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String createIdOfSubTypeName(String realmName, String type, String subType, String id) {
|
||||||
|
assertRealmName(realmName);
|
||||||
|
assertType(type);
|
||||||
|
assertSubType(subType);
|
||||||
|
assertId(id);
|
||||||
|
return SLASH + realmName + SLASH + type + SLASH + subType + SLASH + id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertRealmName(String realmName) {
|
||||||
|
if (StringHelper.isEmpty(realmName)) {
|
||||||
|
throw new IllegalArgumentException("Realm name may not be empty!"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertType(String type) {
|
||||||
|
if (StringHelper.isEmpty(type)) {
|
||||||
|
throw new IllegalArgumentException("type may not be empty!"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertSubType(String subType) {
|
||||||
|
if (StringHelper.isEmpty(subType)) {
|
||||||
|
throw new IllegalArgumentException("subType may not be empty!"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertId(String id) {
|
||||||
|
if (StringHelper.isEmpty(id)) {
|
||||||
|
throw new IllegalArgumentException("id may not be empty!"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.objref;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceContext;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceTransaction;
|
||||||
|
import ch.eitchnet.xmlpers.impl.PathBuilder;
|
||||||
|
|
||||||
|
public class RootRef extends ObjectRef {
|
||||||
|
|
||||||
|
public RootRef(String realmName) {
|
||||||
|
super(realmName, RefNameCreator.createRootName(realmName));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRoot() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeaf() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
String msg = MessageFormat.format("RootRef has no type: {0}", getName()); //$NON-NLS-1$
|
||||||
|
throw new UnsupportedOperationException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectRef getParent(PersistenceTransaction tx) {
|
||||||
|
String msg = MessageFormat.format("RootRef has no parent: {0}", getName()); //$NON-NLS-1$
|
||||||
|
throw new UnsupportedOperationException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectRef getChildIdRef(PersistenceTransaction tx, String id) {
|
||||||
|
String msg = MessageFormat.format("RootRef has no child id: {0}", getName()); //$NON-NLS-1$
|
||||||
|
throw new UnsupportedOperationException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectRef getChildTypeRef(PersistenceTransaction tx, String type) {
|
||||||
|
return tx.getRealm().getObjectRefCache().getTypeRef(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getPath(PathBuilder pathBuilder) {
|
||||||
|
return pathBuilder.getRootPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> PersistenceContext<T> createPersistenceContext(PersistenceTransaction tx) {
|
||||||
|
String msg = MessageFormat.format("{0} is not a leaf and can thus not have a Persistence Context", getName()); //$NON-NLS-1$
|
||||||
|
throw new UnsupportedOperationException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((this.realmName == null) ? 0 : this.realmName.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
RootRef other = (RootRef) obj;
|
||||||
|
if (this.realmName == null) {
|
||||||
|
if (other.realmName != null)
|
||||||
|
return false;
|
||||||
|
} else if (!this.realmName.equals(other.realmName))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.objref;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceContext;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceTransaction;
|
||||||
|
import ch.eitchnet.xmlpers.impl.PathBuilder;
|
||||||
|
|
||||||
|
public class SubTypeRef extends ObjectRef {
|
||||||
|
|
||||||
|
private final String type;
|
||||||
|
private final String subType;
|
||||||
|
|
||||||
|
public SubTypeRef(String realmName, String type, String subType) {
|
||||||
|
super(realmName, RefNameCreator.createSubTypeName(realmName, type, subType));
|
||||||
|
this.type = type;
|
||||||
|
this.subType = subType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSubType() {
|
||||||
|
return this.subType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRoot() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeaf() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectRef getParent(PersistenceTransaction tx) {
|
||||||
|
return tx.getRealm().getObjectRefCache().getTypeRef(this.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectRef getChildIdRef(PersistenceTransaction tx, String id) {
|
||||||
|
return tx.getRealm().getObjectRefCache().getIdOfSubTypeRef(this.type, this.subType, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectRef getChildTypeRef(PersistenceTransaction tx, String type) {
|
||||||
|
String msg = MessageFormat.format("A SubType has no child type: {0}", getName()); //$NON-NLS-1$
|
||||||
|
throw new UnsupportedOperationException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getPath(PathBuilder pathBuilder) {
|
||||||
|
return pathBuilder.getSubTypePath(this.type, this.subType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> PersistenceContext<T> createPersistenceContext(PersistenceTransaction tx) {
|
||||||
|
String msg = MessageFormat.format("{0} is not a leaf and can thus not have a Persistence Context", getName()); //$NON-NLS-1$
|
||||||
|
throw new UnsupportedOperationException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((this.realmName == null) ? 0 : this.realmName.hashCode());
|
||||||
|
result = prime * result + ((this.subType == null) ? 0 : this.subType.hashCode());
|
||||||
|
result = prime * result + ((this.type == null) ? 0 : this.type.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
SubTypeRef other = (SubTypeRef) obj;
|
||||||
|
if (this.realmName == null) {
|
||||||
|
if (other.realmName != null)
|
||||||
|
return false;
|
||||||
|
} else if (!this.realmName.equals(other.realmName))
|
||||||
|
return false;
|
||||||
|
if (this.subType == null) {
|
||||||
|
if (other.subType != null)
|
||||||
|
return false;
|
||||||
|
} else if (!this.subType.equals(other.subType))
|
||||||
|
return false;
|
||||||
|
if (this.type == null) {
|
||||||
|
if (other.type != null)
|
||||||
|
return false;
|
||||||
|
} else if (!this.type.equals(other.type))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.objref;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceContext;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceTransaction;
|
||||||
|
import ch.eitchnet.xmlpers.impl.PathBuilder;
|
||||||
|
|
||||||
|
public class TypeRef extends ObjectRef {
|
||||||
|
|
||||||
|
private final String type;
|
||||||
|
|
||||||
|
public TypeRef(String realmName, String type) {
|
||||||
|
super(realmName, RefNameCreator.createTypeName(realmName, type));
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRoot() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeaf() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectRef getParent(PersistenceTransaction tx) {
|
||||||
|
return tx.getRealm().getObjectRefCache().getRootRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectRef getChildIdRef(PersistenceTransaction tx, String id) {
|
||||||
|
return tx.getRealm().getObjectRefCache().getIdOfTypeRef(this.type, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectRef getChildTypeRef(PersistenceTransaction tx, String type) {
|
||||||
|
return tx.getRealm().getObjectRefCache().getSubTypeRef(this.type, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getPath(PathBuilder pathBuilder) {
|
||||||
|
return pathBuilder.getTypePath(this.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> PersistenceContext<T> createPersistenceContext(PersistenceTransaction tx) {
|
||||||
|
String msg = MessageFormat.format("{0} is not a leaf and can thus not have a Persistence Context", getName()); //$NON-NLS-1$
|
||||||
|
throw new UnsupportedOperationException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((this.realmName == null) ? 0 : this.realmName.hashCode());
|
||||||
|
result = prime * result + ((this.type == null) ? 0 : this.type.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
TypeRef other = (TypeRef) obj;
|
||||||
|
if (this.realmName == null) {
|
||||||
|
if (other.realmName != null)
|
||||||
|
return false;
|
||||||
|
} else if (!this.realmName.equals(other.realmName))
|
||||||
|
return false;
|
||||||
|
if (this.type == null) {
|
||||||
|
if (other.type != null)
|
||||||
|
return false;
|
||||||
|
} else if (!this.type.equals(other.type))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.util;
|
||||||
|
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceContext;
|
||||||
|
import ch.eitchnet.xmlpers.objref.ObjectRef;
|
||||||
|
|
||||||
|
public class AssertionUtil {
|
||||||
|
|
||||||
|
public static void assertNotNull(Object object) {
|
||||||
|
if (object == null)
|
||||||
|
throw new RuntimeException("Object may not be null!"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assertObjectRead(PersistenceContext<?> context) {
|
||||||
|
if (context.getObject() == null) {
|
||||||
|
String msg = "Failed to read object with for {0}"; //$NON-NLS-1$
|
||||||
|
ObjectRef objectRef = context.getObjectRef();
|
||||||
|
msg = MessageFormat.format(msg, objectRef.getName());
|
||||||
|
throw new RuntimeException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assertIsIdRef(ObjectRef objectRef) {
|
||||||
|
if (!objectRef.isLeaf()) {
|
||||||
|
String msg = "Expected IdRef not {0}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, objectRef.getName());
|
||||||
|
throw new IllegalArgumentException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assertIsNotIdRef(ObjectRef objectRef) {
|
||||||
|
if (objectRef.isLeaf()) {
|
||||||
|
String msg = "IdRef not expected {0}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, objectRef.getName());
|
||||||
|
throw new IllegalArgumentException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assertIsNotRootRef(ObjectRef objectRef) {
|
||||||
|
if (objectRef.isRoot()) {
|
||||||
|
String msg = "RootRef not expected {0}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, objectRef.getName());
|
||||||
|
throw new IllegalArgumentException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.util;
|
||||||
|
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.XmlPersistenceException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DomUtil {
|
||||||
|
|
||||||
|
public static DocumentBuilder createDocumentBuilder() {
|
||||||
|
try {
|
||||||
|
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
|
||||||
|
DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
|
||||||
|
return docBuilder;
|
||||||
|
} catch (ParserConfigurationException e) {
|
||||||
|
String msg = "No Xml Parser could be loaded: {0}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, e.getMessage());
|
||||||
|
throw new XmlPersistenceException(msg, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.util;
|
||||||
|
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.XmlPersistenceException;
|
||||||
|
import ch.eitchnet.xmlpers.impl.PathBuilder;
|
||||||
|
|
||||||
|
public class FilenameUtility {
|
||||||
|
|
||||||
|
public static String getId(String filename) {
|
||||||
|
assertFilename(filename);
|
||||||
|
return filename.substring(0, filename.length() - PathBuilder.EXT_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assertFilename(String filename) {
|
||||||
|
if (filename.charAt(filename.length() - PathBuilder.EXT_LENGTH) != '.') {
|
||||||
|
String msg = "The filename does not have a . (dot) at index {0}"; //$NON-NLS-1$
|
||||||
|
msg = MessageFormat.format(msg, (filename.length() - PathBuilder.EXT_LENGTH));
|
||||||
|
throw new XmlPersistenceException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import ch.eitchnet.utils.helper.FileHelper;
|
||||||
|
import ch.eitchnet.xmlpers.api.IoMode;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceConstants;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceManager;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceManagerLoader;
|
||||||
|
import ch.eitchnet.xmlpers.test.impl.BookContextFactory;
|
||||||
|
import ch.eitchnet.xmlpers.test.impl.MyModelContextFactory;
|
||||||
|
import ch.eitchnet.xmlpers.test.impl.TestConstants;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.Book;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.MyModel;
|
||||||
|
|
||||||
|
public abstract class AbstractPersistenceTest {
|
||||||
|
|
||||||
|
protected static final Logger logger = LoggerFactory.getLogger(AbstractPersistenceTest.class);
|
||||||
|
|
||||||
|
protected PersistenceManager persistenceManager;
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
protected static void cleanPath(String path) {
|
||||||
|
|
||||||
|
File file = new File(path).getAbsoluteFile();
|
||||||
|
File parent = file.getParentFile();
|
||||||
|
if (!parent.getAbsolutePath().endsWith("/target/db"))
|
||||||
|
throw new RuntimeException("Bad parent! Must be /target/db/: " + parent);
|
||||||
|
if (!parent.exists() && !parent.mkdirs())
|
||||||
|
throw new RuntimeException("Failed to create path " + parent);
|
||||||
|
|
||||||
|
if (file.exists() && file.isDirectory())
|
||||||
|
if (!FileHelper.deleteFiles(file.listFiles(), true))
|
||||||
|
throw new RuntimeException("Could not clean up path " + file.getAbsolutePath());
|
||||||
|
|
||||||
|
if (!file.exists() && !file.mkdir())
|
||||||
|
throw new RuntimeException("Failed to create path " + file);
|
||||||
|
|
||||||
|
File domFile = new File(file, IoMode.DOM.name());
|
||||||
|
if (!domFile.mkdir())
|
||||||
|
throw new RuntimeException("Failed to create path " + domFile);
|
||||||
|
|
||||||
|
File saxFile = new File(file, IoMode.SAX.name());
|
||||||
|
if (!saxFile.mkdir())
|
||||||
|
throw new RuntimeException("Failed to create path " + saxFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setup(Properties properties) {
|
||||||
|
properties.setProperty(PersistenceConstants.PROP_VERBOSE, "true"); //$NON-NLS-1$
|
||||||
|
this.persistenceManager = PersistenceManagerLoader.load(properties);
|
||||||
|
this.persistenceManager.getCtxFactory().registerPersistenceContextFactory(MyModel.class,
|
||||||
|
TestConstants.TYPE_RES, new MyModelContextFactory());
|
||||||
|
this.persistenceManager.getCtxFactory().registerPersistenceContextFactory(Book.class, TestConstants.TYPE_BOOK,
|
||||||
|
new BookContextFactory());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.test;
|
||||||
|
|
||||||
|
import static ch.eitchnet.xmlpers.test.model.ModelBuilder.assertResource;
|
||||||
|
import static ch.eitchnet.xmlpers.test.model.ModelBuilder.assertResourceUpdated;
|
||||||
|
import static ch.eitchnet.xmlpers.test.model.ModelBuilder.createResource;
|
||||||
|
import static ch.eitchnet.xmlpers.test.model.ModelBuilder.updateResource;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.FileDao;
|
||||||
|
import ch.eitchnet.xmlpers.api.IoMode;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceConstants;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceContext;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceContextFactory;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceContextFactoryDelegator;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceManager;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceTransaction;
|
||||||
|
import ch.eitchnet.xmlpers.impl.DefaultPersistenceRealm;
|
||||||
|
import ch.eitchnet.xmlpers.impl.DefaultPersistenceTransaction;
|
||||||
|
import ch.eitchnet.xmlpers.impl.PathBuilder;
|
||||||
|
import ch.eitchnet.xmlpers.objref.ObjectReferenceCache;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.MyModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
public class FileDaoTest extends AbstractPersistenceTest {
|
||||||
|
|
||||||
|
private static final String TEST_PATH = "target/db/FileDaoTest/";
|
||||||
|
private static final boolean VERBOSE = true;
|
||||||
|
private DefaultPersistenceRealm realm;
|
||||||
|
private PathBuilder pathBuilder;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void beforeClass() {
|
||||||
|
cleanPath(TEST_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setup(IoMode ioMode) {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.setProperty(PersistenceConstants.PROP_BASEPATH, TEST_PATH + ioMode.name());
|
||||||
|
setup(properties);
|
||||||
|
|
||||||
|
ObjectReferenceCache objectRefCache = new ObjectReferenceCache(PersistenceManager.DEFAULT_REALM);
|
||||||
|
this.pathBuilder = new PathBuilder(PersistenceManager.DEFAULT_REALM, properties);
|
||||||
|
this.realm = new DefaultPersistenceRealm(PersistenceManager.DEFAULT_REALM, this.persistenceManager,
|
||||||
|
this.persistenceManager.getCtxFactory(), this.pathBuilder, objectRefCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCrudSax() {
|
||||||
|
setup(IoMode.SAX);
|
||||||
|
try (PersistenceTransaction tx = new DefaultPersistenceTransaction(this.realm, VERBOSE)) {
|
||||||
|
FileDao fileDao = new FileDao(tx, this.pathBuilder, VERBOSE);
|
||||||
|
tx.setIoMode(IoMode.SAX);
|
||||||
|
testCrud(this.realm.getCtxFactoryDelegator(), fileDao);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCrudDom() {
|
||||||
|
setup(IoMode.DOM);
|
||||||
|
try (PersistenceTransaction tx = new DefaultPersistenceTransaction(this.realm, VERBOSE)) {
|
||||||
|
FileDao fileDao = new FileDao(tx, this.pathBuilder, VERBOSE);
|
||||||
|
tx.setIoMode(IoMode.DOM);
|
||||||
|
testCrud(this.realm.getCtxFactoryDelegator(), fileDao);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testCrud(PersistenceContextFactoryDelegator ctxFactoryDelegator, FileDao fileDao) {
|
||||||
|
|
||||||
|
MyModel resource = createResource();
|
||||||
|
assertResource(resource);
|
||||||
|
Class<? extends MyModel> classType = resource.getClass();
|
||||||
|
PersistenceContextFactory<MyModel> ctxFactory = ctxFactoryDelegator.getCtxFactory(classType);
|
||||||
|
ObjectReferenceCache objectRefCache = this.realm.getObjectRefCache();
|
||||||
|
PersistenceContext<MyModel> context = ctxFactory.createCtx(objectRefCache, resource);
|
||||||
|
context.setObject(resource);
|
||||||
|
fileDao.performCreate(context);
|
||||||
|
|
||||||
|
context.setObject(null);
|
||||||
|
fileDao.performRead(context);
|
||||||
|
assertResource(context.getObject());
|
||||||
|
|
||||||
|
updateResource(context.getObject());
|
||||||
|
fileDao.performUpdate(context);
|
||||||
|
|
||||||
|
context.setObject(null);
|
||||||
|
fileDao.performRead(context);
|
||||||
|
assertResourceUpdated(context.getObject());
|
||||||
|
|
||||||
|
fileDao.performDelete(context);
|
||||||
|
|
||||||
|
context.setObject(null);
|
||||||
|
fileDao.performRead(context);
|
||||||
|
assertNull(context.getObject());
|
||||||
|
|
||||||
|
context.setObject(createResource());
|
||||||
|
fileDao.performCreate(context);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,233 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.test;
|
||||||
|
|
||||||
|
import static ch.eitchnet.xmlpers.test.impl.TestConstants.TYPE_RES;
|
||||||
|
import static ch.eitchnet.xmlpers.test.model.ModelBuilder.RES_TYPE;
|
||||||
|
import static ch.eitchnet.xmlpers.test.model.ModelBuilder.createResource;
|
||||||
|
import static ch.eitchnet.xmlpers.test.model.ModelBuilder.updateResource;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.IoMode;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceConstants;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceTransaction;
|
||||||
|
import ch.eitchnet.xmlpers.objref.IdOfSubTypeRef;
|
||||||
|
import ch.eitchnet.xmlpers.objref.LockableObject;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.MyModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class LockingTest extends AbstractPersistenceTest {
|
||||||
|
|
||||||
|
private static final String BASE_PATH = "target/db/LockingTest/"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
private long waitForWorkersTime;
|
||||||
|
private boolean run;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void beforeClass() {
|
||||||
|
cleanPath(BASE_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.setProperty(PersistenceConstants.PROP_BASEPATH, BASE_PATH + IoMode.DOM.name());
|
||||||
|
properties.setProperty(PersistenceConstants.PROP_LOCK_TIME_MILLIS, Long.toString(500L));
|
||||||
|
setup(properties);
|
||||||
|
|
||||||
|
this.waitForWorkersTime = LockableObject.getLockTime() + getWaitForWorkersTime() + 300L;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldLockObjects() throws InterruptedException {
|
||||||
|
|
||||||
|
List<CreateResourceWorker> workers = new ArrayList<>(5);
|
||||||
|
|
||||||
|
String resoureId = "worker"; //$NON-NLS-1$
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
String workerName = resoureId + "_" + i; //$NON-NLS-1$
|
||||||
|
CreateResourceWorker worker = new CreateResourceWorker(workerName, workerName);
|
||||||
|
worker.start();
|
||||||
|
workers.add(worker);
|
||||||
|
logger.info("Setup thread " + worker.getName()); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
int nrOfSuccess = runWorkers(workers);
|
||||||
|
|
||||||
|
assertEquals("Only one thread should be able to perform the TX!", 5, nrOfSuccess); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldFailIfResourceAlreadyExists() throws InterruptedException {
|
||||||
|
|
||||||
|
List<CreateResourceWorker> workers = new ArrayList<>(5);
|
||||||
|
|
||||||
|
String resourceId = "createWorkerRes"; //$NON-NLS-1$
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
String workerName = resourceId + "_" + i; //$NON-NLS-1$
|
||||||
|
CreateResourceWorker worker = new CreateResourceWorker(workerName, resourceId);
|
||||||
|
worker.start();
|
||||||
|
workers.add(worker);
|
||||||
|
logger.info("Setup thread " + worker.getName()); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
int nrOfSuccess = runWorkers(workers);
|
||||||
|
|
||||||
|
assertEquals("Only one thread should be able to perform the TX!", 1, nrOfSuccess); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldFailUpdateIfLockNotAcquirable() throws InterruptedException {
|
||||||
|
|
||||||
|
// prepare workers
|
||||||
|
List<UpdateResourceWorker> workers = new ArrayList<>(5);
|
||||||
|
String resourceId = "updatWorkerRes"; //$NON-NLS-1$
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
String workerName = resourceId + "_" + i; //$NON-NLS-1$
|
||||||
|
UpdateResourceWorker worker = new UpdateResourceWorker(workerName, resourceId);
|
||||||
|
worker.start();
|
||||||
|
workers.add(worker);
|
||||||
|
logger.info("Setup thread " + worker.getName()); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
// create resource which is to be updated
|
||||||
|
try (PersistenceTransaction tx = this.persistenceManager.openTx()) {
|
||||||
|
MyModel resource = createResource(resourceId);
|
||||||
|
tx.getObjectDao().add(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nrOfSuccess = runWorkers(workers);
|
||||||
|
|
||||||
|
assertEquals("Only one thread should be able to perform the TX!", 1, nrOfSuccess); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
private int runWorkers(List<? extends AbstractWorker> workers) throws InterruptedException {
|
||||||
|
|
||||||
|
setRun(true);
|
||||||
|
|
||||||
|
for (AbstractWorker worker : workers) {
|
||||||
|
worker.join(getWaitForWorkersTime() + 2000L);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nrOfSuccess = 0;
|
||||||
|
for (AbstractWorker worker : workers) {
|
||||||
|
if (worker.isSuccess())
|
||||||
|
nrOfSuccess++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nrOfSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getWaitForWorkersTime() {
|
||||||
|
return this.waitForWorkersTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRun() {
|
||||||
|
return this.run;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRun(boolean run) {
|
||||||
|
this.run = run;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class AbstractWorker extends Thread {
|
||||||
|
|
||||||
|
protected boolean success;
|
||||||
|
protected String resourceId;
|
||||||
|
|
||||||
|
public AbstractWorker(String name, String resourceId) {
|
||||||
|
super(name);
|
||||||
|
this.resourceId = resourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
|
||||||
|
logger.info("Waiting for ok to work..."); //$NON-NLS-1$
|
||||||
|
while (!isRun()) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(10L);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("Starting work..."); //$NON-NLS-1$
|
||||||
|
try (PersistenceTransaction tx = LockingTest.this.persistenceManager.openTx()) {
|
||||||
|
doWork(tx);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Thread.sleep(getWaitForWorkersTime());
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.success = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("Work completed."); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void doWork(PersistenceTransaction tx);
|
||||||
|
|
||||||
|
public boolean isSuccess() {
|
||||||
|
return this.success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CreateResourceWorker extends AbstractWorker {
|
||||||
|
|
||||||
|
public CreateResourceWorker(String name, String resourceId) {
|
||||||
|
super(name, resourceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doWork(PersistenceTransaction tx) {
|
||||||
|
MyModel resource = createResource(this.resourceId);
|
||||||
|
tx.getObjectDao().add(resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UpdateResourceWorker extends AbstractWorker {
|
||||||
|
|
||||||
|
public UpdateResourceWorker(String name, String resourceId) {
|
||||||
|
super(name, resourceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doWork(PersistenceTransaction tx) {
|
||||||
|
|
||||||
|
IdOfSubTypeRef objectRef = tx.getObjectRefCache().getIdOfSubTypeRef(TYPE_RES, RES_TYPE, this.resourceId);
|
||||||
|
MyModel resource = tx.getObjectDao().queryById(objectRef);
|
||||||
|
assertNotNull(resource);
|
||||||
|
updateResource(resource);
|
||||||
|
|
||||||
|
tx.getObjectDao().update(resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,226 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.test;
|
||||||
|
|
||||||
|
import static ch.eitchnet.xmlpers.test.model.ModelBuilder.BOOK_ID;
|
||||||
|
import static ch.eitchnet.xmlpers.test.model.ModelBuilder.assertBook;
|
||||||
|
import static ch.eitchnet.xmlpers.test.model.ModelBuilder.assertBookUpdated;
|
||||||
|
import static ch.eitchnet.xmlpers.test.model.ModelBuilder.createBook;
|
||||||
|
import static ch.eitchnet.xmlpers.test.model.ModelBuilder.updateBook;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.IoMode;
|
||||||
|
import ch.eitchnet.xmlpers.api.ObjectDao;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceConstants;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceTransaction;
|
||||||
|
import ch.eitchnet.xmlpers.objref.IdOfTypeRef;
|
||||||
|
import ch.eitchnet.xmlpers.objref.ObjectRef;
|
||||||
|
import ch.eitchnet.xmlpers.objref.TypeRef;
|
||||||
|
import ch.eitchnet.xmlpers.test.impl.TestConstants;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.Book;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ObjectDaoBookTest extends AbstractPersistenceTest {
|
||||||
|
|
||||||
|
private static final String BASEPATH = "target/db/ObjectDaoTest/"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
cleanPath(BASEPATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setup(IoMode ioMode) {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.setProperty(PersistenceConstants.PROP_BASEPATH, BASEPATH + ioMode.name());
|
||||||
|
setup(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCrudSax() {
|
||||||
|
setup(IoMode.SAX);
|
||||||
|
testCrud(IoMode.SAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCrudDom() {
|
||||||
|
setup(IoMode.DOM);
|
||||||
|
testCrud(IoMode.DOM);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PersistenceTransaction freshTx(IoMode ioMode) {
|
||||||
|
PersistenceTransaction tx = this.persistenceManager.openTx();
|
||||||
|
tx.setIoMode(ioMode);
|
||||||
|
return tx;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testCrud(IoMode ioMode) {
|
||||||
|
|
||||||
|
ObjectDao objectDao;
|
||||||
|
|
||||||
|
// create new book
|
||||||
|
Book book = createBook();
|
||||||
|
try (PersistenceTransaction tx = freshTx(ioMode);) {
|
||||||
|
objectDao = tx.getObjectDao();
|
||||||
|
objectDao.add(book);
|
||||||
|
}
|
||||||
|
|
||||||
|
// read book
|
||||||
|
try (PersistenceTransaction tx = freshTx(ioMode);) {
|
||||||
|
IdOfTypeRef bookRef = tx.getObjectRefCache()
|
||||||
|
.getIdOfTypeRef(TestConstants.TYPE_BOOK, Long.toString(BOOK_ID));
|
||||||
|
objectDao = tx.getObjectDao();
|
||||||
|
book = objectDao.queryById(bookRef);
|
||||||
|
assertBook(book);
|
||||||
|
|
||||||
|
// modify book
|
||||||
|
updateBook(book);
|
||||||
|
objectDao.update(book);
|
||||||
|
}
|
||||||
|
|
||||||
|
// read modified book
|
||||||
|
try (PersistenceTransaction tx = freshTx(ioMode);) {
|
||||||
|
IdOfTypeRef bookRef = tx.getObjectRefCache()
|
||||||
|
.getIdOfTypeRef(TestConstants.TYPE_BOOK, Long.toString(BOOK_ID));
|
||||||
|
objectDao = tx.getObjectDao();
|
||||||
|
book = objectDao.queryById(bookRef);
|
||||||
|
assertBookUpdated(book);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete book
|
||||||
|
try (PersistenceTransaction tx = freshTx(ioMode);) {
|
||||||
|
objectDao = tx.getObjectDao();
|
||||||
|
objectDao.remove(book);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fail to read
|
||||||
|
try (PersistenceTransaction tx = freshTx(ioMode);) {
|
||||||
|
IdOfTypeRef bookRef = tx.getObjectRefCache()
|
||||||
|
.getIdOfTypeRef(TestConstants.TYPE_BOOK, Long.toString(BOOK_ID));
|
||||||
|
objectDao = tx.getObjectDao();
|
||||||
|
book = objectDao.queryById(bookRef);
|
||||||
|
assertNull(book);
|
||||||
|
|
||||||
|
// and create again
|
||||||
|
book = createBook();
|
||||||
|
assertBook(book);
|
||||||
|
objectDao.add(book);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBulkSax() {
|
||||||
|
setup(IoMode.SAX);
|
||||||
|
testBulk(IoMode.SAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBulkDom() {
|
||||||
|
setup(IoMode.DOM);
|
||||||
|
testBulk(IoMode.DOM);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testBulk(IoMode ioMode) {
|
||||||
|
|
||||||
|
// create a list of books
|
||||||
|
List<Book> books = new ArrayList<>(10);
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
long id = i;
|
||||||
|
String title = "Bulk Test Book. " + i; //$NON-NLS-1$
|
||||||
|
String author = "Nick Hornby"; //$NON-NLS-1$
|
||||||
|
String press = "Penguin Books"; //$NON-NLS-1$
|
||||||
|
double price = 21.30;
|
||||||
|
|
||||||
|
Book book = createBook(id, title, author, press, price);
|
||||||
|
books.add(book);
|
||||||
|
}
|
||||||
|
|
||||||
|
// save all
|
||||||
|
try (PersistenceTransaction tx = freshTx(ioMode);) {
|
||||||
|
ObjectDao objectDao = tx.getObjectDao();
|
||||||
|
objectDao.addAll(books);
|
||||||
|
books.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// query all
|
||||||
|
try (PersistenceTransaction tx = freshTx(ioMode);) {
|
||||||
|
TypeRef typeRef = tx.getObjectRefCache().getTypeRef(TestConstants.TYPE_BOOK);
|
||||||
|
ObjectDao objectDao = tx.getObjectDao();
|
||||||
|
books = objectDao.queryAll(typeRef);
|
||||||
|
assertEquals("Expected to find 10 entries!", 10, books.size()); //$NON-NLS-1$
|
||||||
|
|
||||||
|
// delete them all
|
||||||
|
objectDao.removeAll(books);
|
||||||
|
}
|
||||||
|
|
||||||
|
// now query them again
|
||||||
|
try (PersistenceTransaction tx = freshTx(ioMode);) {
|
||||||
|
TypeRef typeRef = tx.getObjectRefCache().getTypeRef(TestConstants.TYPE_BOOK);
|
||||||
|
ObjectDao objectDao = tx.getObjectDao();
|
||||||
|
books = objectDao.queryAll(typeRef);
|
||||||
|
assertEquals("Expected to find 0 entries!", 0, books.size()); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldPersistById() {
|
||||||
|
setup(IoMode.SAX);
|
||||||
|
|
||||||
|
String classType = TestConstants.TYPE_BOOK;
|
||||||
|
long id = System.currentTimeMillis();
|
||||||
|
String title = "About a boy"; //$NON-NLS-1$
|
||||||
|
String author = "Nick Hornby"; //$NON-NLS-1$
|
||||||
|
String press = "Penguin Books"; //$NON-NLS-1$
|
||||||
|
double price = 21.30;
|
||||||
|
|
||||||
|
// create a book
|
||||||
|
try (PersistenceTransaction tx = this.persistenceManager.openTx()) {
|
||||||
|
Book book = createBook(id, title, author, press, price);
|
||||||
|
tx.getObjectDao().add(book);
|
||||||
|
}
|
||||||
|
|
||||||
|
// read by id
|
||||||
|
try (PersistenceTransaction tx = this.persistenceManager.openTx()) {
|
||||||
|
ObjectRef objectRef = tx.getObjectRefCache().getIdOfTypeRef(classType, Long.toString(id));
|
||||||
|
Book book = tx.getObjectDao().queryById(objectRef);
|
||||||
|
assertNotNull("Expected to read book by ID", book); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete by id
|
||||||
|
try (PersistenceTransaction tx = this.persistenceManager.openTx()) {
|
||||||
|
ObjectRef objectRef = tx.getObjectRefCache().getIdOfTypeRef(classType, Long.toString(id));
|
||||||
|
tx.getObjectDao().removeById(objectRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fail to read by id
|
||||||
|
try (PersistenceTransaction tx = this.persistenceManager.openTx()) {
|
||||||
|
ObjectRef objectRef = tx.getObjectRefCache().getIdOfTypeRef(classType, Long.toString(id));
|
||||||
|
Book book = tx.getObjectDao().queryById(objectRef);
|
||||||
|
assertNull("Expected that book was deleted by ID, thus can not be read anymore", book); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,357 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.test;
|
||||||
|
|
||||||
|
import static ch.eitchnet.xmlpers.test.impl.TestConstants.TYPE_RES;
|
||||||
|
import static ch.eitchnet.xmlpers.test.model.ModelBuilder.RES_ID;
|
||||||
|
import static ch.eitchnet.xmlpers.test.model.ModelBuilder.RES_TYPE;
|
||||||
|
import static ch.eitchnet.xmlpers.test.model.ModelBuilder.assertResource;
|
||||||
|
import static ch.eitchnet.xmlpers.test.model.ModelBuilder.assertResourceUpdated;
|
||||||
|
import static ch.eitchnet.xmlpers.test.model.ModelBuilder.createResource;
|
||||||
|
import static ch.eitchnet.xmlpers.test.model.ModelBuilder.updateResource;
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.ExpectedException;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.IoMode;
|
||||||
|
import ch.eitchnet.xmlpers.api.ObjectDao;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceConstants;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceTransaction;
|
||||||
|
import ch.eitchnet.xmlpers.api.XmlPersistenceException;
|
||||||
|
import ch.eitchnet.xmlpers.objref.IdOfSubTypeRef;
|
||||||
|
import ch.eitchnet.xmlpers.objref.ObjectRef;
|
||||||
|
import ch.eitchnet.xmlpers.objref.SubTypeRef;
|
||||||
|
import ch.eitchnet.xmlpers.test.impl.TestConstants;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.ModelBuilder;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.MyModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ObjectDaoResourceTest extends AbstractPersistenceTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ExpectedException thrown = ExpectedException.none();
|
||||||
|
|
||||||
|
private static final String BASEPATH = "target/db/ObjectDaoTest/"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void beforeClass() {
|
||||||
|
cleanPath(BASEPATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setup(IoMode ioMode) {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.setProperty(PersistenceConstants.PROP_BASEPATH, BASEPATH + ioMode.name());
|
||||||
|
setup(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCrudSax() {
|
||||||
|
setup(IoMode.SAX);
|
||||||
|
testCrud(IoMode.SAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCrudDom() {
|
||||||
|
setup(IoMode.DOM);
|
||||||
|
testCrud(IoMode.DOM);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PersistenceTransaction freshTx(IoMode ioMode) {
|
||||||
|
PersistenceTransaction tx = this.persistenceManager.openTx();
|
||||||
|
tx.setIoMode(ioMode);
|
||||||
|
return tx;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testCrud(IoMode ioMode) {
|
||||||
|
|
||||||
|
ObjectDao objectDao;
|
||||||
|
|
||||||
|
// create new resource
|
||||||
|
MyModel resource = createResource();
|
||||||
|
try (PersistenceTransaction tx = freshTx(ioMode);) {
|
||||||
|
objectDao = tx.getObjectDao();
|
||||||
|
objectDao.add(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// read resource
|
||||||
|
try (PersistenceTransaction tx = freshTx(ioMode);) {
|
||||||
|
IdOfSubTypeRef resRef = tx.getObjectRefCache().getIdOfSubTypeRef(TestConstants.TYPE_RES, RES_TYPE, RES_ID);
|
||||||
|
objectDao = tx.getObjectDao();
|
||||||
|
resource = objectDao.queryById(resRef);
|
||||||
|
assertResource(resource);
|
||||||
|
|
||||||
|
// modify resource
|
||||||
|
updateResource(resource);
|
||||||
|
objectDao.update(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// read modified resource
|
||||||
|
try (PersistenceTransaction tx = freshTx(ioMode);) {
|
||||||
|
IdOfSubTypeRef resRef = tx.getObjectRefCache().getIdOfSubTypeRef(TestConstants.TYPE_RES, RES_TYPE, RES_ID);
|
||||||
|
objectDao = tx.getObjectDao();
|
||||||
|
resource = objectDao.queryById(resRef);
|
||||||
|
assertResourceUpdated(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete resource
|
||||||
|
try (PersistenceTransaction tx = freshTx(ioMode);) {
|
||||||
|
objectDao = tx.getObjectDao();
|
||||||
|
objectDao.remove(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fail to read
|
||||||
|
try (PersistenceTransaction tx = freshTx(ioMode);) {
|
||||||
|
IdOfSubTypeRef resRef = tx.getObjectRefCache().getIdOfSubTypeRef(TestConstants.TYPE_RES, RES_TYPE, RES_ID);
|
||||||
|
objectDao = tx.getObjectDao();
|
||||||
|
resource = objectDao.queryById(resRef);
|
||||||
|
assertNull(resource);
|
||||||
|
|
||||||
|
// and create again
|
||||||
|
resource = createResource();
|
||||||
|
assertResource(resource);
|
||||||
|
objectDao.add(resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBulkSax() {
|
||||||
|
setup(IoMode.SAX);
|
||||||
|
testBulk(IoMode.SAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBulkDom() {
|
||||||
|
setup(IoMode.DOM);
|
||||||
|
testBulk(IoMode.DOM);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testBulk(IoMode ioMode) {
|
||||||
|
|
||||||
|
// context
|
||||||
|
String type = "testBulk" + ioMode.name(); //$NON-NLS-1$
|
||||||
|
|
||||||
|
// create a list of resources
|
||||||
|
List<MyModel> resources = new ArrayList<>(10);
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
String id = RES_ID + "_" + i; //$NON-NLS-1$
|
||||||
|
String name = "Bulk Test Object. " + i; //$NON-NLS-1$
|
||||||
|
|
||||||
|
MyModel resource = createResource(id, name, type);
|
||||||
|
resources.add(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// save all
|
||||||
|
try (PersistenceTransaction tx = freshTx(ioMode);) {
|
||||||
|
ObjectDao objectDao = tx.getObjectDao();
|
||||||
|
objectDao.addAll(resources);
|
||||||
|
resources.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// query all
|
||||||
|
try (PersistenceTransaction tx = freshTx(ioMode);) {
|
||||||
|
SubTypeRef subTypeRef = tx.getObjectRefCache().getSubTypeRef(TestConstants.TYPE_RES, type);
|
||||||
|
ObjectDao objectDao = tx.getObjectDao();
|
||||||
|
resources = objectDao.queryAll(subTypeRef);
|
||||||
|
assertEquals("Expected to find 10 entries!", 10, resources.size()); //$NON-NLS-1$
|
||||||
|
|
||||||
|
// delete them all
|
||||||
|
objectDao.removeAll(resources);
|
||||||
|
}
|
||||||
|
|
||||||
|
// now query them again
|
||||||
|
try (PersistenceTransaction tx = freshTx(ioMode);) {
|
||||||
|
SubTypeRef subTypeRef = tx.getObjectRefCache().getSubTypeRef(TestConstants.TYPE_RES, type);
|
||||||
|
ObjectDao objectDao = tx.getObjectDao();
|
||||||
|
resources = objectDao.queryAll(subTypeRef);
|
||||||
|
assertEquals("Expected to find 0 entries!", 0, resources.size()); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldPersistById() {
|
||||||
|
setup(IoMode.SAX);
|
||||||
|
|
||||||
|
String classType = TestConstants.TYPE_RES;
|
||||||
|
String subType = ModelBuilder.RES_TYPE;
|
||||||
|
String id = "shouldPersistById"; //$NON-NLS-1$
|
||||||
|
String name = "shouldPersistById "; //$NON-NLS-1$
|
||||||
|
|
||||||
|
// create a resource
|
||||||
|
try (PersistenceTransaction tx = this.persistenceManager.openTx()) {
|
||||||
|
MyModel resource = createResource(id, name, subType);
|
||||||
|
tx.getObjectDao().add(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// read by id
|
||||||
|
try (PersistenceTransaction tx = this.persistenceManager.openTx()) {
|
||||||
|
ObjectRef objectRef = tx.getObjectRefCache().getIdOfSubTypeRef(classType, subType, id);
|
||||||
|
MyModel resource = tx.getObjectDao().queryById(objectRef);
|
||||||
|
assertNotNull("Expected to read resource by ID", resource); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete by id
|
||||||
|
try (PersistenceTransaction tx = this.persistenceManager.openTx()) {
|
||||||
|
ObjectRef objectRef = tx.getObjectRefCache().getIdOfSubTypeRef(classType, subType, id);
|
||||||
|
tx.getObjectDao().removeById(objectRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fail to read by id
|
||||||
|
try (PersistenceTransaction tx = this.persistenceManager.openTx()) {
|
||||||
|
ObjectRef objectRef = tx.getObjectRefCache().getIdOfSubTypeRef(classType, subType, id);
|
||||||
|
MyModel resource = tx.getObjectDao().queryById(objectRef);
|
||||||
|
assertNull("Expected that resource was deleted by ID, thus can not be read anymore", resource); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldFailModifyNotExisting() {
|
||||||
|
setup(IoMode.SAX);
|
||||||
|
|
||||||
|
this.thrown.expect(XmlPersistenceException.class);
|
||||||
|
this.thrown.expectMessage(containsString("Persistence unit does not exist for")); //$NON-NLS-1$
|
||||||
|
|
||||||
|
// update
|
||||||
|
try (PersistenceTransaction tx = this.persistenceManager.openTx()) {
|
||||||
|
|
||||||
|
MyModel resource = createResource();
|
||||||
|
tx.getObjectDao().update(resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldFailDeleteNotExisting() {
|
||||||
|
setup(IoMode.SAX);
|
||||||
|
|
||||||
|
this.thrown.expect(XmlPersistenceException.class);
|
||||||
|
this.thrown.expectMessage(containsString("Persistence unit does not exist for")); //$NON-NLS-1$
|
||||||
|
|
||||||
|
// delete
|
||||||
|
try (PersistenceTransaction tx = this.persistenceManager.openTx()) {
|
||||||
|
|
||||||
|
MyModel resource = createResource();
|
||||||
|
tx.getObjectDao().remove(resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldAllowAllOperationsInSameTx() {
|
||||||
|
setup(IoMode.SAX);
|
||||||
|
|
||||||
|
String subType = ModelBuilder.RES_TYPE;
|
||||||
|
String name = "shouldPersistById "; //$NON-NLS-1$
|
||||||
|
|
||||||
|
// create
|
||||||
|
try (PersistenceTransaction tx = this.persistenceManager.openTx()) {
|
||||||
|
|
||||||
|
String id = "shouldAllowAllOperationsInSameTx_create"; //$NON-NLS-1$
|
||||||
|
MyModel resource = createResource(id, name, subType);
|
||||||
|
|
||||||
|
tx.getObjectDao().add(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create / modify
|
||||||
|
try (PersistenceTransaction tx = this.persistenceManager.openTx()) {
|
||||||
|
|
||||||
|
String id = "shouldAllowAllOperationsInSameTx_create_modify"; //$NON-NLS-1$
|
||||||
|
MyModel resource = createResource(id, name, subType);
|
||||||
|
|
||||||
|
tx.getObjectDao().add(resource);
|
||||||
|
tx.getObjectDao().update(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create / delete
|
||||||
|
try (PersistenceTransaction tx = this.persistenceManager.openTx()) {
|
||||||
|
|
||||||
|
String id = "shouldAllowAllOperationsInSameTx_create_delete"; //$NON-NLS-1$
|
||||||
|
MyModel resource = createResource(id, name, subType);
|
||||||
|
|
||||||
|
tx.getObjectDao().add(resource);
|
||||||
|
tx.getObjectDao().remove(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create / modify / delete
|
||||||
|
try (PersistenceTransaction tx = this.persistenceManager.openTx()) {
|
||||||
|
|
||||||
|
String id = "shouldAllowAllOperationsInSameTx_create_modify_delete"; //$NON-NLS-1$
|
||||||
|
MyModel resource = createResource(id, name, subType);
|
||||||
|
|
||||||
|
tx.getObjectDao().add(resource);
|
||||||
|
tx.getObjectDao().update(resource);
|
||||||
|
tx.getObjectDao().remove(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
String id = "shouldAllowAllOperationsInSameTx_read_modify"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
// prepare for read/modify
|
||||||
|
try (PersistenceTransaction tx = this.persistenceManager.openTx()) {
|
||||||
|
MyModel resource = createResource(id, name, subType);
|
||||||
|
tx.getObjectDao().add(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// read / modify
|
||||||
|
try (PersistenceTransaction tx = this.persistenceManager.openTx()) {
|
||||||
|
|
||||||
|
ObjectRef objectRef = tx.getObjectRefCache().getIdOfSubTypeRef(TYPE_RES, subType, id);
|
||||||
|
Object resource = tx.getObjectDao().queryById(objectRef);
|
||||||
|
assertNotNull(resource);
|
||||||
|
tx.getObjectDao().update(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// read / delete
|
||||||
|
try (PersistenceTransaction tx = this.persistenceManager.openTx()) {
|
||||||
|
|
||||||
|
ObjectRef objectRef = tx.getObjectRefCache().getIdOfSubTypeRef(TYPE_RES, subType, id);
|
||||||
|
Object resource = tx.getObjectDao().queryById(objectRef);
|
||||||
|
assertNotNull(resource);
|
||||||
|
tx.getObjectDao().remove(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure deleted, then recreate
|
||||||
|
try (PersistenceTransaction tx = this.persistenceManager.openTx()) {
|
||||||
|
|
||||||
|
ObjectRef objectRef = tx.getObjectRefCache().getIdOfSubTypeRef(TYPE_RES, subType, id);
|
||||||
|
Object resource = tx.getObjectDao().queryById(objectRef);
|
||||||
|
assertNull(resource);
|
||||||
|
|
||||||
|
// recreate
|
||||||
|
resource = createResource(id, name, subType);
|
||||||
|
tx.getObjectDao().add(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// read / modify / delete
|
||||||
|
try (PersistenceTransaction tx = this.persistenceManager.openTx()) {
|
||||||
|
|
||||||
|
ObjectRef objectRef = tx.getObjectRefCache().getIdOfSubTypeRef(TYPE_RES, subType, id);
|
||||||
|
Object resource = tx.getObjectDao().queryById(objectRef);
|
||||||
|
assertNotNull(resource);
|
||||||
|
tx.getObjectDao().update(resource);
|
||||||
|
tx.getObjectDao().remove(resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.IoMode;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceConstants;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceTransaction;
|
||||||
|
import ch.eitchnet.xmlpers.objref.ObjectRef;
|
||||||
|
import ch.eitchnet.xmlpers.test.impl.TestConstants;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.ModelBuilder;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.MyModel;
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
public class RealmTest extends AbstractPersistenceTest {
|
||||||
|
|
||||||
|
private static final String REALM_2 = "Realm2";
|
||||||
|
private static final String REALM_1 = "Realm1";
|
||||||
|
protected static final String BASE_PATH = "target/db/RealmTest/";
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void beforeClass() {
|
||||||
|
cleanPath(BASE_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.setProperty(PersistenceConstants.PROP_BASEPATH, BASE_PATH + IoMode.DOM.name());
|
||||||
|
setup(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldNotFindObjInBothRealms() {
|
||||||
|
|
||||||
|
// object details
|
||||||
|
String objType = TestConstants.TYPE_RES;
|
||||||
|
String type = ModelBuilder.RES_TYPE;
|
||||||
|
String name = ModelBuilder.RES_NAME;
|
||||||
|
String id = "shouldNotFindObjInBothRealms";
|
||||||
|
|
||||||
|
// create in first realm
|
||||||
|
try (PersistenceTransaction txRealm1 = this.persistenceManager.openTx(REALM_1);) {
|
||||||
|
MyModel resource1 = ModelBuilder.createResource(id, name, type);
|
||||||
|
txRealm1.getObjectDao().add(resource1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// find in first realm
|
||||||
|
try (PersistenceTransaction txRealm1 = this.persistenceManager.openTx(REALM_1);) {
|
||||||
|
ObjectRef objectRef = txRealm1.getObjectRefCache().getIdOfSubTypeRef(objType, type, id);
|
||||||
|
MyModel resource = txRealm1.getObjectDao().queryById(objectRef);
|
||||||
|
assertNotNull("Resource was not found in first realm!", resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fail to find in second realm
|
||||||
|
try (PersistenceTransaction txRealm2 = this.persistenceManager.openTx(REALM_2);) {
|
||||||
|
ObjectRef objectRef = txRealm2.getObjectRefCache().getIdOfSubTypeRef(objType, type, id);
|
||||||
|
MyModel resource = txRealm2.getObjectDao().queryById(objectRef);
|
||||||
|
assertNull("Resource was not created in second realm, thus not expected to be found there!", resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldNotDeleteObjInWrongRealm() {
|
||||||
|
|
||||||
|
// object details
|
||||||
|
String objType = TestConstants.TYPE_RES;
|
||||||
|
String subType = ModelBuilder.RES_TYPE;
|
||||||
|
String name = ModelBuilder.RES_NAME;
|
||||||
|
String id = "shouldNotDeleteObjInWrongRealm";
|
||||||
|
|
||||||
|
// create in first realm
|
||||||
|
try (PersistenceTransaction txRealm1 = this.persistenceManager.openTx(REALM_1);) {
|
||||||
|
MyModel resource1 = ModelBuilder.createResource(id, name, subType);
|
||||||
|
txRealm1.getObjectDao().add(resource1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create in second realm
|
||||||
|
try (PersistenceTransaction txRealm2 = this.persistenceManager.openTx(REALM_2);) {
|
||||||
|
MyModel resource1 = ModelBuilder.createResource(id, name, subType);
|
||||||
|
txRealm2.getObjectDao().add(resource1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete in second realm
|
||||||
|
try (PersistenceTransaction txRealm2 = this.persistenceManager.openTx(REALM_2);) {
|
||||||
|
ObjectRef objectRef = txRealm2.getObjectRefCache().getIdOfSubTypeRef(objType, subType, id);
|
||||||
|
txRealm2.getObjectDao().removeById(objectRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fail to find in second realm
|
||||||
|
try (PersistenceTransaction txRealm2 = this.persistenceManager.openTx(REALM_2);) {
|
||||||
|
ObjectRef objectRef = txRealm2.getObjectRefCache().getIdOfSubTypeRef(objType, subType, id);
|
||||||
|
MyModel resource = txRealm2.getObjectDao().queryById(objectRef);
|
||||||
|
assertNull("Resource was not deleted from second realm, thus not expected to be found there!", resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// find in first realm
|
||||||
|
try (PersistenceTransaction txRealm1 = this.persistenceManager.openTx(REALM_1);) {
|
||||||
|
ObjectRef objectRef = txRealm1.getObjectRefCache().getIdOfSubTypeRef(objType, subType, id);
|
||||||
|
MyModel resource = txRealm1.getObjectDao().queryById(objectRef);
|
||||||
|
assertNotNull("Resource was not found in first realm!", resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,135 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.test;
|
||||||
|
|
||||||
|
import static ch.eitchnet.xmlpers.test.model.ModelBuilder.RES_ID;
|
||||||
|
import static ch.eitchnet.xmlpers.test.model.ModelBuilder.createResource;
|
||||||
|
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.ExpectedException;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.IoMode;
|
||||||
|
import ch.eitchnet.xmlpers.api.ModificationResult;
|
||||||
|
import ch.eitchnet.xmlpers.api.ObjectDao;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceConstants;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceTransaction;
|
||||||
|
import ch.eitchnet.xmlpers.api.TransactionResult;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.Book;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.MyModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TransactionResultTest extends AbstractPersistenceTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ExpectedException thrown = ExpectedException.none();
|
||||||
|
|
||||||
|
private static final String BASEPATH = "target/db/TxResultTest/"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
cleanPath(BASEPATH);
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.setProperty(PersistenceConstants.PROP_BASEPATH, BASEPATH);
|
||||||
|
setup(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PersistenceTransaction freshTx() {
|
||||||
|
PersistenceTransaction tx = this.persistenceManager.openTx();
|
||||||
|
tx.setIoMode(IoMode.SAX);
|
||||||
|
return tx;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWithTxResult() {
|
||||||
|
|
||||||
|
TransactionResult txResult = new TransactionResult();
|
||||||
|
performChanges(txResult);
|
||||||
|
String logMessage = txResult.getLogMessage();
|
||||||
|
logger.info(logMessage);
|
||||||
|
assertThat(logMessage, containsString("TX for realm defaultRealm was completed after")); //$NON-NLS-1$
|
||||||
|
assertThat(logMessage, containsString("30 objects in 2 types were modified")); //$NON-NLS-1$
|
||||||
|
assertThat(txResult.getKeys(), containsInAnyOrder("Resource", "Book")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
|
ModificationResult resourceModificationResult = txResult.getModificationResult("Resource"); //$NON-NLS-1$
|
||||||
|
assertEquals(20, resourceModificationResult.getCreated().size());
|
||||||
|
assertEquals(0, resourceModificationResult.getUpdated().size());
|
||||||
|
assertEquals(0, resourceModificationResult.getDeleted().size());
|
||||||
|
|
||||||
|
ModificationResult bookModificationResult = txResult.getModificationResult("Book"); //$NON-NLS-1$
|
||||||
|
assertEquals(10, bookModificationResult.getCreated().size());
|
||||||
|
assertEquals(0, bookModificationResult.getUpdated().size());
|
||||||
|
assertEquals(0, bookModificationResult.getDeleted().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWithoutTxResult() {
|
||||||
|
performChanges(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void performChanges(TransactionResult txResult) {
|
||||||
|
|
||||||
|
// create a list of resources
|
||||||
|
List<MyModel> resources = new ArrayList<>(10);
|
||||||
|
int i = 0;
|
||||||
|
for (; i < 10; i++) {
|
||||||
|
String id = RES_ID + "_" + i; //$NON-NLS-1$
|
||||||
|
String name = "Tx Result Test 1 Object. " + i; //$NON-NLS-1$
|
||||||
|
String type = "testTxResult1"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
MyModel resource = createResource(id, name, type);
|
||||||
|
resources.add(resource);
|
||||||
|
}
|
||||||
|
for (; i < 20; i++) {
|
||||||
|
String id = RES_ID + "_" + i; //$NON-NLS-1$
|
||||||
|
String name = "Tx Result Test 2 Object. " + i; //$NON-NLS-1$
|
||||||
|
String type = "testTxResult2"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
MyModel resource = createResource(id, name, type);
|
||||||
|
resources.add(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a list of books
|
||||||
|
List<Book> books = new ArrayList<>(10);
|
||||||
|
i = 0;
|
||||||
|
for (; i < 10; i++) {
|
||||||
|
String title = "Tx Result Test Book " + i; //$NON-NLS-1$
|
||||||
|
Book book = new Book((long) i, title, "Douglas Adams", "Apress", Math.random() * i); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
books.add(book);
|
||||||
|
}
|
||||||
|
|
||||||
|
// save all
|
||||||
|
try (PersistenceTransaction tx = freshTx();) {
|
||||||
|
tx.setTransactionResult(txResult);
|
||||||
|
ObjectDao objectDao = tx.getObjectDao();
|
||||||
|
objectDao.addAll(resources);
|
||||||
|
objectDao.addAll(books);
|
||||||
|
resources.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,298 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javanet.staxutils.IndentingXMLStreamWriter;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.parsers.SAXParser;
|
||||||
|
import javax.xml.parsers.SAXParserFactory;
|
||||||
|
import javax.xml.stream.XMLOutputFactory;
|
||||||
|
import javax.xml.stream.XMLStreamWriter;
|
||||||
|
import javax.xml.transform.OutputKeys;
|
||||||
|
import javax.xml.transform.Source;
|
||||||
|
import javax.xml.transform.Transformer;
|
||||||
|
import javax.xml.transform.TransformerFactory;
|
||||||
|
import javax.xml.transform.dom.DOMSource;
|
||||||
|
import javax.xml.transform.stream.StreamResult;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.NodeList;
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
import org.xml.sax.helpers.DefaultHandler;
|
||||||
|
|
||||||
|
import ch.eitchnet.utils.exceptions.XmlException;
|
||||||
|
import ch.eitchnet.utils.helper.XmlHelper;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.ModelBuilder;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.MyModel;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.MyParameter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
public class XmlTestMain {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(XmlTestMain.class);
|
||||||
|
|
||||||
|
private static MyModel res;
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
|
res = ModelBuilder.createResource();
|
||||||
|
|
||||||
|
logger.info("Writing Res:\n" + res);
|
||||||
|
|
||||||
|
writeSax(res);
|
||||||
|
writeDom(res);
|
||||||
|
|
||||||
|
List<MyModel> resoures;
|
||||||
|
resoures = readDom();
|
||||||
|
logger.info("Parsed Resources:\n" + resoures);
|
||||||
|
resoures = readSax();
|
||||||
|
logger.info("Parsed Resources:\n" + resoures);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static List<MyModel> readDom() throws Exception {
|
||||||
|
|
||||||
|
File file = new File("target/res_dom.xml");
|
||||||
|
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
|
||||||
|
DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
|
||||||
|
Document document = docBuilder.parse(file);
|
||||||
|
Element rootElement = document.getDocumentElement();
|
||||||
|
|
||||||
|
List<MyModel> resources = new ArrayList<>();
|
||||||
|
|
||||||
|
NodeList resElements = rootElement.getElementsByTagName("Resource");
|
||||||
|
for (int i = 0; i < resElements.getLength(); i++) {
|
||||||
|
Element resElement = (Element) resElements.item(i);
|
||||||
|
String id = resElement.getAttribute("id");
|
||||||
|
String name = resElement.getAttribute("name");
|
||||||
|
String type = resElement.getAttribute("type");
|
||||||
|
|
||||||
|
MyModel res = new MyModel();
|
||||||
|
res.setId(id);
|
||||||
|
res.setName(name);
|
||||||
|
res.setType(type);
|
||||||
|
|
||||||
|
NodeList paramElements = resElement.getElementsByTagName("Parameter");
|
||||||
|
parseParameters(res, paramElements);
|
||||||
|
|
||||||
|
resources.add(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("DOM parsed file " + file.getAbsolutePath());
|
||||||
|
|
||||||
|
return resources;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void parseParameters(MyModel res, NodeList paramElements) {
|
||||||
|
for (int i = 0; i < paramElements.getLength(); i++) {
|
||||||
|
Element paramElement = (Element) paramElements.item(i);
|
||||||
|
String id = paramElement.getAttribute("id");
|
||||||
|
String name = paramElement.getAttribute("name");
|
||||||
|
String type = paramElement.getAttribute("type");
|
||||||
|
String value = paramElement.getAttribute("value");
|
||||||
|
|
||||||
|
MyParameter param = new MyParameter();
|
||||||
|
param.setId(id);
|
||||||
|
param.setName(name);
|
||||||
|
param.setType(type);
|
||||||
|
param.setValue(value);
|
||||||
|
|
||||||
|
res.addParameter(param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static List<MyModel> readSax() throws Exception {
|
||||||
|
|
||||||
|
final List<MyModel> resources = new ArrayList<>();
|
||||||
|
final MyModel[] currentRes = new MyModel[1];
|
||||||
|
|
||||||
|
DefaultHandler xmlHandler = new DefaultHandler() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startElement(String uri, String localName, String qName, Attributes attributes)
|
||||||
|
throws SAXException {
|
||||||
|
|
||||||
|
switch (qName) {
|
||||||
|
case "Resource":
|
||||||
|
MyModel res = new MyModel();
|
||||||
|
res.setId(attributes.getValue("id"));
|
||||||
|
res.setName(attributes.getValue("name"));
|
||||||
|
res.setType(attributes.getValue("type"));
|
||||||
|
currentRes[0] = res;
|
||||||
|
resources.add(res);
|
||||||
|
break;
|
||||||
|
case "Parameter":
|
||||||
|
MyParameter param = new MyParameter();
|
||||||
|
param.setId(attributes.getValue("id"));
|
||||||
|
param.setName(attributes.getValue("name"));
|
||||||
|
param.setType(attributes.getValue("type"));
|
||||||
|
param.setValue(attributes.getValue("value"));
|
||||||
|
currentRes[0].addParameter(param);
|
||||||
|
break;
|
||||||
|
case "model":
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("The element '" + qName + "' is unhandled!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SAXParserFactory spf = SAXParserFactory.newInstance();
|
||||||
|
SAXParser sp = spf.newSAXParser();
|
||||||
|
File file = new File("target/res_sax.xml");
|
||||||
|
sp.parse(file, xmlHandler);
|
||||||
|
|
||||||
|
logger.info("SAX parsed file " + file.getAbsolutePath());
|
||||||
|
|
||||||
|
return resources;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void writeDom(MyModel res) throws Exception {
|
||||||
|
|
||||||
|
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
|
||||||
|
DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
|
||||||
|
Document doc = docBuilder.newDocument();
|
||||||
|
|
||||||
|
Element resElement = doc.createElement("Resource");
|
||||||
|
resElement.setAttribute("id", res.getId());
|
||||||
|
resElement.setAttribute("name", res.getName());
|
||||||
|
resElement.setAttribute("type", res.getType());
|
||||||
|
|
||||||
|
for (String paramId : res.getParameterKeySet()) {
|
||||||
|
MyParameter param = res.getParameterBy(paramId);
|
||||||
|
Element paramElement = doc.createElement("Parameter");
|
||||||
|
paramElement.setAttribute("id", param.getId());
|
||||||
|
paramElement.setAttribute("name", param.getName());
|
||||||
|
paramElement.setAttribute("type", param.getType());
|
||||||
|
paramElement.setAttribute("value", param.getValue());
|
||||||
|
resElement.appendChild(paramElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
Element rootElement = doc.createElement("model");
|
||||||
|
rootElement.appendChild(resElement);
|
||||||
|
|
||||||
|
doc.appendChild(rootElement);
|
||||||
|
|
||||||
|
String lineSep = System.getProperty(XmlHelper.PROP_LINE_SEPARATOR);
|
||||||
|
try {
|
||||||
|
|
||||||
|
String encoding = doc.getInputEncoding();
|
||||||
|
if (encoding == null || encoding.isEmpty()) {
|
||||||
|
logger.info("No encoding passed. Using default encoding " + XmlHelper.DEFAULT_ENCODING);
|
||||||
|
encoding = XmlHelper.DEFAULT_ENCODING;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lineSep.equals("\n")) {
|
||||||
|
logger.info("Overriding line separator to \\n");
|
||||||
|
System.setProperty(XmlHelper.PROP_LINE_SEPARATOR, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up a transformer
|
||||||
|
TransformerFactory transfac = TransformerFactory.newInstance();
|
||||||
|
Transformer transformer = transfac.newTransformer();
|
||||||
|
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
|
||||||
|
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||||
|
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
|
||||||
|
transformer.setOutputProperty(OutputKeys.ENCODING, encoding);
|
||||||
|
transformer.setOutputProperty("{http://xml.apache.org/xalan}indent-amount", "2");
|
||||||
|
// transformer.setOutputProperty("{http://xml.apache.org/xalan}line-separator", "\t");
|
||||||
|
|
||||||
|
// Transform to file
|
||||||
|
File file = new File("target/res_dom.xml");
|
||||||
|
StreamResult result = new StreamResult(file);
|
||||||
|
Source xmlSource = new DOMSource(doc);
|
||||||
|
transformer.transform(xmlSource, result);
|
||||||
|
|
||||||
|
logger.info("Wrote DOM to " + file.getAbsolutePath());
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
throw new XmlException("Exception while exporting to file: " + e, e);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
|
||||||
|
System.setProperty(XmlHelper.PROP_LINE_SEPARATOR, lineSep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void writeSax(MyModel res) throws Exception {
|
||||||
|
XMLOutputFactory factory = XMLOutputFactory.newInstance();
|
||||||
|
|
||||||
|
File file = new File("target/res_sax.xml");
|
||||||
|
try (FileWriter fileWriter = new FileWriter(file)) {
|
||||||
|
XMLStreamWriter writer = factory.createXMLStreamWriter(fileWriter);
|
||||||
|
|
||||||
|
writer = new IndentingXMLStreamWriter(writer);
|
||||||
|
|
||||||
|
writer.writeStartDocument("utf-8", "1.0");
|
||||||
|
writer.writeStartElement("model");
|
||||||
|
|
||||||
|
writer.writeStartElement("Resource");
|
||||||
|
writer.writeAttribute("id", res.getId());
|
||||||
|
writer.writeAttribute("name", res.getName());
|
||||||
|
writer.writeAttribute("type", res.getType());
|
||||||
|
|
||||||
|
for (String paramId : res.getParameterKeySet()) {
|
||||||
|
MyParameter param = res.getParameterBy(paramId);
|
||||||
|
writer.writeEmptyElement("Parameter");
|
||||||
|
writer.writeAttribute("id", param.getId());
|
||||||
|
writer.writeAttribute("name", param.getName());
|
||||||
|
writer.writeAttribute("type", param.getType());
|
||||||
|
writer.writeAttribute("value", param.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
//writer.writeEmptyElement("data");
|
||||||
|
//writer.writeAttribute("name", "value");
|
||||||
|
////writer.writeEndElement();
|
||||||
|
//writer.writeEmptyElement("stuff");
|
||||||
|
//writer.writeAttribute("attr", "attrVal");
|
||||||
|
|
||||||
|
writer.writeEndElement();
|
||||||
|
writer.writeEndDocument();
|
||||||
|
|
||||||
|
writer.flush();
|
||||||
|
writer.close();
|
||||||
|
logger.info("Wrote SAX to " + file.getAbsolutePath());
|
||||||
|
|
||||||
|
//Transformer transformer = TransformerFactory.newInstance().newTransformer();
|
||||||
|
//Result outputTarget = new StaxR;
|
||||||
|
//Source xmlSource;
|
||||||
|
//transformer.transform(xmlSource, outputTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.test.impl;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceContext;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceContextFactory;
|
||||||
|
import ch.eitchnet.xmlpers.objref.IdOfTypeRef;
|
||||||
|
import ch.eitchnet.xmlpers.objref.ObjectRef;
|
||||||
|
import ch.eitchnet.xmlpers.objref.ObjectReferenceCache;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.Book;
|
||||||
|
|
||||||
|
public class BookContextFactory implements PersistenceContextFactory<Book> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PersistenceContext<Book> createCtx(ObjectRef objectRef) {
|
||||||
|
PersistenceContext<Book> ctx = new PersistenceContext<>(objectRef);
|
||||||
|
ctx.setParserFactory(new BookParserFactory());
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PersistenceContext<Book> createCtx(ObjectReferenceCache objectRefCache, Book t) {
|
||||||
|
IdOfTypeRef objectRef = objectRefCache.getIdOfTypeRef(TestConstants.TYPE_BOOK, t.getId().toString());
|
||||||
|
PersistenceContext<Book> ctx = createCtx(objectRef);
|
||||||
|
ctx.setObject(t);
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.test.impl;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.DomParser;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.Book;
|
||||||
|
import ch.eitchnet.xmlpers.util.DomUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class BookDomParser implements DomParser<Book> {
|
||||||
|
|
||||||
|
private Book book;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Book getObject() {
|
||||||
|
return this.book;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setObject(Book object) {
|
||||||
|
this.book = object;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
@Override
|
||||||
|
public Document toDom() {
|
||||||
|
|
||||||
|
DocumentBuilder documentBuilder = DomUtil.createDocumentBuilder();
|
||||||
|
Document document = documentBuilder.getDOMImplementation().createDocument(null, null, null);
|
||||||
|
|
||||||
|
Element rootElement = document.createElement("Book");
|
||||||
|
document.appendChild(rootElement);
|
||||||
|
rootElement.setAttribute("id", Long.toString(this.book.getId()));
|
||||||
|
rootElement.setAttribute("title", this.book.getTitle());
|
||||||
|
rootElement.setAttribute("author", this.book.getAuthor());
|
||||||
|
rootElement.setAttribute("press", this.book.getPress());
|
||||||
|
rootElement.setAttribute("price", Double.toString(this.book.getPrice()));
|
||||||
|
|
||||||
|
return document;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
@Override
|
||||||
|
public void fromDom(Document document) {
|
||||||
|
|
||||||
|
Element rootElement = document.getDocumentElement();
|
||||||
|
|
||||||
|
String idS = rootElement.getAttribute("id");
|
||||||
|
long id = Long.parseLong(idS);
|
||||||
|
String title = rootElement.getAttribute("title");
|
||||||
|
String author = rootElement.getAttribute("author");
|
||||||
|
String press = rootElement.getAttribute("press");
|
||||||
|
String priceS = rootElement.getAttribute("price");
|
||||||
|
double price = Double.parseDouble(priceS);
|
||||||
|
|
||||||
|
Book book = new Book(id, title, author, press, price);
|
||||||
|
this.book = book;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.test.impl;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.DomParser;
|
||||||
|
import ch.eitchnet.xmlpers.api.ParserFactory;
|
||||||
|
import ch.eitchnet.xmlpers.api.SaxParser;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.Book;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class BookParserFactory implements ParserFactory<Book> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DomParser<Book> getDomParser() {
|
||||||
|
return new BookDomParser();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SaxParser<Book> getSaxParser() {
|
||||||
|
return new BookSaxParser();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.test.impl;
|
||||||
|
|
||||||
|
import javax.xml.stream.XMLStreamException;
|
||||||
|
import javax.xml.stream.XMLStreamWriter;
|
||||||
|
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
import org.xml.sax.helpers.DefaultHandler;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.SaxParser;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.Book;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class BookSaxParser extends DefaultHandler implements SaxParser<Book> {
|
||||||
|
|
||||||
|
private Book book;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Book getObject() {
|
||||||
|
return this.book;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setObject(Book object) {
|
||||||
|
this.book = object;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DefaultHandler getDefaultHandler() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
@Override
|
||||||
|
public void write(XMLStreamWriter writer) throws XMLStreamException {
|
||||||
|
|
||||||
|
writer.writeEmptyElement("Book");
|
||||||
|
writer.writeAttribute("id", Long.toString(this.book.getId()));
|
||||||
|
writer.writeAttribute("title", this.book.getTitle());
|
||||||
|
writer.writeAttribute("author", this.book.getAuthor());
|
||||||
|
writer.writeAttribute("press", this.book.getPress());
|
||||||
|
writer.writeAttribute("price", Double.toString(this.book.getPrice()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
@Override
|
||||||
|
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||||
|
|
||||||
|
switch (qName) {
|
||||||
|
case "Book":
|
||||||
|
String idS = attributes.getValue("id");
|
||||||
|
long id = Long.parseLong(idS);
|
||||||
|
Book book = new Book(id);
|
||||||
|
book.setTitle(attributes.getValue("title"));
|
||||||
|
book.setAuthor(attributes.getValue("author"));
|
||||||
|
book.setPress(attributes.getValue("press"));
|
||||||
|
String priceS = attributes.getValue("price");
|
||||||
|
double price = Double.parseDouble(priceS);
|
||||||
|
book.setPrice(price);
|
||||||
|
this.book = book;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("The element '" + qName + "' is unhandled!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.test.impl;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceContext;
|
||||||
|
import ch.eitchnet.xmlpers.api.PersistenceContextFactory;
|
||||||
|
import ch.eitchnet.xmlpers.objref.IdOfSubTypeRef;
|
||||||
|
import ch.eitchnet.xmlpers.objref.ObjectRef;
|
||||||
|
import ch.eitchnet.xmlpers.objref.ObjectReferenceCache;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.MyModel;
|
||||||
|
|
||||||
|
public class MyModelContextFactory implements PersistenceContextFactory<MyModel> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PersistenceContext<MyModel> createCtx(ObjectReferenceCache objectRefCache, MyModel t) {
|
||||||
|
IdOfSubTypeRef objectRef = objectRefCache.getIdOfSubTypeRef(TestConstants.TYPE_RES, t.getType(), t.getId());
|
||||||
|
PersistenceContext<MyModel> ctx = createCtx(objectRef);
|
||||||
|
ctx.setObject(t);
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PersistenceContext<MyModel> createCtx(ObjectRef objectRef) {
|
||||||
|
PersistenceContext<MyModel> ctx = new PersistenceContext<>(objectRef);
|
||||||
|
ctx.setParserFactory(new MyModelParserFactory());
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.test.impl;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
import org.w3c.dom.NodeList;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.DomParser;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.MyModel;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.MyParameter;
|
||||||
|
import ch.eitchnet.xmlpers.util.DomUtil;
|
||||||
|
|
||||||
|
public class MyModelDomParser implements DomParser<MyModel> {
|
||||||
|
|
||||||
|
private MyModel resource;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MyModel getObject() {
|
||||||
|
return this.resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setObject(MyModel resource) {
|
||||||
|
this.resource = resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
@Override
|
||||||
|
public Document toDom() {
|
||||||
|
|
||||||
|
DocumentBuilder documentBuilder = DomUtil.createDocumentBuilder();
|
||||||
|
Document document = documentBuilder.getDOMImplementation().createDocument(null, null, null);
|
||||||
|
|
||||||
|
Element element = document.createElement("Resource");
|
||||||
|
document.appendChild(element);
|
||||||
|
|
||||||
|
element.setAttribute("id", this.resource.getId());
|
||||||
|
element.setAttribute("name", this.resource.getName());
|
||||||
|
element.setAttribute("type", this.resource.getType());
|
||||||
|
|
||||||
|
for (String paramId : this.resource.getParameterKeySet()) {
|
||||||
|
MyParameter param = this.resource.getParameterBy(paramId);
|
||||||
|
Element paramElement = document.createElement("Parameter");
|
||||||
|
element.appendChild(paramElement);
|
||||||
|
|
||||||
|
paramElement.setAttribute("id", param.getId());
|
||||||
|
paramElement.setAttribute("name", param.getName());
|
||||||
|
paramElement.setAttribute("type", param.getType());
|
||||||
|
paramElement.setAttribute("value", param.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
return document;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
@Override
|
||||||
|
public void fromDom(Document document) {
|
||||||
|
|
||||||
|
Element rootElement = document.getDocumentElement();
|
||||||
|
|
||||||
|
String id = rootElement.getAttribute("id");
|
||||||
|
String name = rootElement.getAttribute("name");
|
||||||
|
String type = rootElement.getAttribute("type");
|
||||||
|
|
||||||
|
MyModel resource = new MyModel(id, name, type);
|
||||||
|
|
||||||
|
NodeList children = rootElement.getChildNodes();
|
||||||
|
for (int i = 0; i < children.getLength(); i++) {
|
||||||
|
Node item = children.item(i);
|
||||||
|
if (!item.getNodeName().equals("Parameter"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Element paramElement = (Element) item;
|
||||||
|
String paramId = paramElement.getAttribute("id");
|
||||||
|
String paramName = paramElement.getAttribute("name");
|
||||||
|
String paramType = paramElement.getAttribute("type");
|
||||||
|
String paramValue = paramElement.getAttribute("value");
|
||||||
|
|
||||||
|
MyParameter param = new MyParameter(paramId, paramName, paramType, paramValue);
|
||||||
|
resource.addParameter(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.resource = resource;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.test.impl;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.DomParser;
|
||||||
|
import ch.eitchnet.xmlpers.api.ParserFactory;
|
||||||
|
import ch.eitchnet.xmlpers.api.SaxParser;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.MyModel;
|
||||||
|
|
||||||
|
public class MyModelParserFactory implements ParserFactory<MyModel> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DomParser<MyModel> getDomParser() {
|
||||||
|
return new MyModelDomParser();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SaxParser<MyModel> getSaxParser() {
|
||||||
|
return new MyModelSaxParser();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.test.impl;
|
||||||
|
|
||||||
|
import javax.xml.stream.XMLStreamException;
|
||||||
|
import javax.xml.stream.XMLStreamWriter;
|
||||||
|
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
import org.xml.sax.helpers.DefaultHandler;
|
||||||
|
|
||||||
|
import ch.eitchnet.xmlpers.api.SaxParser;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.MyModel;
|
||||||
|
import ch.eitchnet.xmlpers.test.model.MyParameter;
|
||||||
|
|
||||||
|
class MyModelSaxParser extends DefaultHandler implements SaxParser<MyModel> {
|
||||||
|
|
||||||
|
private MyModel resource;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MyModel getObject() {
|
||||||
|
return this.resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setObject(MyModel object) {
|
||||||
|
this.resource = object;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DefaultHandler getDefaultHandler() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
@Override
|
||||||
|
public void write(XMLStreamWriter writer) throws XMLStreamException {
|
||||||
|
|
||||||
|
writer.writeStartElement("Resource");
|
||||||
|
writer.writeAttribute("id", this.resource.getId());
|
||||||
|
writer.writeAttribute("name", this.resource.getName());
|
||||||
|
writer.writeAttribute("type", this.resource.getType());
|
||||||
|
for (String paramId : this.resource.getParameterKeySet()) {
|
||||||
|
MyParameter param = this.resource.getParameterBy(paramId);
|
||||||
|
writer.writeEmptyElement("Parameter");
|
||||||
|
writer.writeAttribute("id", param.getId());
|
||||||
|
writer.writeAttribute("name", param.getName());
|
||||||
|
writer.writeAttribute("type", param.getType());
|
||||||
|
writer.writeAttribute("value", param.getValue());
|
||||||
|
}
|
||||||
|
writer.writeEndElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
@Override
|
||||||
|
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||||
|
|
||||||
|
switch (qName) {
|
||||||
|
case "Resource":
|
||||||
|
String id = attributes.getValue("id");
|
||||||
|
String name = attributes.getValue("name");
|
||||||
|
String type = attributes.getValue("type");
|
||||||
|
MyModel resource = new MyModel(id, name, type);
|
||||||
|
this.resource = resource;
|
||||||
|
break;
|
||||||
|
case "Parameter":
|
||||||
|
id = attributes.getValue("id");
|
||||||
|
name = attributes.getValue("name");
|
||||||
|
type = attributes.getValue("type");
|
||||||
|
String value = attributes.getValue("value");
|
||||||
|
MyParameter param = new MyParameter(id, name, type, value);
|
||||||
|
this.resource.addParameter(param);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("The element '" + qName + "' is unhandled!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.test.impl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TestConstants {
|
||||||
|
|
||||||
|
public static final String TYPE_RES = "Resource"; //$NON-NLS-1$
|
||||||
|
public static final String TYPE_BOOK = "Book"; //$NON-NLS-1$
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.test.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Book {
|
||||||
|
|
||||||
|
private final Long id;
|
||||||
|
private String title;
|
||||||
|
private String author;
|
||||||
|
private String press;
|
||||||
|
private double price;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param id
|
||||||
|
* @param title
|
||||||
|
* @param author
|
||||||
|
* @param press
|
||||||
|
* @param price
|
||||||
|
*/
|
||||||
|
public Book(Long id, String title, String author, String press, double price) {
|
||||||
|
super();
|
||||||
|
this.id = id;
|
||||||
|
this.title = title;
|
||||||
|
this.author = author;
|
||||||
|
this.press = press;
|
||||||
|
this.price = price;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public Book(Long id) {
|
||||||
|
if (id == null)
|
||||||
|
throw new IllegalArgumentException("Id may not be null!"); //$NON-NLS-1$
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the id
|
||||||
|
*/
|
||||||
|
public Long getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the title
|
||||||
|
*/
|
||||||
|
public String getTitle() {
|
||||||
|
return this.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param title
|
||||||
|
* the title to set
|
||||||
|
*/
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the author
|
||||||
|
*/
|
||||||
|
public String getAuthor() {
|
||||||
|
return this.author;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param author
|
||||||
|
* the author to set
|
||||||
|
*/
|
||||||
|
public void setAuthor(String author) {
|
||||||
|
this.author = author;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the press
|
||||||
|
*/
|
||||||
|
public String getPress() {
|
||||||
|
return this.press;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param press
|
||||||
|
* the press to set
|
||||||
|
*/
|
||||||
|
public void setPress(String press) {
|
||||||
|
this.press = press;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the price
|
||||||
|
*/
|
||||||
|
public double getPrice() {
|
||||||
|
return this.price;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param price
|
||||||
|
* the price to set
|
||||||
|
*/
|
||||||
|
public void setPrice(double price) {
|
||||||
|
this.price = price;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.test.model;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
public class ModelBuilder {
|
||||||
|
|
||||||
|
public static final String RES_TYPE = "@subType";
|
||||||
|
public static final String RES_TYPE_INEXISTANT = "@inexistant";
|
||||||
|
public static final String RES_NAME = "@name";
|
||||||
|
public static final String RES_NAME_MODIFIED = "@name_modified";
|
||||||
|
public static final String RES_ID = "@id";
|
||||||
|
|
||||||
|
public static final String PARAM_TYPE = "@paramType";
|
||||||
|
public static final String PARAM_NAME = "@paramName";
|
||||||
|
public static final String PARAM_ID = "@paramId";
|
||||||
|
public static final String PARAM_VALUE_1 = "@paramValue1";
|
||||||
|
public static final String PARAM_VALUE_2 = "@paramValue2";
|
||||||
|
|
||||||
|
public static final long BOOK_ID = 10L;
|
||||||
|
public static final String BOOK_TITLE = "Nick Hornby";
|
||||||
|
public static final String BOOK_AUTHOR = "A long way down";
|
||||||
|
public static final String BOOK_PRESS_1 = "Some press";
|
||||||
|
public static final String BOOK_PRESS_2 = "Another press";
|
||||||
|
public static final double BOOK_PRICE = 45.55D;
|
||||||
|
|
||||||
|
public static MyModel createResource() {
|
||||||
|
return createResource(RES_ID, RES_NAME, RES_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MyModel createResource(String id) {
|
||||||
|
return createResource(id, RES_NAME, RES_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MyModel createResource(String id, String name, String type) {
|
||||||
|
MyModel resource = new MyModel(id, name, type);
|
||||||
|
MyParameter param = new MyParameter(PARAM_ID, PARAM_NAME, PARAM_TYPE, PARAM_VALUE_1);
|
||||||
|
resource.addParameter(param);
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updateResource(MyModel resource) {
|
||||||
|
resource.setName(RES_NAME_MODIFIED);
|
||||||
|
resource.getParameterBy(PARAM_ID).setValue(PARAM_VALUE_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Book createBook() {
|
||||||
|
Book book = new Book(BOOK_ID, BOOK_TITLE, BOOK_AUTHOR, BOOK_PRESS_1, BOOK_PRICE);
|
||||||
|
return book;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Book createBook(long id, String title, String author, String press, double price) {
|
||||||
|
Book book = new Book(id, title, author, press, price);
|
||||||
|
return book;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void updateBook(Book book) {
|
||||||
|
book.setPress(BOOK_PRESS_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assertBook(Book book) {
|
||||||
|
Assert.assertNotNull(book);
|
||||||
|
Assert.assertEquals(BOOK_ID, book.getId().longValue());
|
||||||
|
Assert.assertEquals(BOOK_TITLE, book.getTitle());
|
||||||
|
Assert.assertEquals(BOOK_AUTHOR, book.getAuthor());
|
||||||
|
Assert.assertEquals(BOOK_PRESS_1, book.getPress());
|
||||||
|
Assert.assertEquals(BOOK_PRICE, book.getPrice(), 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assertBookUpdated(Book book) {
|
||||||
|
Assert.assertNotNull(book);
|
||||||
|
Assert.assertEquals(BOOK_ID, book.getId().longValue());
|
||||||
|
Assert.assertEquals(BOOK_TITLE, book.getTitle());
|
||||||
|
Assert.assertEquals(BOOK_AUTHOR, book.getAuthor());
|
||||||
|
Assert.assertEquals(BOOK_PRESS_2, book.getPress());
|
||||||
|
Assert.assertEquals(BOOK_PRICE, book.getPrice(), 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assertResource(MyModel resource) {
|
||||||
|
Assert.assertNotNull(resource);
|
||||||
|
Assert.assertEquals(RES_ID, resource.getId());
|
||||||
|
Assert.assertEquals(RES_NAME, resource.getName());
|
||||||
|
Assert.assertEquals(RES_TYPE, resource.getType());
|
||||||
|
MyParameter param = resource.getParameterBy(PARAM_ID);
|
||||||
|
Assert.assertNotNull(param);
|
||||||
|
Assert.assertEquals(PARAM_ID, param.getId());
|
||||||
|
Assert.assertEquals(PARAM_NAME, param.getName());
|
||||||
|
Assert.assertEquals(PARAM_TYPE, param.getType());
|
||||||
|
Assert.assertEquals(PARAM_VALUE_1, param.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assertResourceUpdated(MyModel resource) {
|
||||||
|
Assert.assertNotNull(resource);
|
||||||
|
Assert.assertEquals(RES_ID, resource.getId());
|
||||||
|
Assert.assertEquals(RES_NAME_MODIFIED, resource.getName());
|
||||||
|
Assert.assertEquals(RES_TYPE, resource.getType());
|
||||||
|
MyParameter param = resource.getParameterBy(PARAM_ID);
|
||||||
|
Assert.assertNotNull(param);
|
||||||
|
Assert.assertEquals(PARAM_ID, param.getId());
|
||||||
|
Assert.assertEquals(PARAM_NAME, param.getName());
|
||||||
|
Assert.assertEquals(PARAM_TYPE, param.getType());
|
||||||
|
Assert.assertEquals(PARAM_VALUE_2, param.getValue());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,124 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.test.model;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class MyModel {
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
private String name;
|
||||||
|
private String type;
|
||||||
|
private Map<String, MyParameter> parameters = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public MyModel() {
|
||||||
|
// empty constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param id
|
||||||
|
* @param name
|
||||||
|
* @param type
|
||||||
|
*/
|
||||||
|
public MyModel(String id, String name, String type) {
|
||||||
|
super();
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append("Resource [id=");
|
||||||
|
builder.append(this.id);
|
||||||
|
builder.append(", name=");
|
||||||
|
builder.append(this.name);
|
||||||
|
builder.append(", type=");
|
||||||
|
builder.append(this.type);
|
||||||
|
builder.append(", parameters=");
|
||||||
|
for (Entry<String, MyParameter> param : this.parameters.entrySet()) {
|
||||||
|
builder.append("\n");
|
||||||
|
builder.append(" " + param.getKey() + " = " + param.getValue());
|
||||||
|
}
|
||||||
|
builder.append("]");
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the id
|
||||||
|
*/
|
||||||
|
public String getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param id
|
||||||
|
* the id to set
|
||||||
|
*/
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the name
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param name
|
||||||
|
* the name to set
|
||||||
|
*/
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the type
|
||||||
|
*/
|
||||||
|
public String getType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param type
|
||||||
|
* the type to set
|
||||||
|
*/
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addParameter(MyParameter parameter) {
|
||||||
|
this.parameters.put(parameter.getId(), parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getParameterKeySet() {
|
||||||
|
return this.parameters.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyParameter getParameterBy(String id) {
|
||||||
|
return this.parameters.get(id);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
|
||||||
|
*
|
||||||
|
* 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 ch.eitchnet.xmlpers.test.model;
|
||||||
|
|
||||||
|
public class MyParameter {
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
private String name;
|
||||||
|
private String type;
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public MyParameter() {
|
||||||
|
// empty constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param id
|
||||||
|
* @param name
|
||||||
|
* @param type
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public MyParameter(String id, String name, String type, String value) {
|
||||||
|
super();
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.type = type;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append("Parameter [id=");
|
||||||
|
builder.append(this.id);
|
||||||
|
builder.append(", name=");
|
||||||
|
builder.append(this.name);
|
||||||
|
builder.append(", type=");
|
||||||
|
builder.append(this.type);
|
||||||
|
builder.append(", value=");
|
||||||
|
builder.append(this.value);
|
||||||
|
builder.append("]");
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the id
|
||||||
|
*/
|
||||||
|
public String getId() {
|
||||||
|
return this.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param id
|
||||||
|
* the id to set
|
||||||
|
*/
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the name
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param name
|
||||||
|
* the name to set
|
||||||
|
*/
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the type
|
||||||
|
*/
|
||||||
|
public String getType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param type
|
||||||
|
* the type to set
|
||||||
|
*/
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the value
|
||||||
|
*/
|
||||||
|
public String getValue() {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param value
|
||||||
|
* the value to set
|
||||||
|
*/
|
||||||
|
public void setValue(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE log4j:configuration PUBLIC
|
||||||
|
"-//APACHE//DTD LOG4J 1.2//EN" "http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd">
|
||||||
|
<log4j:configuration debug="false" xmlns:log4j='http://jakarta.apache.org/log4j/'>
|
||||||
|
|
||||||
|
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
|
||||||
|
<layout class="org.apache.log4j.PatternLayout">
|
||||||
|
<param name="ConversionPattern" value="%d %5p [%t] %C{1} %M - %m%n" />
|
||||||
|
</layout>
|
||||||
|
</appender>
|
||||||
|
<appender name="FILE" class="org.apache.log4j.FileAppender">
|
||||||
|
<param name="File" value="sample.log"/>
|
||||||
|
<param name="BufferedIO" value="true" />
|
||||||
|
<param name="Append" value="true" />
|
||||||
|
<layout class="org.apache.log4j.PatternLayout">
|
||||||
|
<param name="ConversionPattern" value="%d %5p [%t] %C{1} %M - %m%n" />
|
||||||
|
</layout>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<logger name="ch.eitchnet">
|
||||||
|
<level value="INFO" />
|
||||||
|
</logger>
|
||||||
|
|
||||||
|
<root>
|
||||||
|
<priority value="INFO" />
|
||||||
|
<appender-ref ref="CONSOLE" />
|
||||||
|
<!-- appender-ref ref="FILE" / -->
|
||||||
|
</root>
|
||||||
|
|
||||||
|
</log4j:configuration>
|
Loading…
Reference in New Issue