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