aboutsummaryrefslogtreecommitdiffstats
path: root/ncomp-utils-journaling
diff options
context:
space:
mode:
Diffstat (limited to 'ncomp-utils-journaling')
-rw-r--r--ncomp-utils-journaling/.classpath27
-rw-r--r--ncomp-utils-journaling/.gitignore1
-rw-r--r--ncomp-utils-journaling/.project44
-rw-r--r--ncomp-utils-journaling/.settings/org.eclipse.core.resources.prefs3
-rw-r--r--ncomp-utils-journaling/.settings/org.eclipse.jdt.core.prefs5
-rw-r--r--ncomp-utils-journaling/.settings/org.eclipse.m2e.core.prefs4
-rw-r--r--ncomp-utils-journaling/LICENSE.txt22
-rw-r--r--ncomp-utils-journaling/META-INF/MANIFEST.MF15
-rw-r--r--ncomp-utils-journaling/build.properties3
-rw-r--r--ncomp-utils-journaling/pom.xml162
-rw-r--r--ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingDateObject.java131
-rw-r--r--ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingEvent.java49
-rw-r--r--ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingHashMap.java243
-rw-r--r--ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingList.java303
-rw-r--r--ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingObject.java457
-rw-r--r--ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingTest.java255
16 files changed, 1724 insertions, 0 deletions
diff --git a/ncomp-utils-journaling/.classpath b/ncomp-utils-journaling/.classpath
new file mode 100644
index 0000000..79ccca7
--- /dev/null
+++ b/ncomp-utils-journaling/.classpath
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" output="target/classes" path="src/main/java">
+ <attributes>
+ <attribute name="optional" value="true"/>
+ <attribute name="maven.pomderived" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
+ <attributes>
+ <attribute name="maven.pomderived" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" output="target/test-classes" path="src/test/java">
+ <attributes>
+ <attribute name="optional" value="true"/>
+ <attribute name="maven.pomderived" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
+ <attributes>
+ <attribute name="maven.pomderived" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/ncomp-utils-journaling/.gitignore b/ncomp-utils-journaling/.gitignore
new file mode 100644
index 0000000..b83d222
--- /dev/null
+++ b/ncomp-utils-journaling/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/ncomp-utils-journaling/.project b/ncomp-utils-journaling/.project
new file mode 100644
index 0000000..ee0b752
--- /dev/null
+++ b/ncomp-utils-journaling/.project
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>ncomp-utils-journaling</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ </natures>
+</projectDescription>
diff --git a/ncomp-utils-journaling/.settings/org.eclipse.core.resources.prefs b/ncomp-utils-journaling/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..e9441bb
--- /dev/null
+++ b/ncomp-utils-journaling/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,3 @@
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding/<project>=UTF-8
diff --git a/ncomp-utils-journaling/.settings/org.eclipse.jdt.core.prefs b/ncomp-utils-journaling/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ec4300d
--- /dev/null
+++ b/ncomp-utils-journaling/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,5 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.7
diff --git a/ncomp-utils-journaling/.settings/org.eclipse.m2e.core.prefs b/ncomp-utils-journaling/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/ncomp-utils-journaling/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/ncomp-utils-journaling/LICENSE.txt b/ncomp-utils-journaling/LICENSE.txt
new file mode 100644
index 0000000..30471b5
--- /dev/null
+++ b/ncomp-utils-journaling/LICENSE.txt
@@ -0,0 +1,22 @@
+
+/*-
+ * ============LICENSE_START==========================================
+ * OPENECOMP - DCAE
+ * ===================================================================
+ * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ */
+
+ECOMP and OpenECOMP are trademarks and service marks of AT&T Intellectual Property.
diff --git a/ncomp-utils-journaling/META-INF/MANIFEST.MF b/ncomp-utils-journaling/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..e469752
--- /dev/null
+++ b/ncomp-utils-journaling/META-INF/MANIFEST.MF
@@ -0,0 +1,15 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: ncomp-utils-journaling
+Bundle-Version: 0.1.0.qualifier
+Export-Package: org.openecomp.ncomp.utils.journaling;uses:="org.apache.log4j,junit.framework,org.json"
+Require-Bundle: org.eclipse.emf.ecore;bundle-version="2.10.2",
+ org.eclipse.emf.ecore.xmi;bundle-version="2.10.2",
+ org.junit;bundle-version="4.11.0",
+ org.apache.log4j;bundle-version="1.2.15",
+ org.apache.commons.cli,
+ org.apache.commons.compress;bundle-version="1.6.0",
+ ncomp-utils-java;bundle-version="0.1.0"
+Bundle-Vendor: %providerName
+Bundle-RequiredExecutionEnvironment: JavaSE-1.7
diff --git a/ncomp-utils-journaling/build.properties b/ncomp-utils-journaling/build.properties
new file mode 100644
index 0000000..a1ec8c4
--- /dev/null
+++ b/ncomp-utils-journaling/build.properties
@@ -0,0 +1,3 @@
+source.. = src/main/java/
+bin.includes = META-INF/,\
+ .
diff --git a/ncomp-utils-journaling/pom.xml b/ncomp-utils-journaling/pom.xml
new file mode 100644
index 0000000..250a7e2
--- /dev/null
+++ b/ncomp-utils-journaling/pom.xml
@@ -0,0 +1,162 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.openecomp.ncomp.utils</groupId>
+ <artifactId>ncomp-utils-journaling</artifactId>
+ <version>0.1.0-SNAPSHOT</version>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <maven.compiler.target>1.7</maven.compiler.target>
+ <maven.compiler.source>1.7</maven.compiler.source>
+ </properties>
+
+
+ <pluginRepositories>
+ <!-- Black Duck plugin dependencies -->
+ <pluginRepository>
+ <id>JCenter</id>
+ <name>JCenter Repository</name>
+ <url>http://jcenter.bintray.com</url>
+ </pluginRepository>
+
+ <pluginRepository>
+ <id>Restlet</id>
+ <name>Restlet Repository</name>
+ <url>http://maven.restlet.com</url>
+ </pluginRepository>
+ </pluginRepositories>
+<build>
+ <plugins>
+ <!-- blackduck maven plugin -->
+ <plugin>
+ <groupId>com.blackducksoftware.integration</groupId>
+ <artifactId>hub-maven-plugin</artifactId>
+ <version>1.4.0</version>
+ <inherited>false</inherited>
+ <configuration>
+ <hubProjectName>${project.name}</hubProjectName>
+ <outputDirectory>${project.basedir}</outputDirectory>
+ </configuration>
+ <executions>
+ <execution>
+ <id>create-bdio-file</id>
+ <phase>package</phase>
+ <goals>
+ <goal>createHubOutput</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <!-- site maven plugin -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-site-plugin</artifactId>
+ <version>3.6</version>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven.wagon</groupId>
+ <artifactId>wagon-webdav-jackrabbit</artifactId>
+ <version>2.10</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.1</version>
+ <configuration>
+ <source />
+ <target />
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.17</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.11</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-compress</artifactId>
+ <version>1.9</version>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-cli</groupId>
+ <artifactId>commons-cli</artifactId>
+ <version>1.3</version>
+ </dependency>
+
+
+ <dependency>
+ <groupId>org.eclipse.emf</groupId>
+ <artifactId>org.eclipse.emf.ecore</artifactId>
+ <version>2.11.0-v20150123-0347</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.emf</groupId>
+ <artifactId>org.eclipse.emf.common</artifactId>
+ <version>2.11.0-v20150123-0347</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.emf</groupId>
+ <artifactId>org.eclipse.emf.ecore.xmi</artifactId>
+ <version>2.11.0-v20150123-0347</version>
+ </dependency>
+ <dependency>
+ <groupId>org.openecomp.ncomp.utils</groupId>
+ <artifactId>ncomp-utils-java</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+
+ <distributionManagement>
+ <repository>
+ <id>osecomp-nexus-releases</id>
+ <name>OSECOMP Release Repository</name>
+ <url>${openecomp.nexus.releases}</url>
+ </repository>
+ <snapshotRepository>
+ <id>osecomp-nexus-snapshots</id>
+ <name>OSECOMP Snapshot Repository</name>
+ <url>${openecomp.nexus.snapshots}</url>
+ </snapshotRepository>
+ <site>
+ <id>dcae-javadoc</id>
+ <url>${site.urlroot}/${project.artifactId}/${project.version}/</url>
+ </site>
+ </distributionManagement>
+
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.10.4</version>
+ <configuration>
+ <failOnError>false</failOnError>
+ <doclet>org.umlgraph.doclet.UmlGraphDoc</doclet>
+ <docletArtifact>
+ <groupId>org.umlgraph</groupId>
+ <artifactId>umlgraph</artifactId>
+ <version>5.6</version>
+ </docletArtifact>
+ <additionalparam>-views</additionalparam>
+ <useStandardDocletOptions>true</useStandardDocletOptions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
+
+</project>
diff --git a/ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingDateObject.java b/ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingDateObject.java
new file mode 100644
index 0000000..466e671
--- /dev/null
+++ b/ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingDateObject.java
@@ -0,0 +1,131 @@
+
+/*-
+ * ============LICENSE_START==========================================
+ * OPENECOMP - DCAE
+ * ===================================================================
+ * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ */
+
+package org.openecomp.ncomp.utils.journaling;
+
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.json.JSONObject;
+
+public class JournalingDateObject<T extends JournalingObject> {
+ public static final Logger logger = Logger
+ .getLogger(JournalingDateObject.class);
+ private String rootDir;
+ private HashMap<Date, T> map = new HashMap<Date, T>();
+ private HashMap<Date, Date> createdTime = new HashMap<Date, Date>();
+ @SuppressWarnings("rawtypes")
+ private Class clazz;
+
+ @SuppressWarnings("rawtypes")
+ public JournalingDateObject(String filePrefix, Class clazz) {
+ this.rootDir = filePrefix;
+ this.clazz = clazz;
+ }
+
+ public T get(Date d) {
+ return getPmap(d);
+ }
+
+ public void save() {
+ synchronized (this) {
+ for (Date d : map.keySet()) {
+ map.get(d).save();
+ }
+ Date now = new Date();
+ List<Date> l = new ArrayList<Date>();
+ for (Date d : map.keySet()) {
+ if (createdTime.get(d).getTime() + msInDay < now.getTime()) {
+ // created 1 day ago. remove from map to save memory
+ l.add(d);
+ }
+ }
+ for (Date d : l) {
+ map.remove(d);
+ createdTime.remove(d);
+ }
+ }
+ }
+
+ public void close() {
+ save();
+ for (Date d : map.keySet()) {
+ map.get(d).close();
+ }
+ }
+
+ private final long msInDay = 86400000L;
+
+ @SuppressWarnings("unchecked")
+ private T getPmap(Date d) {
+ synchronized (this) {
+ Date d1 = new Date(d.getTime() / msInDay * msInDay);
+ T o = map.get(d1);
+ if (o == null) {
+ try {
+ @SuppressWarnings("rawtypes")
+ Constructor c = clazz.getConstructor();
+ Method m = clazz.getMethod("create", File.class);
+ o = (T) m.invoke(c.newInstance(), dbRootDir(d1));
+ map.put(d1, o);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ createdTime.put(d1, new Date());
+ }
+ return o;
+ }
+ }
+
+ private File dbRootDir(Date d) {
+ return new File(rootDir + String.format("/%1$tY_%1$tm_%1$td", d));
+ }
+
+ public void dump() {
+ synchronized (this) {
+ for (Date d : map.keySet()) {
+ T o = map.get(d);
+ System.out.println("Status for: " + d + " " + o);
+ }
+ }
+ }
+
+ public JSONObject toJson() {
+ synchronized (this) {
+ JSONObject json = new JSONObject();
+ for (Date d : map.keySet()) {
+ JSONObject json1 = new JSONObject();
+ json1.put("createdTime", createdTime.get(d));
+ json1.put("object", map.get(d).toJson());
+ json.put(d.toString(), json1);
+ }
+ return json;
+ }
+ }
+
+}
diff --git a/ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingEvent.java b/ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingEvent.java
new file mode 100644
index 0000000..cdf3224
--- /dev/null
+++ b/ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingEvent.java
@@ -0,0 +1,49 @@
+
+/*-
+ * ============LICENSE_START==========================================
+ * OPENECOMP - DCAE
+ * ===================================================================
+ * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ */
+
+package org.openecomp.ncomp.utils.journaling;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+public class JournalingEvent implements Serializable {
+ @Override
+ public String toString() {
+ return "JournalingEvent [context=" + context + ", o=" + value + ", method=" + method + "]";
+ }
+ private static final long serialVersionUID = -7697839584139633393L;
+ List<String> context = new ArrayList<String>();
+ Object value = null;
+ int method = -1;
+ public String pname;
+ public JournalingEvent() {}
+ public JournalingEvent(String context, int method, String pname, Object o) {
+ if (context != null)
+ this.context.add(context);
+ this.value = o;
+ this.method = method;
+ this.pname = pname;
+ }
+ public void addContext(JournalingObject journalingObject) {
+ context.add(journalingObject.getContext());
+ }
+}
diff --git a/ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingHashMap.java b/ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingHashMap.java
new file mode 100644
index 0000000..3fab2ec
--- /dev/null
+++ b/ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingHashMap.java
@@ -0,0 +1,243 @@
+
+/*-
+ * ============LICENSE_START==========================================
+ * OPENECOMP - DCAE
+ * ===================================================================
+ * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ */
+
+package org.openecomp.ncomp.utils.journaling;
+
+import java.io.File;
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.json.JSONObject;
+
+public class JournalingHashMap<V> extends JournalingObject implements Map<String, V>, Serializable {
+ @Override
+ public String toString() {
+ return "JournalingHashMap [map=" + map + "]";
+ }
+
+ private static final long serialVersionUID = 1L;
+ private HashMap<String, V> map;
+ static final int REMOVE_METHOD = 2000;
+ static final int PUT_METHOD = 2001;
+ static final int CLEAR_METHOD = 2002;
+ static final int NEWKEY_METHOD = 2003;
+
+ @SuppressWarnings("rawtypes")
+ public static JournalingHashMap create(File dir) {
+ return (JournalingHashMap) create2(dir, new JournalingHashMap());
+ }
+
+ public JournalingHashMap(String context, JournalingObject parent) {
+ super(context, parent);
+ }
+
+ public JournalingHashMap() {
+ // TODO Auto-generated constructor stub
+ }
+
+ @Override
+ public void init() {
+ if (map == null)
+ map = new HashMap<String, V>();
+ else {
+ for (String k : map.keySet()) {
+ V o = map.get(k);
+ if (o instanceof JournalingObject) {
+ JournalingObject oo = (JournalingObject) o;
+ initChild(k, oo);
+ }
+ }
+ }
+
+ }
+ @SuppressWarnings("unchecked")
+ void play(JournalingEvent e, int index) {
+ if (index == 0) {
+ switch (e.method) {
+ case REMOVE_METHOD: {
+ remove(e.pname);
+ return;
+ }
+ case PUT_METHOD: {
+ put(e.pname, (V) e.value);
+ return;
+ }
+ case CLEAR_METHOD: {
+ clear();
+ return;
+ }
+ case NEWKEY_METHOD: {
+ try {
+ newKey(e.pname, (Class<V>) Class.forName((String) e.value));
+ } catch (ClassNotFoundException e1) {
+ throw new RuntimeException("Unexpected class: " + e.method);
+ }
+ return;
+ }
+ default:
+ logger.debug("Unexpected method: " + e.method);
+ return;
+ }
+ }
+ String context = e.context.get(index - 1);
+ V c = map.get(context);
+ if (c == null) {
+ throw new RuntimeException("Unknown key: " + context + " not in " + map.keySet());
+ }
+ JournalingObject cc = (JournalingObject) c;
+ cc.play(e, index - 1);
+ }
+
+ public V newKey(String key, Class<V> clazz) {
+ return newKey2(key, clazz);
+ }
+
+ public V newList(String key) {
+ return newKey2(key, JournalingList.class);
+ }
+
+ public V newMap(String key) {
+ return newKey2(key, JournalingHashMap.class);
+ }
+
+ private V newKey2(String key, @SuppressWarnings("rawtypes") Class clazz) {
+ try {
+ if (clazz.getName().contains("$"))
+ throw new RuntimeException("Cannot be an inner class: " + clazz.getName());
+ @SuppressWarnings("unchecked")
+ Constructor<V> m = clazz.getConstructor(String.class, JournalingObject.class);
+ V v = m.newInstance(key, this);
+ log(new JournalingEvent(null, NEWKEY_METHOD, key, clazz.getName()));
+ map.put(key, v);
+ return v;
+ } catch (Exception e) {
+ throw new RuntimeException("Unable to create new " + clazz.getName() + " " + e);
+ }
+ }
+
+ protected String eventToString(JournalingEvent e) {
+ switch (e.method) {
+ case REMOVE_METHOD:
+ return "map:remove " + e.context + " " + e.pname;
+ case PUT_METHOD:
+ return "map:put " + e.context + " " + e.pname + " " + e.value;
+ case CLEAR_METHOD:
+ return "map:put " + e.context;
+ case NEWKEY_METHOD:
+ return "map:new " + e.context + " key=" + e.pname + " " + e.value;
+ default:
+ return "map:def " + e.context + " key=" + e.pname + " value=" + e.value;
+ }
+ }
+
+ // //////////////////// Standard Map Method //////////////////////////////
+ @Override
+ public void clear() {
+ log(new JournalingEvent(null, CLEAR_METHOD, null, null));
+ map.clear();
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ return map.containsKey(key);
+ }
+
+ @Override
+ public boolean containsValue(Object value) {
+ return map.containsKey(value);
+ }
+
+ @Override
+ public Set<java.util.Map.Entry<String, V>> entrySet() {
+ return map.entrySet();
+ }
+
+ @Override
+ public V get(Object key) {
+ return map.get(key);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return map.isEmpty();
+ }
+
+ @Override
+ public Set<String> keySet() {
+ return map.keySet();
+ }
+
+ @Override
+ public V put(String key, V value) {
+ if (value instanceof JournalingObject) {
+ throw new RuntimeException("Use newkey method instead of put for values of type JournalingObject");
+ }
+ log(new JournalingEvent(null, PUT_METHOD, key, value));
+ return map.put(key, value);
+ }
+
+ @Override
+ public void putAll(Map<? extends String, ? extends V> m) {
+ for (String k : m.keySet()) {
+ map.put(k, m.get(k));
+ }
+ }
+
+ @Override
+ public V remove(Object key) {
+ if (key == null || key instanceof String) {
+ String k = (String) key;
+ log(new JournalingEvent(null, REMOVE_METHOD, k, null));
+ return map.remove(key);
+ }
+ return null;
+ }
+
+ @Override
+ public int size() {
+ return map.size();
+ }
+
+ @Override
+ public Collection<V> values() {
+ return map.values();
+ }
+
+ public JSONObject toJson() {
+ JSONObject json = new JSONObject();
+ for (String k : map.keySet()) {
+ Object o = map.get(k);
+ if (o instanceof JournalingObject) {
+ JournalingObject o1 = (JournalingObject) o;
+ json.put(k, o1.toJson());
+ }
+ else {
+ json.put(k, o.toString());
+ }
+ }
+ return json;
+ }
+
+}
diff --git a/ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingList.java b/ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingList.java
new file mode 100644
index 0000000..e40f842
--- /dev/null
+++ b/ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingList.java
@@ -0,0 +1,303 @@
+
+/*-
+ * ============LICENSE_START==========================================
+ * OPENECOMP - DCAE
+ * ===================================================================
+ * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ */
+
+package org.openecomp.ncomp.utils.journaling;
+
+import java.io.File;
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+public class JournalingList<V> extends JournalingObject implements List<V>, Serializable {
+ @Override
+ public String toString() {
+ return "JournalingList [list=" + list + "]";
+ }
+
+ private static final long serialVersionUID = 1L;
+ private List<V> list;
+ static final int ADD_METHOD = 1001;
+ static final int CLEAR_METHOD = 1002;
+ static final int ADDNEW_METHOD = 1003;
+ static final int REMOVE_METHOD = 1004;
+
+
+ @SuppressWarnings("rawtypes")
+ static public JournalingList create(File dir) {
+ return (JournalingList) create2(dir,new JournalingList());
+ }
+
+ public JournalingList(String context, JournalingObject parent) {
+ super(context,parent);
+ }
+ public JournalingList() {
+ // TODO Auto-generated constructor stub
+ }
+
+ @Override
+ public void init() {
+ if (list == null)
+ list = new ArrayList<V>();
+ else {
+ int i = 0;
+ for (V o : list) {
+ if (o instanceof JournalingObject) {
+ JournalingObject oo = (JournalingObject) o;
+ String key = Integer.toString(i++);
+ initChild(key, oo);
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ void play(JournalingEvent e,int index) {
+ if (index == 0) {
+ switch (e.method) {
+ case ADD_METHOD: {
+ add((V) e.value);
+ return;
+ }
+ case CLEAR_METHOD: {
+ clear();
+ return;
+ }
+ case ADDNEW_METHOD: {
+ try {
+ addNew((Class<V>) Class.forName((String) e.value));
+ } catch (ClassNotFoundException e1) {
+ throw new RuntimeException("Unexpected class: " + e.method);
+ }
+ return;
+ }
+ case REMOVE_METHOD: {
+ remove((int)(Integer)e.value);
+ return;
+ }
+ default:
+ logger.debug("Unexpected method: " + e.method);
+ return;
+ }
+ }
+ String context = e.context.get(index-1);
+ int i = Integer.parseInt(context);
+ V c = list.get(i);
+ if (c == null) {
+ throw new RuntimeException("unknown list error");
+ }
+ JournalingObject cc = (JournalingObject) c;
+ cc.play(e, index-1);
+ }
+ protected String eventToString(JournalingEvent e) {
+ switch (e.method) {
+ case REMOVE_METHOD:
+ return "list:remove " + e.context + " " + e.value;
+ case ADD_METHOD:
+ return "list:add " + e.context + " " + e.value;
+ case CLEAR_METHOD:
+ return "list:clear " + e.context;
+ case ADDNEW_METHOD:
+ return "list:new " + e.context + " key=" + e.value;
+ default:
+ return "list:def " + e.context + " key=" + e.pname + " value=" + e.value;
+ }
+ }
+
+ public V addNew(Class<V> clazz) {
+ return addNew2(clazz);
+ }
+ public V newList(String key) {
+ return addNew2(JournalingList.class);
+ }
+ public V newMap() {
+ return addNew2(JournalingHashMap.class);
+ }
+ private V addNew2(@SuppressWarnings("rawtypes") Class clazz) {
+ try {
+ if (clazz.getName().contains("$"))
+ throw new RuntimeException("Cannot be an inner class: " + clazz.getName());
+ @SuppressWarnings("unchecked")
+ Constructor<V> m = clazz.getConstructor(String.class,JournalingObject.class);
+ String key = Integer.toString(list.size());
+ V v = m.newInstance(key, this);
+ log(new JournalingEvent(null, ADDNEW_METHOD, null, clazz.getName()));
+ list.add(v);
+ return v;
+ } catch (Exception e) {
+ throw new RuntimeException("Unable to create new " + clazz.getName() + " " + e);
+ }
+ }
+
+ ////////////////////// Standard List Method //////////////////////////////
+
+ @Override
+ public boolean add(V v) {
+ if (v instanceof JournalingObject) {
+ throw new RuntimeException("Use newkey method instead of put for values of type JournalingObject");
+ }
+ log(new JournalingEvent(null, ADD_METHOD, null, v));
+ return list.add(v);
+ }
+
+ @Override
+ public void add(int arg0, V arg1) {
+ throw new RuntimeException("not implemented");
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends V> l) {
+ for (V v: l) {
+ if (!add(v)) return false;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean addAll(int arg0, Collection<? extends V> arg1) {
+ throw new RuntimeException("not implemented");
+ }
+
+ @Override
+ public void clear() {
+ log(new JournalingEvent(null, CLEAR_METHOD, null, null));
+ list.clear();
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ return list.contains(o);
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> l) {
+ // TODO Auto-generated method stub
+ return list.containsAll(l);
+ }
+
+ @Override
+ public V get(int index) {
+ return list.get(index);
+ }
+
+ @Override
+ public int indexOf(Object o) {
+ return indexOf(o);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return list.isEmpty();
+ }
+
+ @Override
+ public Iterator<V> iterator() {
+ return list.iterator();
+ }
+
+ @Override
+ public int lastIndexOf(Object o) {
+ return list.lastIndexOf(o);
+ }
+
+ @Override
+ public ListIterator<V> listIterator() {
+ return listIterator();
+ }
+
+ @Override
+ public ListIterator<V> listIterator(int i) {
+ return listIterator(i);
+ }
+
+ @Override
+ public boolean remove(Object arg0) {
+ throw new RuntimeException("not implemented");
+ }
+
+ @Override
+ public V remove(int i) {
+ log(new JournalingEvent(null, REMOVE_METHOD, null, (Integer) i));
+ return list.remove(i);
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> arg0) {
+ throw new RuntimeException("not implemented");
+ }
+
+ @Override
+ public boolean retainAll(Collection<?> arg0) {
+ throw new RuntimeException("not implemented");
+ }
+
+ @Override
+ public V set(int arg0, V arg1) {
+ throw new RuntimeException("not implemented");
+ }
+
+ @Override
+ public int size() {
+ return list.size();
+ }
+
+ @Override
+ public List<V> subList(int arg0, int arg1) {
+ throw new RuntimeException("not implemented");
+ }
+
+ @Override
+ public Object[] toArray() {
+ return list.toArray();
+ }
+
+ @Override
+ public <T> T[] toArray(T[] a) {
+ return list.toArray(a);
+ }
+
+
+
+ public JSONObject toJson() {
+ JSONObject json = new JSONObject();
+ JSONArray a = new JSONArray();
+ json.put("array", a);
+ for (V o : list) {
+ if (o instanceof JournalingObject) {
+ JournalingObject o1 = (JournalingObject) o;
+ a.put(o1.toJson());
+ }
+ else {
+ a.put(o.toString());
+ }
+ }
+ return json;
+ }
+
+
+}
diff --git a/ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingObject.java b/ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingObject.java
new file mode 100644
index 0000000..d294aa7
--- /dev/null
+++ b/ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingObject.java
@@ -0,0 +1,457 @@
+
+/*-
+ * ============LICENSE_START==========================================
+ * OPENECOMP - DCAE
+ * ===================================================================
+ * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ */
+
+package org.openecomp.ncomp.utils.journaling;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.StreamCorruptedException;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.GnuParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.OptionBuilder;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.log4j.Logger;
+import org.json.JSONObject;
+
+import org.openecomp.ncomp.webservice.utils.FileUtils;
+
+public abstract class JournalingObject {
+ public static final Logger logger = Logger.getLogger(JournalingObject.class);
+ static final int SET_METHOD = 0;
+ static final int SAVE_METHOD = -999;
+ protected HashMap<String, JournalingObject> children = new HashMap<String, JournalingObject>();
+ private JournalingObject parent = null;
+ private String context;
+ private File dir;
+ private ObjectOutputStream jStream;
+
+ private List<JournalingEvent> playList = new ArrayList<JournalingEvent>();
+ private int snapShotInterval = 30 * 60000; // every 30 minutes
+ private Date lastSnapShot = new Date();
+ private int numLogs = 0;
+
+ static {
+ startCleanupThread();
+ }
+
+ public JournalingObject(String context, JournalingObject parent) {
+ setSnapshotInterval(snapShotInterval);
+ this.parent = parent;
+ this.context = context;
+ if (parent.children.get(context) != null)
+ throw new RuntimeException("dublicate child");
+ parent.children.put(context, this);
+ init();
+ }
+
+ public JournalingObject() {
+ }
+
+ public abstract void init();
+
+ static protected JournalingObject create2(File dir, JournalingObject o) {
+ if (dir.exists() && !dir.isDirectory())
+ throw new RuntimeException("journaling directory exists but is not a directory");
+ if (!dir.exists())
+ dir.mkdirs();
+ logger.info("creating journaling data structure: " + o.getClass().getName() + " " + dir);
+ File logFile = saveObjectFile(dir, "log.dat");
+ File snapshotFile = FileUtils.createSafeFile(dir, "snapshot.dat");
+ if (snapshotFile.exists()) {
+ JournalingObject oo = initFromSnapshot(snapshotFile);
+ if (oo != null) {
+ o = oo;
+ }
+ }
+ o.init(); // setup object
+ o.jStream = getObjectFile(dir, "log.dat");
+ o.dir = dir;
+ if (logFile != null) {
+ o.initFromLog(logFile);
+ logger.info("initialized from file: " + logFile);
+ o.save();
+ }
+ addCleanupDirectory(dir);
+ return o;
+ }
+
+ protected void initChild(String context, JournalingObject child) {
+ children.put(context, child);
+ child.parent = this;
+ child.context = context;
+ child.init();
+ }
+
+ public synchronized void log(JournalingEvent event) {
+ if (parent != null) {
+ event.addContext(this);
+ parent.log(event);
+ return;
+ }
+ try {
+ if (logger.isDebugEnabled())
+ logger.debug("log " + eventToString(event));
+ jStream.writeUnshared(event);
+ numLogs++;
+ if (event.context.size() == 0 && event.method == SAVE_METHOD) {
+ jStream.flush();
+ if (lastSnapShot.getTime() + snapShotInterval < new Date().getTime() && numLogs > 100) {
+ createSnapshot();
+ }
+ }
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ public void logAttributeValue(String arg, Object value) {
+ log(new JournalingEvent(null, SET_METHOD, arg, value));
+ }
+
+ public void save() {
+ if (parent != null) {
+ throw new RuntimeException("Can only save on the toplevel object");
+ }
+ log(new JournalingEvent(null, SAVE_METHOD, null, null));
+ try {
+ if (jStream != null)
+ jStream.reset();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void close() {
+ try {
+ jStream.close();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ public String getContext() {
+ return context;
+ }
+
+ private void play(JournalingEvent e) {
+ // System.out.println("play: " + e);
+ if (logger.isDebugEnabled())
+ logger.debug("play: " + eventToString(e));
+ if (e.context.size() == 0 && e.method == SAVE_METHOD) {
+ for (JournalingEvent e1 : playList) {
+ play(e1, e1.context.size());
+ }
+ playList.clear();
+ } else
+ playList.add(e);
+ }
+
+ void play(JournalingEvent e, int index) {
+ if (index == 0) {
+ switch (e.method) {
+ case SET_METHOD: {
+ try {
+ Field fld = this.getClass().getDeclaredField(e.pname);
+ fld.setAccessible(true);
+ logAttributeValue(e.pname, e.value);
+ fld.set(this, e.value);
+ } catch (Exception e1) {
+ // TODO Auto-generated catch block
+ logger.error("Unable to set attribute: " + this.getClass().getName() + " " + e1);
+ logger.debug("Unable to set attribute: " + e.pname + " " + this.getClass().getName() + " " + e1);
+ }
+ return;
+ }
+ default:
+ throw new RuntimeException("Unexpected method: " + e.method);
+ }
+ }
+ String context = e.context.get(index - 1);
+ JournalingObject c = children.get(context);
+ if (c == null) {
+ throw new RuntimeException("Unknown Child: " + context + " not in " + children.keySet());
+ }
+ c.play(e, index - 1);
+ }
+
+ protected String eventToString(JournalingEvent e) {
+ switch (e.method) {
+ case SET_METHOD:
+ return "object:method context=" + e.context + " key=" + e.pname + " value=" + e.value;
+ default:
+ return e.toString();
+ }
+ }
+
+ void createSnapshot() {
+ Date now = new Date();
+ String fName = "snapshot.dat";
+ String tName = fName + "." + now.getTime();
+ logger.debug("create snapshot:" + fName + " " + this);
+ try {
+ ObjectOutputStream out = getObjectFile(dir, tName);
+ try {
+ out.writeObject(this);
+ } finally {
+ out.close();
+ }
+ File f = FileUtils.createSafeFile(dir, fName);
+ File t = FileUtils.createSafeFile(dir, tName);
+ if (f.exists()) {
+ f.delete();
+ }
+ if (!t.renameTo(f)) {
+ throw new RuntimeException("Unable to rename file:" + f);
+ }
+ jStream.close();
+ saveObjectFile(dir, "log.dat", now);
+ jStream = getObjectFile(dir, "log.dat");
+ numLogs = 0;
+ lastSnapShot = new Date();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ private static JournalingObject initFromSnapshot(File file) {
+ try {
+ logger.debug("reading" + file);
+ BufferedInputStream fin = new BufferedInputStream(new FileInputStream(file),16777216);
+ ObjectInputStream in = new ObjectInputStream(fin);
+ Object o = null;
+ try {
+ o = in.readObject();
+ } finally {
+ in.close();
+ }
+ return (JournalingObject) o;
+ } catch (Exception e) {
+ logger.error("Unable to init from snapshot file: " + file + " " + e);
+ if (logger.isDebugEnabled())
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public void setSnapshotInterval(int i) {
+ snapShotInterval = i;
+ lastSnapShot = new Date();
+ // make sure snapshots time are randomized and not happening at the same time.
+ lastSnapShot.setTime(lastSnapShot.getTime()-(long) (i*Math.random()));
+ }
+
+ public int getLogSize() {
+ return numLogs;
+ }
+
+ @SuppressWarnings("static-access")
+ public static void main(String[] args) throws IOException, ClassNotFoundException {
+ CommandLineParser parser = new GnuParser();
+
+ // create the Options
+ Options options = new Options();
+ options.addOption("h", "help", false, "Show usage");
+ options.addOption(OptionBuilder.withLongOpt("file").withArgName("fileName").hasArg().create('f'));
+ // Handle inputs
+ CommandLine line = null;
+ try {
+ line = parser.parse(options, args);
+ } catch (ParseException e) {
+ }
+ if (line == null || line.hasOption("help") || line.hasOption("h")) {
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp("util", options);
+ return;
+ }
+ // String args1[] = line.getArgs();
+ if (line.hasOption("file")) {
+ FileInputStream fin = new FileInputStream(new File(line.getOptionValue("file")));
+ ObjectInputStream in = new ObjectInputStream(fin);
+ try {
+ while (true) {
+ Object o;
+ try {
+ o = in.readUnshared();
+ if (o instanceof JournalingEvent) {
+ JournalingEvent e = (JournalingEvent) o;
+ System.out.println(e.toString());
+ continue;
+ }
+ System.out.println(o.toString());
+ } catch (EOFException e) {
+ break;
+ }
+ }
+ } finally {
+ in.close();
+ }
+ }
+ }
+
+ static int num = 0;
+
+ static private File saveObjectFile(File dir, String fname) {
+ return saveObjectFile(dir, fname, new Date());
+ }
+
+ static private File saveObjectFile(File dir, String fname, Date now) {
+ String fname2 = fname + "." + now.getTime() + "." + num++;
+ File f1 = FileUtils.createSafeFile(dir, fname);
+ File f2 = FileUtils.createSafeFile(dir, fname2);
+ if (f1.exists()) {
+ if (f2.exists()) {
+ f2.delete();
+ }
+ if (!f1.renameTo(f2)) {
+ throw new RuntimeException("Unable to rename file: " + f2);
+ }
+ return f2;
+ }
+ return null;
+ }
+
+ static private ObjectOutputStream getObjectFile(File dir, String fname) {
+ File f1 = FileUtils.createSafeFile(dir, fname);
+ ObjectOutputStream s = null;
+ try {
+ s = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(f1)));
+ } catch (Exception e) {
+ throw new RuntimeException("unknown error: " + e);
+ }
+ return s;
+ }
+
+ private void initFromLog(File file) {
+ int numEvents = 0;
+ Object o = null;
+ try {
+ FileInputStream fin = new FileInputStream(file);
+ ObjectInputStream in = new ObjectInputStream(fin);
+ try {
+ while (true) {
+ try {
+ o = in.readUnshared();
+ // logger.info("new object: " + o);
+ numEvents++;
+ if (o instanceof JournalingEvent) {
+ JournalingEvent e = (JournalingEvent) o;
+ play(e);
+ }
+ if (o == null) {
+ logger.warn("read null object from: " + file);
+ }
+ } catch (EOFException e1) {
+ break;
+ } catch (StreamCorruptedException e1) {
+ break;
+ }
+ }
+ } finally {
+ if (in != null)
+ in.close();
+ if (fin != null)
+ fin.close();
+ }
+ playList.clear();
+ } catch (EOFException e) {
+ logger.debug("initFromLog failed: " + file + " numEvents=" + numEvents + " o=" + o);
+ } catch (Exception e) {
+ logger.warn("initFromLog failed: " + file + " numEvents=" + numEvents + " o=" + o.getClass());
+ logger.debug("initFromLog failed: " + file + " numEvents=" + numEvents + " o=" + o);
+ e.printStackTrace();
+ }
+ }
+
+ public JSONObject toJson() {
+ JSONObject json = new JSONObject();
+ for (String k : children.keySet()) {
+ json.put(k, children.get(k).toJson());
+ }
+ return json;
+ }
+
+ // Cleanup old files
+ static List<File> cleanupDirectories = new ArrayList<File>();
+ private static void startCleanupThread() {
+ Thread t = new Thread("journaling cleanup") {
+ public void run() {
+ while (true) {
+ try {
+ cleanup();
+ Thread.sleep(300000);
+ } catch (Exception e) {
+ e.printStackTrace();
+ logger.error(e);
+ }
+ }
+ }
+
+ };
+ t.setDaemon(true);
+ t.start();
+ }
+ private static void cleanup() {
+ List<File> l = new ArrayList<File>();
+ synchronized (cleanupDirectories) {
+ l.addAll(cleanupDirectories);
+ }
+ Date now = new Date();
+ for (File dir : l) {
+ if (!dir.exists() || ! dir.isDirectory()) {
+ synchronized (cleanupDirectories) {
+ logger.warn("removing bad journaling directory" + dir.getAbsolutePath());
+ cleanupDirectories.remove(dir);
+ continue;
+ }
+ }
+ for (File f : dir.listFiles()) {
+ // ignore file that is recently changed
+ if (f.lastModified() + 3600000 > now.getTime()) continue;
+ if (f.getName().startsWith("log.dat."))
+ f.delete();
+ }
+ }
+ }
+ private static void addCleanupDirectory(File dir) {
+ synchronized (cleanupDirectories) {
+ cleanupDirectories.add(dir);
+ }
+ }
+}
diff --git a/ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingTest.java b/ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingTest.java
new file mode 100644
index 0000000..a1e7517
--- /dev/null
+++ b/ncomp-utils-journaling/src/main/java/org/openecomp/ncomp/utils/journaling/JournalingTest.java
@@ -0,0 +1,255 @@
+
+/*-
+ * ============LICENSE_START==========================================
+ * OPENECOMP - DCAE
+ * ===================================================================
+ * Copyright (c) 2017 AT&T Intellectual Property. All rights reserved.
+ * ===================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ */
+
+package org.openecomp.ncomp.utils.journaling;
+
+import java.io.File;
+import java.io.Serializable;
+
+import junit.framework.TestCase;
+
+public class JournalingTest extends TestCase {
+ private static File clean(File f) {
+ if (f.isDirectory()) {
+ for (File x: f.listFiles()) {
+ clean(x);
+ }
+ }
+ f.delete();
+ return(f);
+ }
+ @SuppressWarnings("unchecked")
+ public void test_case1() {
+ File f = clean(new File("testdata/journal/case1"));
+ JournalingHashMap<String> m = JournalingHashMap.create(f);
+ m.put("foo", "bar");
+ m.save();
+ m.close();
+ for (int i = 0; i < 3; i++) {
+ // overwrite object with new. Can test that it has the correct
+ // state.
+ m = JournalingHashMap.create(f);
+ assertEquals("bar", m.get("foo"));
+ m.close();
+ }
+ }
+
+ public void test_case2() {
+ File f = clean(new File("testdata/journal/case2"));
+ MyTestJObject o = MyTestJObject.create(f);
+ o.setS("foo");
+ o.setS("foo2");
+ o.m.put("a", "b");
+ o.l.add("foo1");
+ o.l.add("foo2");
+ o.l.add("foo3");
+ o.l.remove(0);
+ o.save();
+ o.setS("bar");
+ o.close();
+ for (int i = 0; i < 3; i++) {
+ o = MyTestJObject.create(f);
+ assertEquals("foo2", o.getS());
+ assertEquals("b", o.m.get("a"));
+ assertEquals("foo2", o.l.get(0));
+ o.close();
+ }
+ }
+
+ public void test_case3() {
+ File f = clean(new File("testdata/journal/case3"));
+ MyTestJObject2 o = MyTestJObject2.create(f);
+ o.setS("foo");
+ // hashmap
+ MyTestJObject oo = o.m.newKey("x", MyTestJObject.class);
+ oo.m.put("a", "b");
+ oo.setS("jjj");
+ // list
+ MyTestJObject ooo = o.l.addNew(MyTestJObject.class);
+ ooo = o.l.addNew(MyTestJObject.class);
+ ooo.m.put("aa", "bb");
+ ooo.setS("kkk");
+ // hashmaplist
+ JournalingList<MyTestJObject> x = o.ml.newList("x");
+ MyTestJObject xx = x.addNew(MyTestJObject.class);
+ xx.m.put("aa", "bb");
+ xx.setS("kkk");
+ o.save();
+ o.setS("bar");
+ o.close();
+ for (int i = 0; i < 3; i++) {
+ // System.out.println("Round: " + i);
+ o = MyTestJObject2.create(f);
+ oo = o.m.get("x");
+ assertEquals("foo", o.getS());
+ assertEquals("jjj", oo.getS());
+ assertEquals("b", oo.m.get("a"));
+ assertEquals(2, o.l.size());
+ ooo = o.l.get(1);
+ assertEquals("kkk", ooo.getS());
+ assertEquals("bb", ooo.m.get("aa"));
+ assertEquals(0, o.l.get(0).m.size());
+ xx = o.ml.get("x").get(0);
+ assertEquals("kkk", xx.getS());
+ assertEquals("bb", xx.m.get("aa"));
+ assertEquals(0, o.l.get(0).m.size());
+
+ o.close();
+ }
+ }
+
+ public void test_case4() {
+ File f = clean(new File("testdata/journal/case4"));
+ MyTestJObject o = MyTestJObject.create(f);
+ // o.setSnapshotInterval(1); // 1ms snapshots. This should force
+ // snapshots on each save.
+ o.setS("foo:1");
+ o.setS("foo:2");
+ o.save();
+ // assertEquals(2,o.getLogSize());
+ o.createSnapshot();
+ // assertEquals(0,o.getLogSize());
+ o.setS("foo:3");
+ o.save();
+ o.createSnapshot();
+ o.l.add("foo1");
+ o.save();
+ o.close();
+
+ for (int i = 0; i < 3; i++) {
+ o = MyTestJObject.create(f);
+ System.out.println("Round: " + i + " " + o);
+ assertEquals("foo:3", o.getS());
+ assertEquals("foo1", o.l.get(0));
+ o.close();
+ }
+ }
+
+ public void test_case5() {
+ File f = clean(new File("testdata/journal/case5"));
+ MyTestJObject2 o = MyTestJObject2.create(f);
+ // o.setSnapshotInterval(1); // 1ms snapshots. This should force
+ // snapshots on each save.
+ o.setS("foo");
+ o.save();
+ for (int i = 0; i < 10; i++) {
+ o.setS("foo:" + i);
+ }
+ assertTrue(o.getLogSize() <= 2);
+ o.close();
+
+ for (int i = 0; i < 3; i++) {
+ o = MyTestJObject2.create(f);
+ System.out.println("Round: " + i + " " + o);
+ assertEquals("foo", o.getS());
+ o.close();
+ }
+ }
+}
+
+class MyTestJObject extends JournalingObject implements Serializable {
+ @Override
+ public String toString() {
+ return "MyTestJObject [s=" + s + ", m=" + m + ", l=" + l + "]";
+ }
+
+ private static final long serialVersionUID = 1L;
+ private String s;
+ JournalingHashMap<String> m;
+ JournalingList<String> l;
+
+ public MyTestJObject(String context, JournalingObject parent) {
+ super(context, parent);
+ }
+
+ public MyTestJObject() {
+ // TODO Auto-generated constructor stub
+ }
+
+ public String getS() {
+ return s;
+ }
+
+ public void setS(String str) {
+ logAttributeValue("s", str);
+ this.s = str;
+ }
+
+ @Override
+ public void init() {
+ if (m == null)
+ m = new JournalingHashMap<String>("m", this);
+ else
+ initChild("m", m);
+ if (l == null)
+ l = new JournalingList<String>("l", this);
+ else
+ initChild("l", l);
+ }
+
+ static public MyTestJObject create(File dir) {
+ return (MyTestJObject) create2(dir, new MyTestJObject());
+ }
+}
+
+class MyTestJObject2 extends JournalingObject implements Serializable {
+ @Override
+ public String toString() {
+ return "MyTestJObject2 [s=" + s + ", m=" + m + ", l=" + l + ", ml="
+ + ml + "]";
+ }
+
+ private static final long serialVersionUID = 1L;
+ private String s;
+ JournalingHashMap<MyTestJObject> m;
+ JournalingList<MyTestJObject> l;
+ JournalingHashMap<JournalingList<MyTestJObject>> ml;
+
+ public String getS() {
+ return s;
+ }
+
+ public void setS(String str) {
+ logAttributeValue("s", str);
+ this.s = str;
+ }
+
+ @Override
+ public void init() {
+ if (m == null)
+ m = new JournalingHashMap<MyTestJObject>("m", this);
+ else
+ initChild("m", m);
+ if (l == null)
+ l = new JournalingList<MyTestJObject>("l", this);
+ else
+ initChild("l", l);
+ if (ml == null)
+ ml = new JournalingHashMap<JournalingList<MyTestJObject>>("ml", this);
+ else
+ initChild("ml", ml);
+ }
+
+ static public MyTestJObject2 create(File dir) {
+ return (MyTestJObject2) create2(dir, new MyTestJObject2());
+ }
+
+}