summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPolina Genova2012-11-23 03:41:03 (EST)
committer Borislav Kapukaranov2012-11-23 04:05:12 (EST)
commitdcef081f01c65bb0d91262e33c068b7c0efe2b1d (patch)
treeb9733d86567a1e5b3a2262f08ac93ad083419320
parent29f6cb38d5c313ca55c0af55cd2d65d22089b063 (diff)
downloadorg.eclipse.virgo.nano-dcef081f01c65bb0d91262e33c068b7c0efe2b1d.zip
org.eclipse.virgo.nano-dcef081f01c65bb0d91262e33c068b7c0efe2b1d.tar.gz
org.eclipse.virgo.nano-dcef081f01c65bb0d91262e33c068b7c0efe2b1d.tar.bz2
394687 - Add utility class for easy handling of deployables' status files
-rw-r--r--org.eclipse.virgo.nano.deployer/src/main/java/org/eclipse/virgo/nano/deployer/util/StatusFileModificator.java177
-rw-r--r--org.eclipse.virgo.nano.deployer/src/test/java/org/eclipse/virgo/nano/deployer/util/StatusFileModificatorTest.java102
-rw-r--r--org.eclipse.virgo.nano.deployer/src/test/resources/test/testapp1.deploy.error2
-rw-r--r--org.eclipse.virgo.nano.deployer/src/test/resources/test/testapp1.deploy.ok2
-rw-r--r--org.eclipse.virgo.nano.deployer/src/test/resources/test/testapp1.undeploy.error2
-rw-r--r--org.eclipse.virgo.nano.deployer/src/test/resources/test/testapp1.undeploy.ok2
-rw-r--r--org.eclipse.virgo.nano.deployer/src/test/resources/test/testapp2.deploy.ok2
7 files changed, 289 insertions, 0 deletions
diff --git a/org.eclipse.virgo.nano.deployer/src/main/java/org/eclipse/virgo/nano/deployer/util/StatusFileModificator.java b/org.eclipse.virgo.nano.deployer/src/main/java/org/eclipse/virgo/nano/deployer/util/StatusFileModificator.java
new file mode 100644
index 0000000..a637dd7
--- /dev/null
+++ b/org.eclipse.virgo.nano.deployer/src/main/java/org/eclipse/virgo/nano/deployer/util/StatusFileModificator.java
@@ -0,0 +1,177 @@
+/*******************************************************************************
+ * Copyright (c) 2012 SAP AG
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * SAP AG - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.nano.deployer.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Properties;
+
+import org.eclipse.virgo.util.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The StatusFileModificator class should be used as a utility class to manipulate with deployable status files.
+ * Deployable status files are located in a '.state' folder created in the autodeployment folder (a.k.a the pickup
+ * folder).
+ * Status files names are constructed as follows: <deployable_name>.<operation>.<operation_status>, where
+ * deployable_name is the name of the deployable archive without the file extension (such as jar, war); operation - the
+ * operation which result is reported through the status file, possible values: deploy | undeploy; operation_status -
+ * status of the operation, possible values: ok | error;
+ * Status files include information about the bundleid and the lastmodified timestamp of the deployable archive.
+ * The latter can be used to check if there have been any offline updates of the deployable archive (while app server is stopped).
+ *
+ * Not Thread-safe.
+ */
+public class StatusFileModificator {
+
+ private static final char DOT = '.';
+
+ private static final char NEW_LINE = '\n';
+
+ public static final String SUCCESS_MARK = "ok";
+
+ public static final String ERROR_MARK = "error";
+
+ public static final String OP_DEPLOY = "deploy";
+
+ public static final String OP_UNDEPLOY = "undeploy";
+
+ private static final String STATE_DIR_NAME = ".state";
+
+ private static final String BUNDLE_ID_RECORD = "bundle-id";
+
+ private static final String LAST_MODIFIED = "last-modified";
+
+ private static final String DELIMITER = "=";
+
+ private static final String EMPTY_STRING = "";
+
+ private static final Logger logger = LoggerFactory.getLogger(StatusFileModificator.class);
+
+ private static final String[] STATUS_FILENAMES_SUFFEXES = { DOT + OP_DEPLOY + DOT + SUCCESS_MARK, DOT + OP_DEPLOY + DOT + ERROR_MARK,
+ DOT + OP_UNDEPLOY + DOT + SUCCESS_MARK, DOT + OP_UNDEPLOY + DOT + ERROR_MARK };
+
+ /**
+ * Deletes the current status file (if any) for the given deployable archive
+ */
+ public static void deleteStatusFile(String deployableName, File pickupDir) {
+ final File stateDir = new File(pickupDir, STATE_DIR_NAME);
+ if (stateDir.exists()) {
+ for (String fileNameSuffix : STATUS_FILENAMES_SUFFEXES) {
+ deleteFile(new File(stateDir, deployableName + fileNameSuffix));
+ }
+ } else {
+ if (logger.isInfoEnabled()) {
+ logger.info("State directory [" + stateDir.getAbsolutePath() + "] does not exist. Therefore, there is no status file to delete.");
+ }
+ }
+ }
+
+ /**
+ * Create status file about the given deplayable archive.
+ *
+ * @param deployableName - the name of the deplayable artifact
+ * @param pickupDir - auto deployment fodler where the deployable artifact is located. In this folder .state folder
+ * with the status file is created
+ * @param operation - operation for which status is recorded in status file (i.e. StatusFileModificator.OP_DEPLOY,
+ * StatusFileModificator.OP_UNDEPLOY)
+ * @param status - true if the operation was executed successfully
+ * @param bundleId - bundleId of the deployable archive
+ * @param lastModified - the deployable archive's latest lastmodified timestamp
+ */
+ public static void createStatusFile(String deployableName, File pickupDir, String operation, boolean status, long bundleId, long lastModified) {
+ final File stateDir = new File(pickupDir, STATE_DIR_NAME);
+ if (!stateDir.exists() && !stateDir.mkdirs()) {
+ logger.error("Cannot create state directory [" + stateDir.getAbsolutePath() + "]. Status file for the operation cannot be created.");
+ return;
+ }
+ final File statusFile = new File(stateDir, deployableName + DOT + operation + DOT + (status ? SUCCESS_MARK : ERROR_MARK));
+ writeStatusFileRecord(statusFile, bundleId, lastModified);
+ }
+
+ /**
+ * Returns the lastmodified timestamp if there is a successful status file for the given deployable archive.
+ * Otherwise -1 is returned.
+ *
+ * @param deployableName
+ * @param pickupDir
+ * @return
+ */
+ public static long getLastModifiedFromStatusFile(String deployableName, File pickupDir) {
+ final File stateDir = new File(pickupDir, STATE_DIR_NAME);
+ if (!stateDir.exists()) {
+ if (logger.isInfoEnabled()) {
+ logger.info("Checking if last stored state of [" + deployableName + "]." + "The state directory does not exist.");
+ }
+ return -1;
+ } else {
+ // there is no point to check lastmodified in case of other status files
+ File statusFile = new File(stateDir, deployableName + DOT + OP_DEPLOY + DOT + SUCCESS_MARK);
+ if (!statusFile.exists()) {
+ if (logger.isInfoEnabled()) {
+ logger.info("The status file [" + statusFile.getAbsolutePath() + "] does not exist.");
+ }
+ return -1;
+ }
+ Properties props = loadProperties(statusFile);
+ if (props != null) {
+ String lastModifiedStr = props.getProperty(LAST_MODIFIED);
+ if (lastModifiedStr != null && !EMPTY_STRING.equals(lastModifiedStr)) {
+ return Long.parseLong(lastModifiedStr);
+ }
+ }
+ }
+ return -1;
+ }
+
+ private static void writeStatusFileRecord(File statusFile, long bundleId, long lastModified) {
+ FileWriter fw = null;
+ try {
+ fw = new FileWriter(statusFile, true);
+ fw.write(BUNDLE_ID_RECORD + DELIMITER + bundleId);
+ fw.write(NEW_LINE);
+ fw.write(LAST_MODIFIED + DELIMITER + lastModified);
+ fw.write(NEW_LINE);
+ fw.flush();
+ } catch (IOException e) {
+ logger.error("Cannot update the status of operation.", e);
+ } finally {
+ IOUtils.closeQuietly(fw);
+ }
+ }
+
+ private static void deleteFile(File file) {
+ if (file.exists() && !file.delete()) {
+ logger.error("Cannot delete file [" + file.getAbsolutePath() + "].");
+ }
+ }
+
+ private static Properties loadProperties(File statusFile) {
+ Properties props = new Properties();
+ FileInputStream fis = null;
+ try {
+ fis = new FileInputStream(statusFile);
+ props.load(fis);
+ return props;
+ } catch (IOException e) {
+ if (logger.isInfoEnabled()) {
+ logger.info("Cannot load file with name [" + statusFile.getAbsolutePath() + "].", e);
+ }
+ return null;
+ } finally {
+ IOUtils.closeQuietly(fis);
+ }
+ }
+}
diff --git a/org.eclipse.virgo.nano.deployer/src/test/java/org/eclipse/virgo/nano/deployer/util/StatusFileModificatorTest.java b/org.eclipse.virgo.nano.deployer/src/test/java/org/eclipse/virgo/nano/deployer/util/StatusFileModificatorTest.java
new file mode 100644
index 0000000..6297c25
--- /dev/null
+++ b/org.eclipse.virgo.nano.deployer/src/test/java/org/eclipse/virgo/nano/deployer/util/StatusFileModificatorTest.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2012 SAP AG
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * SAP AG - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.virgo.nano.deployer.util;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+
+import org.eclipse.virgo.util.io.PathReference;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class StatusFileModificatorTest {
+
+ private static final PathReference PICKUP_DIR = new PathReference("target/pickup");
+
+ private static final PathReference STATE_DIR = new PathReference("target/pickup/.state");
+
+ private static final String[] dummyStatusFiles = { "src/test/resources/test/testapp1.deploy.ok", "src/test/resources/test/testapp1.undeploy.ok",
+ "src/test/resources/test/testapp1.deploy.error", "src/test/resources/test/testapp1.undeploy.error",
+ "src/test/resources/test/testapp2.deploy.ok" };
+
+ @Before
+ public void setUp() {
+ PICKUP_DIR.createDirectory();
+ }
+
+ @After
+ public void cleanUp() {
+ PICKUP_DIR.delete(true);
+ }
+
+ @Test
+ public void deleteStatusFileTest() throws Exception {
+ STATE_DIR.createDirectory();
+ copyDummyStatusFiles();
+ File stateFolder = STATE_DIR.toFile();
+ File pickupFolder = PICKUP_DIR.toFile();
+ assertTrue(stateFolder.list().length == 5);
+ StatusFileModificator.deleteStatusFile("testapp1", pickupFolder);
+ assertTrue(stateFolder.list().length == 1);
+ assertTrue("Only 'testapp2.deploy.ok' file should be in .state folder : ", stateFolder.list()[0].equals("testapp2.deploy.ok"));
+ StatusFileModificator.deleteStatusFile("testapp2", pickupFolder);
+ assertTrue(stateFolder.list().length == 0);
+ }
+
+ @Test
+ public void createStatusFileOkTest() throws Exception {
+ for (String st : new String[] { StatusFileModificator.OP_DEPLOY, StatusFileModificator.OP_UNDEPLOY }) {
+ StatusFileModificator.createStatusFile("testApp3", PICKUP_DIR.toFile(), st, true, 33, 123456789);
+ File stateDir = STATE_DIR.toFile();
+ assertTrue(stateDir.exists());
+ assertTrue("Invalid .state folder contents:", stateDir.list().length == 1 && stateDir.list()[0].equals("testApp3." + st + ".ok"));
+ StatusFileModificator.deleteStatusFile("testApp3", PICKUP_DIR.toFile());
+ }
+ }
+
+ @Test
+ public void createStatusFileErrorTest() throws Exception {
+ for (String st : new String[] { StatusFileModificator.OP_DEPLOY, StatusFileModificator.OP_UNDEPLOY }) {
+ StatusFileModificator.createStatusFile("testApp4", PICKUP_DIR.toFile(), st, false, 33, 123456789);
+ File stateDir = STATE_DIR.toFile();
+ assertTrue(stateDir.exists());
+ assertTrue("Invalid .state folder contents:", stateDir.list().length == 1 && stateDir.list()[0].equals("testApp4." + st + ".error"));
+ StatusFileModificator.deleteStatusFile("testApp4", PICKUP_DIR.toFile());
+ }
+ }
+
+ @Test
+ public void getLastModifiedFromStatusFileTest() throws Exception {
+ File pickupDir = PICKUP_DIR.toFile();
+ StatusFileModificator.createStatusFile("testApp5", pickupDir, StatusFileModificator.OP_UNDEPLOY, true, 33, 123456789);
+ assertTrue(StatusFileModificator.getLastModifiedFromStatusFile("testApp5", pickupDir) == -1);
+ StatusFileModificator.createStatusFile("testApp6", pickupDir, StatusFileModificator.OP_UNDEPLOY, false, 33, 123456789);
+ assertTrue(StatusFileModificator.getLastModifiedFromStatusFile("testApp6", pickupDir) == -1);
+ StatusFileModificator.createStatusFile("testApp7", pickupDir, StatusFileModificator.OP_DEPLOY, true, 33, 123456789);
+ assertTrue(StatusFileModificator.getLastModifiedFromStatusFile("testApp7", pickupDir) == 123456789);
+ StatusFileModificator.createStatusFile("testApp8", pickupDir, StatusFileModificator.OP_DEPLOY, false, 33, 123456789);
+ assertTrue(StatusFileModificator.getLastModifiedFromStatusFile("testApp8", pickupDir) == -1);
+ assertTrue(StatusFileModificator.getLastModifiedFromStatusFile("testApp9", pickupDir) == -1);
+ }
+
+ private void copyDummyStatusFiles() {
+ for (String dummyStatusFile : dummyStatusFiles) {
+ PathReference sourceFile = new PathReference(dummyStatusFile);
+ assertTrue(sourceFile.exists());
+ PathReference copy = sourceFile.copy(STATE_DIR);
+ assertTrue(copy.exists());
+ }
+ }
+
+} \ No newline at end of file
diff --git a/org.eclipse.virgo.nano.deployer/src/test/resources/test/testapp1.deploy.error b/org.eclipse.virgo.nano.deployer/src/test/resources/test/testapp1.deploy.error
new file mode 100644
index 0000000..6674615
--- /dev/null
+++ b/org.eclipse.virgo.nano.deployer/src/test/resources/test/testapp1.deploy.error
@@ -0,0 +1,2 @@
+bundle-id=197
+last-modified=1345737442754
diff --git a/org.eclipse.virgo.nano.deployer/src/test/resources/test/testapp1.deploy.ok b/org.eclipse.virgo.nano.deployer/src/test/resources/test/testapp1.deploy.ok
new file mode 100644
index 0000000..6674615
--- /dev/null
+++ b/org.eclipse.virgo.nano.deployer/src/test/resources/test/testapp1.deploy.ok
@@ -0,0 +1,2 @@
+bundle-id=197
+last-modified=1345737442754
diff --git a/org.eclipse.virgo.nano.deployer/src/test/resources/test/testapp1.undeploy.error b/org.eclipse.virgo.nano.deployer/src/test/resources/test/testapp1.undeploy.error
new file mode 100644
index 0000000..6674615
--- /dev/null
+++ b/org.eclipse.virgo.nano.deployer/src/test/resources/test/testapp1.undeploy.error
@@ -0,0 +1,2 @@
+bundle-id=197
+last-modified=1345737442754
diff --git a/org.eclipse.virgo.nano.deployer/src/test/resources/test/testapp1.undeploy.ok b/org.eclipse.virgo.nano.deployer/src/test/resources/test/testapp1.undeploy.ok
new file mode 100644
index 0000000..6674615
--- /dev/null
+++ b/org.eclipse.virgo.nano.deployer/src/test/resources/test/testapp1.undeploy.ok
@@ -0,0 +1,2 @@
+bundle-id=197
+last-modified=1345737442754
diff --git a/org.eclipse.virgo.nano.deployer/src/test/resources/test/testapp2.deploy.ok b/org.eclipse.virgo.nano.deployer/src/test/resources/test/testapp2.deploy.ok
new file mode 100644
index 0000000..6674615
--- /dev/null
+++ b/org.eclipse.virgo.nano.deployer/src/test/resources/test/testapp2.deploy.ok
@@ -0,0 +1,2 @@
+bundle-id=197
+last-modified=1345737442754