You are viewing a plain text version of this content. The canonical link for it is here.
Posted to kalumet-commits@incubator.apache.org by jb...@apache.org on 2011/10/29 09:37:45 UTC

svn commit: r1194852 [1/3] - in /incubator/kalumet/trunk: ./ agent/ agent/src/main/java/org/apache/kalumet/agent/updater/

Author: jbonofre
Date: Sat Oct 29 09:37:44 2011
New Revision: 1194852

URL: http://svn.apache.org/viewvc?rev=1194852&view=rev
Log:
Add new updaters.

Added:
    incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/ArchiveUpdater.java
    incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/ConfigurationFileUpdater.java
    incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/ContentManagerUpdater.java
    incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/DatabaseUpdater.java
    incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/J2EEApplicationServerUpdater.java
    incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/J2EEApplicationUpdater.java
    incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/JDBCConnectionPoolUpdater.java
    incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/JDBCDataSourceUpdater.java
    incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/JMSConnectionFactoryUpdater.java
Modified:
    incubator/kalumet/trunk/agent/pom.xml
    incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/SoftwareUpdater.java
    incubator/kalumet/trunk/pom.xml

Modified: incubator/kalumet/trunk/agent/pom.xml
URL: http://svn.apache.org/viewvc/incubator/kalumet/trunk/agent/pom.xml?rev=1194852&r1=1194851&r2=1194852&view=diff
==============================================================================
--- incubator/kalumet/trunk/agent/pom.xml (original)
+++ incubator/kalumet/trunk/agent/pom.xml Sat Oct 29 09:37:44 2011
@@ -50,6 +50,10 @@
             <artifactId>org.apache.kalumet.common</artifactId>
         </dependency>
         <dependency>
+            <groupId>org.apache.kalumet.controller</groupId>
+            <artifactId>org.apache.kalumet.controller.core</artifactId>
+        </dependency>
+        <dependency>
             <groupId>org.apache.kalumet</groupId>
             <artifactId>org.apache.kalumet.utils</artifactId>
         </dependency>

Added: incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/ArchiveUpdater.java
URL: http://svn.apache.org/viewvc/incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/ArchiveUpdater.java?rev=1194852&view=auto
==============================================================================
--- incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/ArchiveUpdater.java (added)
+++ incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/ArchiveUpdater.java Sat Oct 29 09:37:44 2011
@@ -0,0 +1,372 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.kalumet.agent.updater;
+
+import org.apache.kalumet.FileManipulator;
+import org.apache.kalumet.FileManipulatorException;
+import org.apache.kalumet.KalumetException;
+import org.apache.kalumet.agent.Configuration;
+import org.apache.kalumet.agent.utils.EventUtils;
+import org.apache.kalumet.controller.core.J2EEApplicationServerController;
+import org.apache.kalumet.controller.core.J2EEApplicationServerControllerFactory;
+import org.apache.kalumet.model.*;
+import org.apache.kalumet.model.update.UpdateLog;
+import org.apache.kalumet.model.update.UpdateMessage;
+import org.apache.kalumet.utils.NotifierUtils;
+import org.apache.kalumet.utils.PublisherUtils;
+import org.apache.kalumet.utils.VariableUtils;
+import org.apache.kalumet.ws.client.ArchiveClient;
+import org.apache.kalumet.ws.client.ClientException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * J2EE application archive updater.
+ */
+public class ArchiveUpdater {
+
+    private static final transient Logger LOGGER = LoggerFactory.getLogger(ArchiveUpdater.class);
+
+    /**
+     * Wrapper method to update J2EE application archive.
+     *
+     * @param environmentName the target environment name.
+     * @param serverName      the target J2EE application server name.
+     * @param applicationName the target J2EE application name.
+     * @param archiveName     the target archive name.
+     * @param delegation      flag indicating if the update is a delegation from another agent (true), or a client call (false).
+     * @throws UpdateException in case of update failure.
+     */
+    public static void update(String environmentName, String serverName, String applicationName, String archiveName, boolean delegation) throws KalumetException {
+        LOGGER.info("Archive {} update requested by WS", archiveName);
+
+        // load configuration.
+        LOGGER.debug("Loading configuration");
+        Kalumet kalumet = Kalumet.digeste(Configuration.CONFIG_LOCATION);
+        Environment environment = kalumet.getEnvironment(environmentName);
+        if (environment == null) {
+            LOGGER.error("Environment {} is not found in the configuration", environmentName);
+            throw new KalumetException("Environment " + environmentName + " is not found in the configuration");
+        }
+        J2EEApplicationServer server = environment.getJ2EEApplicationServers().getJ2EEApplicationServer(serverName);
+        if (server == null) {
+            LOGGER.error("J2EE application server {} is not found in environment {}", serverName, environmentName);
+            throw new KalumetException("J2EE application server " + serverName + " is not found in environment " + environmentName);
+        }
+        J2EEApplication application = server.getJ2EEApplication(applicationName);
+        if (application == null) {
+            LOGGER.error("J2EE application {} is not found in J2EE application server {}", applicationName, serverName);
+            throw new KalumetException("J2EE application " + applicationName + " is not found in J2EE application server " + serverName);
+        }
+        Archive archive = application.getArchive(archiveName);
+        if (archive == null) {
+            LOGGER.error("Archive {} is not found in J2EE application {}", archiveName, applicationName);
+            throw new KalumetException("Archive " + archiveName + " is not found in J2EE application " + applicationName);
+        }
+
+        // update configuration cache
+        LOGGER.debug("Updating configuration cache");
+        Configuration.CONFIG_CACHE = kalumet;
+
+        // post journal event
+        EventUtils.post(environment, "UPDATE", "Archive " + archiveName + " update requested by WS");
+        // create an update logger
+        UpdateLog updateLog = new UpdateLog("Archive " + archiveName + " update in progress ...", environment.getName(), environment);
+
+        if (!delegation) {
+            // the update is a client call
+            LOGGER.info("Send a notification and waiting for the count down");
+            EventUtils.post(environment, "UPDATE", "Send a notification and waiting for the count down");
+            NotifierUtils.waitAndNotify(environment);
+        }
+
+        try {
+            // call the updater method
+            ArchiveUpdater.update(environment, server, application, archive, updateLog);
+        } catch (Exception e) {
+            LOGGER.error("Archive {} update failed", archiveName, e);
+            EventUtils.post(environment, "ERROR", "Archive " + archiveName + " update failed: " + e.getMessage());
+            if (!delegation) {
+                updateLog.setStatus("Archive " + archiveName + " update failed");
+                updateLog.addUpdateMessage(new UpdateMessage("error", "Archive " + archiveName + " update failed: " + e.getMessage()));
+                LOGGER.info("Publishing update report");
+                PublisherUtils.publish(environment);
+            }
+            throw new UpdateException("Archive " + archiveName + " update failed", e);
+        }
+
+        // update completed
+        LOGGER.info("Archive {} updated", archive.getName());
+        EventUtils.post(environment, "UPDATE", "Archive " + archive.getName() + " updated");
+
+        if (!delegation) {
+            if (updateLog.isUpdated()) {
+                updateLog.setStatus("Archive " + archive.getName() + " updated");
+            } else {
+                updateLog.setStatus("Archive " + archive.getName() + " already up to date");
+            }
+            updateLog.addUpdateMessage(new UpdateMessage("info", "Archive " + archive.getName() + " updated"));
+            LOGGER.info("Publishing update report");
+            PublisherUtils.publish(environment);
+        }
+    }
+
+    /**
+     * Updates a archive.
+     *
+     * @param environment the target <code>Environment</code>.
+     * @param server      the target <code>J2EEApplicationServer</code>.
+     * @param application the target JZEE <code>Application</code>.
+     * @param archive     the target <code>Archive</code>.
+     * @param updateLog   the <code>UpdateLog</code> to use.
+     */
+    public static void update(Environment environment, J2EEApplicationServer server, J2EEApplication application, Archive archive, UpdateLog updateLog) throws UpdateException {
+        LOGGER.info("Updating archive {}", archive.getName());
+        updateLog.addUpdateMessage(new UpdateMessage("info", "Updating archive " + archive.getName()));
+        EventUtils.post(environment, "UPDATE", "Updating archive " + archive.getName());
+
+        if (!archive.isActive()) {
+            LOGGER.info("Archive {} is inactive, so not updated", archive.getName());
+            updateLog.addUpdateMessage(new UpdateMessage("info", "Archive " + archive.getName() + " is inactive, so not updated"));
+            EventUtils.post(environment, "UPDATE", "Archive " + archive.getName() + " is inactive, so not updated");
+            return;
+        }
+
+        // check to delegate the update
+        if (archive.getAgent() != null && archive.getAgent().trim().length() > 0 && !archive.getAgent().equals(Configuration.AGENT_ID)) {
+            LOGGER.info("Delegating archive {} update to agent {}", archive.getName(), archive.getAgent());
+            EventUtils.post(environment, "UPDATE", "Delegating archive " + archive.getName() + " update to agent " + archive.getAgent());
+            updateLog.addUpdateMessage(new UpdateMessage("info", "Delegating archive " + archive.getName() + " update to agent " + archive.getAgent()));
+            Agent delegationAgent = Configuration.CONFIG_CACHE.getAgent(archive.getAgent());
+            if (delegationAgent == null) {
+                LOGGER.error("Agent {} is not found in the configuration", archive.getAgent());
+                throw new UpdateException("Agent " + archive.getAgent() + " is not found in the configuration");
+            }
+            try {
+                LOGGER.debug("Call archive WS");
+                ArchiveClient client = new ArchiveClient(delegationAgent.getHostname(), delegationAgent.getPort());
+                client.update(environment.getName(), server.getName(), application.getName(), archive.getName(), true);
+            } catch (ClientException clientException) {
+                LOGGER.error("Archive " + archive.getName() + " update failed", clientException);
+                throw new UpdateException("Archive " + archive.getName() + " update failed", clientException);
+            }
+            return;
+        }
+
+        // construct the archiveUri
+        String archiveUri = VariableUtils.replace(archive.getUri(), environment.getVariables());
+        if (!FileManipulator.protocolExists(archiveUri)) {
+            // the archive URI is relative (no prefix protocol), use the
+            // application URI to construct the VFS URI
+            LOGGER.debug("Archive URI is relative (no protocol prefix) to J2EE application URI");
+            archiveUri = FileManipulator.format(VariableUtils.replace(application.getUri(), environment.getVariables())) + "!/" + archiveUri;
+        }
+        // get the application cache directory
+        String applicationCacheDir = null;
+        // initialize the file manipulator instance
+        FileManipulator fileManipulator = null;
+        try {
+            applicationCacheDir = FileManipulator.createJ2EEApplicationCacheDir(environment, application);
+            fileManipulator = FileManipulator.getInstance();
+        } catch (FileManipulatorException e) {
+            LOGGER.error("Can't create J2EE application {} cache directory", application.getName(), e);
+            throw new UpdateException("Can't create J2EE application " + application.getName() + " cache directory", e);
+        }
+        // define the archive cache location
+        String archiveCache = applicationCacheDir + "/" + archive.getName();
+        // define the archive installation URI
+        String archiveInstallation = null;
+        if (archive.getPath() == null || archive.getPath().trim().length() < 1) {
+            LOGGER.error("Archive {} path is not defined", archive.getName());
+            throw new UpdateException("Archive " + archive.getName() + " path is not defined");
+        }
+        // the archive path is defined, use it
+        archiveInstallation = VariableUtils.replace(archive.getPath(), environment.getVariables());
+        // get the J2EE application server controller
+        LOGGER.debug("Getting the J2EE application server controller");
+        J2EEApplicationServerController controller = null;
+        try {
+            controller = J2EEApplicationServerControllerFactory.getController(environment, server);
+        } catch (KalumetException e) {
+            LOGGER.error("Can't get the J2EE application server {} controller", server.getName(), e);
+            throw new UpdateException("Can't get the J2EE application server " + server.getName() + " controller", e);
+        }
+        // check if the archive is already deployed
+        try {
+            if (controller.isJ2EEApplicationDeployed(archiveInstallation, archive.getName())) {
+                // the archive is already deployed, check for update
+                LOGGER.info("Archive {} is already deployed, check for update", archive.getName());
+                updateLog.addUpdateMessage(new UpdateMessage("info", "Archive " + archive.getName() + " is already deployed, check for update"));
+                EventUtils.post(environment, "UPDATE", "Archive " + archive.getName() + " is already deployed, check for update");
+                if (!fileManipulator.checksumEquals(archiveUri, archiveCache)) {
+                    // the archive file is different from the copy in the
+                    // application directory, perform an update
+                    // update the cache
+                    fileManipulator.copy(archiveUri, archiveCache);
+                    LOGGER.info("Archive {} (located {}) is different from the cache, performing update", archive.getName(), archiveUri);
+                    updateLog.addUpdateMessage(new UpdateMessage("info", "Archive " + archive.getName() + " (located " + archiveUri + ") is different from the cache, performing update"));
+                    EventUtils.post(environment, "UPDATE", "Archive " + archive.getName() + " (located " + archiveUri + ") is different from the cache, performing update");
+                    updateLog.addUpdateMessage(new UpdateMessage("info", "Copy " + archiveUri + " to " + archiveInstallation));
+                    EventUtils.post(environment, "UPDATE", "Copy " + archiveUri + " to " + archiveInstallation);
+                    // update the archive path
+                    fileManipulator.copy(archiveUri, archiveInstallation);
+                    // undeploy the archive
+                    LOGGER.info("Undeploying archive {}", archive.getName());
+                    updateLog.addUpdateMessage(new UpdateMessage("info", "Undeploying archive " + archive.getName()));
+                    EventUtils.post(environment, "UPDATE", "Undeploying archive " + archive.getName());
+                    controller.undeployJ2EEApplication(archiveInstallation, archive.getName());
+                    // deploy the archive
+                    LOGGER.info("Deploying archive {}", archive.getName());
+                    updateLog.addUpdateMessage(new UpdateMessage("info", "Deploying archive " + archive.getName()));
+                    EventUtils.post(environment, "UPDATE", "Deploying archive " + archive.getName());
+                    controller.deployJ2EEApplication(archiveInstallation, archive.getName(), archive.getClassloaderorder(), archive.getClassloaderpolicy(), VariableUtils.replace(archive.getVhost(), environment.getVariables()));
+                    LOGGER.info("Archive {} updated", archive.getName());
+                    updateLog.addUpdateMessage(new UpdateMessage("info", "Archive " + archive.getName() + " updated"));
+                    EventUtils.post(environment, "UPDATE", "Archive " + archive.getName() + " updated");
+                    updateLog.setUpdated(true);
+                }
+            } else {
+                // the archive is not deployed
+                LOGGER.info("Archive {} is not deployed, deploying it", archive.getName());
+                updateLog.addUpdateMessage(new UpdateMessage("info", "Archive " + archive.getName() + " is not deployed, deploying it"));
+                EventUtils.post(environment, "UPDATE", "Archive " + archive.getName() + " is not deployed, deploying it");
+                // copy the archive agent locally
+                fileManipulator.copy(archiveUri, archiveCache);
+                // copy the archive to the destination path
+                fileManipulator.copy(archiveUri, archiveInstallation);
+                // deploy the archive
+                LOGGER.info("Deploying archive {}", archive.getName());
+                updateLog.addUpdateMessage(new UpdateMessage("info", "Deploying archive " + archive.getName()));
+                EventUtils.post(environment, "UPDATE", "Deploying archive " + archive.getName());
+                controller.deployJ2EEApplication(archiveInstallation, archive.getName(), archive.getClassloaderorder(), archive.getClassloaderpolicy(), VariableUtils.replace(archive.getVhost(), environment.getVariables()));
+                updateLog.setUpdated(true);
+            }
+            // as some J2EE application server (like IBM WebSphere) change the archive file during deployment, update
+            // the local archive with a original copy (for next update)
+            LOGGER.debug("Restoring the original archive (before deployment) from {}", archiveUri);
+            fileManipulator.copy(archiveUri, archiveCache);
+            // check if the J2EE application is deployed (it should be)
+            if (!controller.isJ2EEApplicationDeployed(archiveInstallation, archive.getName())) {
+                LOGGER.error("Archive {} is not deployed whereas it should be. Please check the J2EE application server logs", archive.getName());
+                throw new UpdateException("Archive " + archive.getName() + " is not deployed whereas it should be. Please check the J2EE application server logs");
+            }
+        } catch (Exception e) {
+            // the archive update has failed
+            LOGGER.error("Archive {} update failed", archive.getName(), e);
+            try {
+                fileManipulator.delete(archiveCache);
+            } catch (FileManipulatorException fileManipulatorException) {
+                LOGGER.warn("Can't delete " + archiveCache, fileManipulatorException);
+            }
+            throw new UpdateException("Archive " + archive.getName() + " update failed", e);
+        }
+    }
+
+    /**
+     * Wrapper method to check if a archive is up to date or not via WS.
+     *
+     * @param environmentName the target environment name.
+     * @param serverName      the target J2EE application server name.
+     * @param applicationName the target J2EE application name.
+     * @param archiveName     the target archive name.
+     * @return true if the archive is up to date, false else.
+     * @throws KalumetException in case of status check failure
+     */
+    public static boolean check(String environmentName, String serverName, String applicationName, String archiveName) throws KalumetException {
+        LOGGER.info("Checking status of archive {} via WS", archiveName);
+        // load configuration
+        LOGGER.debug("Load configuration");
+        Kalumet kalumet = Kalumet.digeste(Configuration.CONFIG_LOCATION);
+        Environment environment = kalumet.getEnvironment(environmentName);
+        if (environment == null) {
+            LOGGER.error("Environment {} is not found in the configuration", environmentName);
+            throw new KalumetException("Environment " + environmentName + " is not found in the configuration");
+        }
+        J2EEApplicationServer applicationServer = environment.getJ2EEApplicationServers().getJ2EEApplicationServer(serverName);
+        if (applicationServer == null) {
+            LOGGER.error("J2EE application server {} is not found in environment {}", serverName, environmentName);
+            throw new KalumetException("J2EE application server " + serverName + " is not found in environment " + environmentName);
+        }
+        J2EEApplication application = applicationServer.getJ2EEApplication(applicationName);
+        if (application == null) {
+            LOGGER.error("J2EE application {} is not found in J2EE application server {}", applicationName, serverName);
+            throw new KalumetException("J2EE application " + applicationName + " is not found in J2EE application server " + serverName);
+        }
+        Archive archive = application.getArchive(archiveName);
+        if (archive == null) {
+            LOGGER.error("Archive {} is not found in J2EE application {}", archiveName, applicationName);
+            throw new KalumetException("Archive " + archiveName + " is not found in J2EE application " + applicationName);
+        }
+
+        // check if the check should be delegated to another agent
+        if (archive.getAgent() != null && archive.getAgent().trim().length() > 0 && !archive.getAgent().equals(Configuration.AGENT_ID)) {
+            // the check needs to be delegated to another agent
+            LOGGER.info("Delegating archive {} status check to agent {}", archive.getName(), archive.getAgent());
+            Agent agentDelegation = kalumet.getAgent(archive.getAgent());
+            if (agentDelegation == null) {
+                LOGGER.error("Agent {} is not found in the configuration", archive.getName());
+                throw new KalumetException("Agent " + archive.getAgent() + " is not found in the configuration");
+            }
+            // call the service
+            ArchiveClient client = new ArchiveClient(agentDelegation.getHostname(), agentDelegation.getPort());
+            return client.check(environmentName, serverName, applicationName, archiveName);
+        }
+
+        // initialize file manipulator
+        LOGGER.debug("Initializing file manipulator");
+        FileManipulator fileManipulator = FileManipulator.getInstance();
+
+        // get J2EE application server controller
+        LOGGER.debug("Getting J2EE application server controller");
+        J2EEApplicationServerController controller = J2EEApplicationServerControllerFactory.getController(environment, applicationServer);
+
+        // get application cache directory
+        LOGGER.debug("Getting application cache directory");
+        String applicationCacheDirectory = FileManipulator.createJ2EEApplicationCacheDir(environment, application);
+
+        // construct the archive URI
+        String archiveUri = VariableUtils.replace(archive.getUri(), environment.getVariables());
+        if (!FileManipulator.protocolExists(archiveUri)) {
+            // the archive URI is relative (doesn't contain the protocol prefix), construct the URI using the application URI
+            archiveUri = VariableUtils.replace(application.getUri(), environment.getVariables()) + "!/" + archiveUri;
+        }
+
+        // get the archive cache
+        String archiveCache = applicationCacheDirectory + "/" + archive.getName();
+
+        // get the archive installation path
+        if (archive.getPath() == null || archive.getPath().trim().length() < 1) {
+            LOGGER.error("Archive {} path is not defined", archive.getName());
+            throw new KalumetException("Archive " + archive.getName() + " path is not defined");
+        }
+        String archiveInstallation = VariableUtils.replace(archive.getPath(), environment.getVariables());
+
+        if (controller.isJ2EEApplicationDeployed(archiveInstallation, archive.getName())) {
+            // check if the archive is deployed or not
+            if (fileManipulator.checksumEquals(archiveUri, archiveCache)) {
+                // archive URI and cache are the same
+                LOGGER.debug("Archive URI and agent cache are the same");
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+}

Added: incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/ConfigurationFileUpdater.java
URL: http://svn.apache.org/viewvc/incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/ConfigurationFileUpdater.java?rev=1194852&view=auto
==============================================================================
--- incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/ConfigurationFileUpdater.java (added)
+++ incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/ConfigurationFileUpdater.java Sat Oct 29 09:37:44 2011
@@ -0,0 +1,328 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.kalumet.agent.updater;
+
+import org.apache.kalumet.FileManipulator;
+import org.apache.kalumet.FileManipulatorException;
+import org.apache.kalumet.KalumetException;
+import org.apache.kalumet.agent.Configuration;
+import org.apache.kalumet.agent.utils.EventUtils;
+import org.apache.kalumet.model.*;
+import org.apache.kalumet.model.update.UpdateLog;
+import org.apache.kalumet.model.update.UpdateMessage;
+import org.apache.kalumet.utils.NotifierUtils;
+import org.apache.kalumet.utils.PublisherUtils;
+import org.apache.kalumet.utils.VariableUtils;
+import org.apache.kalumet.ws.client.ClientException;
+import org.apache.kalumet.ws.client.ConfigurationFileClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Iterator;
+
+/**
+ * J2EE application configuration file updater.
+ */
+public class ConfigurationFileUpdater {
+
+    private static final transient Logger LOGGER = LoggerFactory.getLogger(ConfigurationFileUpdater.class);
+
+    /**
+     * Updates a <code>ConfigurationFile</code>.
+     *
+     * @param environment       the target <code>Environment</code>.
+     * @param server            the target <code>J2EEApplicationServer</code>.
+     * @param application       the target <code>J2EEApplication</code>.
+     * @param configurationFile the target <code>ConfigurationFile</code>.
+     * @param updateLog         the <code>UpdateLog</code> to use.
+     */
+    public static void update(Environment environment, J2EEApplicationServer server, J2EEApplication application, ConfigurationFile configurationFile, UpdateLog updateLog) throws UpdateException {
+        LOGGER.info("Updating configuration file {}", configurationFile.getName());
+        updateLog.addUpdateMessage(new UpdateMessage("info", "Updating configuration file " + configurationFile.getName()));
+        EventUtils.post(environment, "UPDATE", "Updating configuration file " + configurationFile.getName());
+
+        if (!configurationFile.isActive()) {
+            LOGGER.info("Configuration file {} is inactive, so not updated", configurationFile.getName());
+            updateLog.addUpdateMessage(new UpdateMessage("info", "Configuration file " + configurationFile.getName() + " is inactive, so not updated"));
+            EventUtils.post(environment, "UPDATE", "Configuration file " + configurationFile.getName() + " is inactive, so not updated");
+            return;
+        }
+
+        // check for update delegation
+        if (configurationFile.getAgent() != null && configurationFile.getAgent().trim().length() > 0 && !configurationFile.getAgent().equals(Configuration.AGENT_ID)) {
+            LOGGER.info("Delegating the configuration file {} update to agent {}", configurationFile.getName(), configurationFile.getAgent());
+            updateLog.addUpdateMessage(new UpdateMessage("info", "Delegating the configuration file " + configurationFile.getName() + " update to agent " + configurationFile.getAgent()));
+            EventUtils.post(environment, "UPDATE", "Delegating the configuration file " + configurationFile.getName() + " update to agent " + configurationFile.getAgent());
+            Agent delegationAgent = Configuration.CONFIG_CACHE.getAgent(configurationFile.getAgent());
+            if (delegationAgent == null) {
+                // the delegation agent is not found
+                LOGGER.error("Agent {} is not found in the configuration", configurationFile.getAgent());
+                throw new UpdateException("Agent " + configurationFile.getAgent() + " is not found in the configuration");
+            }
+            try {
+                LOGGER.debug("Call the configuration file WS");
+                ConfigurationFileClient client = new ConfigurationFileClient(delegationAgent.getHostname(), delegationAgent.getPort());
+                client.update(environment.getName(), server.getName(), application.getName(), configurationFile.getName(), true);
+            } catch (ClientException clientException) {
+                // delegation update has failed
+                LOGGER.error("Configuration file {} update failed", configurationFile.getName(), clientException);
+                throw new UpdateException("Configuration file " + configurationFile.getName() + " update failed", clientException);
+            }
+            return;
+        }
+
+        String configurationFileUri = VariableUtils.replace(configurationFile.getUri(), environment.getVariables());
+        if (!FileManipulator.protocolExists(configurationFileUri)) {
+            // the configuration file URI is relative, construct the URI using the J2EE application URI
+            LOGGER.debug("The configuration file URI is relative to the J2EE application URI");
+            configurationFileUri = FileManipulator.format(VariableUtils.replace(application.getUri(), environment.getVariables())) + "!/" + configurationFileUri;
+        }
+
+        // get a file manipulator
+        FileManipulator fileManipulator = null;
+        try {
+            LOGGER.debug("Initializing file manipulator");
+            fileManipulator = FileManipulator.getInstance();
+        } catch (FileManipulatorException fileManipulatorException) {
+            LOGGER.error("Can't initialize file manipulator", fileManipulatorException);
+            throw new UpdateException("Can't initialize file manipulator", fileManipulatorException);
+        }
+
+        // get the application working directory
+        String applicationCacheDir = null;
+        try {
+            LOGGER.debug("Initializing application cache directory");
+            applicationCacheDir = FileManipulator.createJ2EEApplicationCacheDir(environment, application);
+        } catch (FileManipulatorException fileManipulatorException) {
+            LOGGER.error("Can't create J2EE application {} cache directory", application.getName(), fileManipulatorException);
+            throw new UpdateException("Can't create J2EE application " + application.getName() + " cache directory", fileManipulatorException);
+        }
+
+        String configurationFileCache = applicationCacheDir + "/config/" + configurationFile.getName();
+        try {
+            // copy the configuration file in the application cache directory
+            LOGGER.debug("Copying the configuration file {} to the application cache directory", configurationFile.getName());
+            fileManipulator.copy(configurationFileUri, configurationFileCache);
+        } catch (FileManipulatorException fileManipulatorException) {
+            LOGGER.error("Can't copy {} to {}", new Object[]{configurationFileUri, configurationFileCache}, fileManipulatorException);
+            throw new UpdateException("Can't copy " + configurationFileUri + " to " + configurationFileCache, fileManipulatorException);
+        }
+
+        // change mappings in the configuration file
+        LOGGER.debug("Replacing mappings key/value");
+        for (Iterator mappingIterator = configurationFile.getMappings().iterator(); mappingIterator.hasNext(); ) {
+            Mapping mapping = (Mapping) mappingIterator.next();
+            FileManipulator.searchAndReplace(mapping.getKey(), VariableUtils.replace(mapping.getValue(), environment.getVariables()), configurationFileCache);
+        }
+
+        // compare the configuration file with the target one
+        try {
+            if (!fileManipulator.contentEquals(configurationFileCache, VariableUtils.replace(configurationFile.getPath(), environment.getVariables()))) {
+                // the configuration file has changed
+                LOGGER.debug("Configuration file {} has changed", configurationFile.getName());
+                fileManipulator.copy(configurationFileCache, VariableUtils.replace(configurationFile.getPath(), environment.getVariables()));
+                updateLog.setStatus("Update performed");
+                updateLog.setUpdated(true);
+                LOGGER.info("Configuration file {} updated", configurationFile.getName());
+                updateLog.addUpdateMessage(new UpdateMessage("info", "Configuration file " + configurationFile.getName() + " updated"));
+                EventUtils.post(environment, "UPDATE", "Configuration file " + configurationFile.getName() + " updated");
+            }
+        } catch (Exception e) {
+            // the configuration file update failed, delete from the cache
+            try {
+                fileManipulator.delete(configurationFileCache);
+            } catch (FileManipulatorException fileManipulatorException) {
+                LOGGER.warn("Can't delete {}", configurationFile.getName(), fileManipulatorException);
+            }
+            LOGGER.error("Configuration file {} update failed", configurationFile.getName(), e);
+            throw new UpdateException("Configuration file " + configurationFile.getName() + " update failed", e);
+        }
+    }
+
+    /**
+     * Wrapper method to update a configuration file via WS.
+     *
+     * @param environmentName       the target environment name.
+     * @param serverName            the target J2EE application server name.
+     * @param applicationName       the target J2EE application name.
+     * @param configurationFileName the target configuration file name.
+     * @param delegation            flag indicating if the call is made by another agent (true), or by a client (false).
+     * @throws KalumetException in case of update error.
+     */
+    public static void update(String environmentName, String serverName, String applicationName, String configurationFileName, boolean delegation) throws KalumetException {
+        LOGGER.info("Configuration file {} update requested by WS", configurationFileName);
+
+        // load configuration
+        LOGGER.debug("Loading configuration");
+        Kalumet kalumet = Kalumet.digeste(Configuration.CONFIG_LOCATION);
+        Environment environment = kalumet.getEnvironment(environmentName);
+        if (environment == null) {
+            LOGGER.error("Environment {} is not found in the configuration", environmentName);
+            throw new KalumetException("Environment " + environmentName + " is not found in the configuration");
+        }
+        J2EEApplicationServer applicationServer = environment.getJ2EEApplicationServers().getJ2EEApplicationServer(serverName);
+        if (applicationServer == null) {
+            LOGGER.error("J2EE application server {} is not found in environment {}", serverName, environmentName);
+            throw new KalumetException("J2EE application server " + serverName + " is not found in environment " + environmentName);
+        }
+        J2EEApplication application = applicationServer.getJ2EEApplication(applicationName);
+        if (application == null) {
+            LOGGER.error("J2EE application {} is not found in J2EE application server {}", applicationName, serverName);
+            throw new KalumetException("J2EE application " + applicationName + " is not found in J2EE application server " + serverName);
+        }
+        ConfigurationFile configurationFile = application.getConfigurationFile(configurationFileName);
+        if (configurationFile == null) {
+            LOGGER.error("Configuration file {} is not found in J2EE application {}", configurationFileName, applicationName);
+            throw new KalumetException("Configuration file " + configurationFileName + " is not found in J2EE application " + applicationName);
+        }
+
+        // update cache
+        LOGGER.debug("Updating configuration cache");
+        Configuration.CONFIG_CACHE = kalumet;
+
+        // post event and create update logger
+        EventUtils.post(environment, "UPDATE", "Configuration file " + configurationFile.getName() + " update requested by WS");
+        UpdateLog updateLog = new UpdateLog("Configuration file " + configurationFile.getName() + " update in progress ...", environment.getName(), environment);
+
+        // send and wait a notification if it's not a delegation
+        if (!delegation) {
+            // it's a client call
+            LOGGER.info("Send a notification and waiting for the count down");
+            EventUtils.post(environment, "UPDATE", "Send a notification and waiting for the count down");
+            NotifierUtils.waitAndNotify(environment);
+        }
+
+        try {
+            // call the updater method
+            LOGGER.debug("Call configuration file updater");
+            ConfigurationFileUpdater.update(environment, applicationServer, application, configurationFile, updateLog);
+        } catch (Exception e) {
+            LOGGER.error("Configuration file {} update failed", configurationFile.getName(), e);
+            EventUtils.post(environment, "ERROR", "Configuration file " + configurationFile.getName() + " update failed: " + e.getMessage());
+            if (!delegation) {
+                // it's a client call, send a publisher
+                updateLog.setStatus("Configuration file " + configurationFile.getName() + " update failed");
+                updateLog.addUpdateMessage(new UpdateMessage("error", "Configuration file " + configurationFile.getName() + " update failed: " + e.getMessage()));
+                PublisherUtils.publish(environment);
+            }
+            throw new UpdateException("Configuration file " + configurationFile.getName() + " update FAILED: " + e.getMessage(), e);
+        }
+
+        LOGGER.info("Configuration file {} updated", configurationFile.getName());
+        EventUtils.post(environment, "UPDATE", "Configuration file " + configurationFile.getName() + " updated");
+        if (!delegation) {
+            if (updateLog.isUpdated()) {
+                updateLog.setStatus("Configuration file " + configurationFile.getName() + " updated");
+            } else {
+                updateLog.setStatus("Configuration file " + configurationFile.getName() + " already up to date");
+            }
+            updateLog.addUpdateMessage(new UpdateMessage("info", "Configuration file " + configurationFile.getName() + " updated"));
+            LOGGER.info("Publishing update report");
+            PublisherUtils.publish(environment);
+        }
+    }
+
+    /**
+     * Wrapper method to check if a configuration file is update to date or not via WS.
+     *
+     * @param environmentName       the target environment name.
+     * @param serverName            the target J2EE application server name.
+     * @param applicationName       the target J2EE application name.
+     * @param configurationFileName the target configuration file name.
+     * @return true if the configuration file is up to date, false else.
+     * @throws KalumetException in case of error during configuration file check.
+     */
+    public static boolean check(String environmentName, String serverName, String applicationName, String configurationFileName) throws KalumetException {
+        LOGGER.info("Configuration file {} status check requested by WS", configurationFileName);
+
+        // load configuration.
+        LOGGER.debug("Loading configuration");
+        Kalumet kalumet = Kalumet.digeste(Configuration.CONFIG_LOCATION);
+
+        Environment environment = kalumet.getEnvironment(environmentName);
+        if (environment == null) {
+            LOGGER.error("Environment {} is not found in the configuration", environmentName);
+            throw new KalumetException("Environment " + environmentName + " is not found in the configuration");
+        }
+        J2EEApplicationServer applicationServer = environment.getJ2EEApplicationServers().getJ2EEApplicationServer(serverName);
+        if (applicationServer == null) {
+            LOGGER.error("J2EE application server {} is not found in environment {}", serverName, environmentName);
+            throw new KalumetException("J2EE application server " + serverName + " is not found in environment " + environmentName);
+        }
+        J2EEApplication application = applicationServer.getJ2EEApplication(applicationName);
+        if (application == null) {
+            LOGGER.error("J2EE application {} is not found in J2EE application server {}", applicationName, serverName);
+            throw new KalumetException("J2EE application " + applicationName + " is not found in J2EE application server " + serverName);
+        }
+        ConfigurationFile configurationFile = application.getConfigurationFile(configurationFileName);
+        if (configurationFile == null) {
+            LOGGER.error("Configuration file {} is not found in J2EE application {}", configurationFileName, applicationName);
+            throw new KalumetException("Configuration file " + configurationFileName + " is not found in J2EE application " + applicationName);
+        }
+
+        if (configurationFile.getAgent() != null && configurationFile.getAgent().trim().length() > 0 && !configurationFile.getAgent().equals(Configuration.AGENT_ID)) {
+            // the check needs to be delegate to another agent
+            LOGGER.info("Delegating configuration file {} check to agent {}", configurationFile.getName(), configurationFile.getAgent());
+            Agent agentDelegation = Configuration.CONFIG_CACHE.getAgent(configurationFile.getAgent());
+            if (agentDelegation == null) {
+                LOGGER.error("Agent {} is not found in the configuration", configurationFile.getAgent());
+                throw new KalumetException("Agent " + configurationFile.getAgent() + " is not found in the configuration");
+            }
+            // call the service
+            ConfigurationFileClient client = new ConfigurationFileClient(agentDelegation.getHostname(), agentDelegation.getPort());
+            return client.check(environmentName, serverName, applicationName, configurationFileName);
+        }
+
+        // initialize the file manipulator.
+        LOGGER.debug("Initializing file manipulator");
+        FileManipulator fileManipulator = FileManipulator.getInstance();
+
+        // constructs the configuration file URI.
+        String configurationFileUri = VariableUtils.replace(configurationFile.getUri(), environment.getVariables());
+        if (!FileManipulator.protocolExists(configurationFileUri)) {
+            // the configuration file URI doesn't contain protocol prefix,
+            // constructs the configuration file URI using the application URI
+            LOGGER.debug("Configuration file {} URI is relative to the J2EE application one", configurationFile.getName());
+            configurationFileUri = FileManipulator.format(VariableUtils.replace(application.getUri(), environment.getVariables())) + "!/" + configurationFileUri;
+        }
+
+        // get the application cache directory.
+        LOGGER.debug("Creating the application cache directory");
+        String applicationCacheDir = FileManipulator.createJ2EEApplicationCacheDir(environment, application);
+
+        // get the configuration file cache.
+        LOGGER.debug("Creating the configuration file cache location");
+        String configurationFileCache = applicationCacheDir + "/config/" + configurationFile.getName();
+
+        // copy the configuration file in the application cache directory
+        LOGGER.debug("Copying the configuration file {} to the application cache directory", configurationFile.getName());
+        fileManipulator.copy(configurationFileUri, configurationFileCache);
+
+        // change mappings into the configuration file.
+        LOGGER.debug("Replacing mappings key/value");
+        for (Iterator mappingIterator = configurationFile.getMappings().iterator(); mappingIterator.hasNext(); ) {
+            Mapping mapping = (Mapping) mappingIterator.next();
+            FileManipulator.searchAndReplace(mapping.getKey(), VariableUtils.replace(mapping.getValue(), environment.getVariables()), configurationFileCache);
+        }
+
+        // compare the configuration file with the target one.
+        return fileManipulator.contentEquals(configurationFileCache, VariableUtils.replace(configurationFile.getPath(), environment.getVariables()));
+    }
+
+}

Added: incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/ContentManagerUpdater.java
URL: http://svn.apache.org/viewvc/incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/ContentManagerUpdater.java?rev=1194852&view=auto
==============================================================================
--- incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/ContentManagerUpdater.java (added)
+++ incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/ContentManagerUpdater.java Sat Oct 29 09:37:44 2011
@@ -0,0 +1,201 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.kalumet.agent.updater;
+
+import org.apache.kalumet.KalumetException;
+import org.apache.kalumet.agent.Configuration;
+import org.apache.kalumet.agent.utils.EventUtils;
+import org.apache.kalumet.model.*;
+import org.apache.kalumet.model.update.UpdateLog;
+import org.apache.kalumet.model.update.UpdateMessage;
+import org.apache.kalumet.utils.NotifierUtils;
+import org.apache.kalumet.utils.PublisherUtils;
+import org.apache.kalumet.utils.VariableUtils;
+import org.apache.kalumet.ws.client.ClientException;
+import org.apache.kalumet.ws.client.ContentManagerClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.Method;
+import java.util.Iterator;
+
+/**
+ * Content manager updater.
+ */
+public class ContentManagerUpdater {
+
+    private static final transient Logger LOGGER = LoggerFactory.getLogger(ContentManagerUpdater.class);
+
+    /**
+     * Update a content manager.
+     *
+     * @param environment    the target <code>Environment</code>.
+     * @param server         the target <code>J2EEApplicationServer</code>.
+     * @param application    the target <code>J2EEApplication</code>.
+     * @param contentManager the target <code>ContentManager</code>.
+     * @param updateLog      the <code>UpdateLog</code> to use.
+     * @throws UpdateException in case of update failure.
+     */
+    public static void update(Environment environment, J2EEApplicationServer server, J2EEApplication application, ContentManager contentManager, UpdateLog updateLog) throws UpdateException {
+        LOGGER.info("Updating content manager {}", contentManager.getName());
+        updateLog.addUpdateMessage(new UpdateMessage("info", "Updating content manager " + contentManager.getName()));
+        EventUtils.post(environment, "UPDATE", "Updating content manager " + contentManager.getName());
+
+        if (!contentManager.isActive()) {
+            // the content manager is not active
+            LOGGER.info("Content manager {} is inactive, so not updated", contentManager.getName());
+            updateLog.addUpdateMessage(new UpdateMessage("info", "Content manager " + contentManager.getName() + " is inactive, so not updated"));
+            EventUtils.post(environment, "UPDATE", "Content manager " + contentManager.getName() + " is inactive, so not updated");
+            return;
+        }
+
+        if (contentManager.getAgent() != null && contentManager.getAgent().trim().length() > 0 && !contentManager.getAgent().equals(Configuration.AGENT_ID)) {
+            // the content manager update is delegated to another agent
+            LOGGER.info("Delegating content manager {} update to agent {}", contentManager.getName(), contentManager.getAgent());
+            updateLog.addUpdateMessage(new UpdateMessage("info", "Delegating content manager " + contentManager.getName() + " update to agent " + contentManager.getAgent()));
+            EventUtils.post(environment, "UPDATE", "Delegating content manager " + contentManager.getName() + " update to agent " + contentManager.getAgent());
+            Agent delegationAgent = Configuration.CONFIG_CACHE.getAgent(contentManager.getAgent());
+            if (delegationAgent == null) {
+                // the content manager agent is not found in the configuration
+                LOGGER.error("Agent {} is not found in the configuration", contentManager.getAgent());
+                throw new UpdateException("Agent " + contentManager.getAgent() + " is not found in the configuration");
+            }
+            try {
+                // call agent WebService
+                LOGGER.debug("Calling content manager WebService WS");
+                ContentManagerClient client = new ContentManagerClient(delegationAgent.getHostname(), delegationAgent.getPort());
+                client.update(environment.getName(), server.getName(), application.getName(), contentManager.getName(), true);
+            } catch (ClientException clientException) {
+                LOGGER.error("Content manager {} update failed", contentManager.getName(), clientException);
+                throw new UpdateException("Content manager " + contentManager.getName() + " update failed", clientException);
+            }
+            return;
+        }
+
+        try {
+            LOGGER.debug("Loading content manager class name");
+            Class contentManagerClass = Class.forName(VariableUtils.replace(contentManager.getClassname(), environment.getVariables()));
+            Object contentManagerObject = contentManagerClass.newInstance();
+            // call method properties
+            for (Iterator propertyIterator = contentManager.getProperties().iterator(); propertyIterator.hasNext(); ) {
+                Property property = (Property) propertyIterator.next();
+                Method method = contentManagerClass.getMethod("set" + VariableUtils.replace(property.getName(), environment.getVariables()), new Class[]{String.class});
+                method.invoke(contentManagerObject, new Object[]{VariableUtils.replace(property.getValue(), environment.getVariables())});
+            }
+            // call main method
+            Method mainMethod = contentManagerClass.getMethod("main", new Class[]{});
+            mainMethod.invoke(contentManagerObject, new Object[]{});
+            LOGGER.info("Content manager {} updated", contentManager.getName());
+            updateLog.setStatus("update performed");
+            updateLog.setUpdated(true);
+            updateLog.addUpdateMessage(new UpdateMessage("info", "Content manager " + contentManager.getName() + " updated"));
+            EventUtils.post(environment, "UPDATE", "Content manager " + contentManager.getName() + " updated");
+        } catch (Exception e) {
+            LOGGER.error("Content manager {} update failed", contentManager.getName(), e);
+            throw new UpdateException("Content manager " + contentManager.getName() + " update failed", e);
+        }
+    }
+
+    /**
+     * Wrapper method to update a content manager via WS.
+     *
+     * @param environmentName    the target environment name.
+     * @param serverName         the target J2EE application server name.
+     * @param applicationName    the target J2E application name.
+     * @param contentManagerName the target content manager name.
+     * @param delegation         flag indicating if the update is called by another agent (true) or by a client (false).
+     * @throws KalumetException in case of update failure.
+     */
+    public static void update(String environmentName, String serverName, String applicationName, String contentManagerName, boolean delegation) throws KalumetException {
+        LOGGER.info("Content manager {} update requested by WS", contentManagerName);
+
+        // load configuration.
+        LOGGER.debug("Loading configuration");
+        Kalumet kalumet = Kalumet.digeste(Configuration.CONFIG_LOCATION);
+
+        // looking for component objects.
+        Environment environment = kalumet.getEnvironment(environmentName);
+        if (environment == null) {
+            LOGGER.error("Environment {} is not found in the configuration", environmentName);
+            throw new KalumetException("Environment " + environmentName + " is not found in the configuration");
+        }
+        J2EEApplicationServer applicationServer = environment.getJ2EEApplicationServers().getJ2EEApplicationServer(serverName);
+        if (applicationServer == null) {
+            LOGGER.error("J2EE application server {} is not found in environment {}", serverName, environment.getName());
+            throw new KalumetException("J2EE application server " + serverName + " is not found in environment " + environment.getName());
+        }
+        J2EEApplication application = applicationServer.getJ2EEApplication(applicationName);
+        if (application == null) {
+            LOGGER.error("J2EE application {} is not found in J2EE application server {}", applicationName, applicationServer.getName());
+            throw new KalumetException("J2EE application " + applicationName + " is not found in J2EE application server " + applicationServer.getName());
+        }
+        ContentManager contentManager = application.getContentManager(contentManagerName);
+        if (contentManager == null) {
+            LOGGER.error("Content manager {} is not found in J2EE application {}", contentManagerName, application.getName());
+            throw new KalumetException("Content manager " + contentManagerName + " is not found in J2EE application " + application.getName());
+        }
+
+        // update configuration cache.
+        LOGGER.debug("Updating configuration cache");
+        Configuration.CONFIG_CACHE = kalumet;
+
+        // post event and create an update log
+        EventUtils.post(environment, "UPDATE", "Content manager " + contentManager.getName() + " update requested by WS");
+        UpdateLog updateLog = new UpdateLog("Content manager " + contentManager.getName() + " update in progress ...", environment.getName(), environment);
+
+        if (!delegation) {
+            // the update is a client call,
+            // send a notification and waiting for the count down
+            LOGGER.info("Send a notification and waiting for the count down");
+            EventUtils.post(environment, "UPDATE", "Send a notification and waiting for the count down");
+            NotifierUtils.waitAndNotify(environment);
+        }
+
+        try {
+            // call the content manager updater
+            LOGGER.debug("Call content manager updater");
+            ContentManagerUpdater.update(environment, applicationServer, application, contentManager, updateLog);
+        } catch (Exception e) {
+            LOGGER.error("Content manager " + contentManager.getName() + " update failed", e);
+            EventUtils.post(environment, "ERROR", "Content manager " + contentManager.getName() + " update failed: " + e.getMessage());
+            if (!delegation) {
+                updateLog.setStatus("Content manager " + contentManager.getName() + " update failed");
+                updateLog.addUpdateMessage(new UpdateMessage("error", "Content manager " + contentManager.getName() + " update failed: " + e.getMessage()));
+                PublisherUtils.publish(environment);
+            }
+            throw new UpdateException("Content manager " + contentManager.getName() + " update failed", e);
+        }
+
+        // update completed
+        LOGGER.info("Content manager {} updated", contentManager.getName());
+        EventUtils.post(environment, "UPDATE", "Content manager " + contentManager.getName() + " updated");
+        if (!delegation) {
+            if (updateLog.isUpdated()) {
+                updateLog.setStatus("Content manager " + contentManager.getName() + " updated");
+            } else {
+                updateLog.setStatus("Content manager " + contentManager.getName() + " already up to date");
+            }
+            updateLog.addUpdateMessage(new UpdateMessage("info", "Content manager " + contentManager.getName() + " updated"));
+            LOGGER.info("Publishing update report");
+            PublisherUtils.publish(environment);
+        }
+
+    }
+
+}

Added: incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/DatabaseUpdater.java
URL: http://svn.apache.org/viewvc/incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/DatabaseUpdater.java?rev=1194852&view=auto
==============================================================================
--- incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/DatabaseUpdater.java (added)
+++ incubator/kalumet/trunk/agent/src/main/java/org/apache/kalumet/agent/updater/DatabaseUpdater.java Sat Oct 29 09:37:44 2011
@@ -0,0 +1,202 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.kalumet.agent.updater;
+
+import org.apache.kalumet.KalumetException;
+import org.apache.kalumet.agent.Configuration;
+import org.apache.kalumet.agent.utils.EventUtils;
+import org.apache.kalumet.model.*;
+import org.apache.kalumet.model.update.UpdateLog;
+import org.apache.kalumet.model.update.UpdateMessage;
+import org.apache.kalumet.utils.NotifierUtils;
+import org.apache.kalumet.utils.PublisherUtils;
+import org.apache.kalumet.ws.client.ClientException;
+import org.apache.kalumet.ws.client.DatabaseClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Iterator;
+
+/**
+ * Database updater.
+ */
+public class DatabaseUpdater {
+
+    private static final transient Logger LOGGER = LoggerFactory.getLogger(DatabaseUpdater.class);
+
+    /**
+     * Updates a database.
+     *
+     * @param environment the target <code>Environment</code>.
+     * @param server      the target <code>J2EEApplicationServer</code>.
+     * @param application the target <code>J2EEApplication</code>.
+     * @param database    the target <code>Database</code>.
+     * @param updateLog   the <code>UpdateLog</code> to use.
+     */
+    public static void update(Environment environment, J2EEApplicationServer server, J2EEApplication application, Database database, UpdateLog updateLog) throws UpdateException {
+        LOGGER.info("Updating database {}", database.getName());
+        updateLog.addUpdateMessage(new UpdateMessage("info", "Updating database " + database.getName()));
+        EventUtils.post(environment, "UPDATE", "Updating database " + database.getName());
+
+        if (!database.isActive()) {
+            // database is not active
+            LOGGER.info("Database {} is inactive, so not updated", database.getName());
+            updateLog.addUpdateMessage(new UpdateMessage("info", "Database " + database.getName() + " is inactive, so not updated"));
+            EventUtils.post(environment, "UPDATE", "Database " + database.getName() + " is inactive, so not updated");
+            return;
+        }
+
+        if (database.getAgent() != null && database.getAgent().trim().length() > 0 && !database.getAgent().equals(Configuration.AGENT_ID)) {
+            // database update delegated to another agent
+            LOGGER.info("Delegating database {} update to agent {}", database.getName(), database.getAgent());
+            updateLog.addUpdateMessage(new UpdateMessage("info", "Delegating database " + database.getName() + " update to agent " + database.getAgent()));
+            EventUtils.post(environment, "UPDATE", "Delegating database " + database.getName() + " update to agent " + database.getAgent());
+            Agent delegationAgent = Configuration.CONFIG_CACHE.getAgent(database.getAgent());
+            if (delegationAgent == null) {
+                // database agent is not found in configuration
+                LOGGER.error("Agent {} is not found in the configuration", database.getAgent());
+                throw new UpdateException("Agent " + database.getAgent() + " is not found in the configuration");
+            }
+            try {
+                // call WS
+                LOGGER.debug("Calling database WS");
+                DatabaseClient client = new DatabaseClient(delegationAgent.getHostname(), delegationAgent.getPort());
+                client.update(environment.getName(), server.getName(), application.getName(), database.getName(), true);
+            } catch (ClientException clientException) {
+                LOGGER.error("Database {} update failed", database.getName(), clientException);
+                throw new UpdateException("Database " + database.getName() + " update failed", clientException);
+            }
+            return;
+        }
+
+        // launch SQL scripts on the database
+        LOGGER.debug("Executing SQL scripts");
+        for (Iterator sqlScriptIterator = database.getSqlScripts().iterator(); sqlScriptIterator.hasNext(); ) {
+            SqlScript sqlScript = (SqlScript) sqlScriptIterator.next();
+            try {
+                SqlScriptUpdater.execute(environment, server, application, database, sqlScript, updateLog);
+            } catch (UpdateException updateException) {
+                // the SQL script execution failed
+                if (sqlScript.isBlocker()) {
+                    // the SQL script is update blocker
+                    LOGGER.error("SQL script {} execution failed", sqlScript.getName(), updateException);
+                    updateLog.addUpdateMessage(new UpdateMessage("error", "SQL script " + sqlScript.getName() + " execution failed: " + updateException.getMessage()));
+                    EventUtils.post(environment, "ERROR", "SQL script " + sqlScript.getName() + " execution failed: " + updateException.getMessage());
+                    throw new UpdateException("SQL script " + sqlScript.getName() + " execution failed", updateException);
+                } else {
+                    // the SQL script is not update blocker
+                    LOGGER.warn("SQL script " + sqlScript.getName() + " execution failed", updateException);
+                    updateLog.addUpdateMessage(new UpdateMessage("warn", "SQL script " + sqlScript.getName() + " execution failed: " + updateException.getMessage()));
+                    updateLog.addUpdateMessage(new UpdateMessage("info", "SQL script " + sqlScript.getName() + " is not update blocker, update continues"));
+                    EventUtils.post(environment, "WARN", "SQL script " + sqlScript.getName() + " execution failed: " + updateException.getMessage());
+                    EventUtils.post(environment, "UPDATE", "SQL script " + sqlScript.getName() + " is not update blocker, update continues");
+                }
+            }
+        }
+
+        // update completed
+        LOGGER.info("Database {} updated", database.getName());
+        updateLog.addUpdateMessage(new UpdateMessage("info", "Database " + database.getName() + " updated"));
+        EventUtils.post(environment, "UPDATE", "Database " + database.getName() + " updated");
+    }
+
+    /**
+     * Wrapper method to update a database via WS.
+     *
+     * @param environmentName the target environment name.
+     * @param serverName      the target J2EE application server name.
+     * @param applicationName the target J2EE application name.
+     * @param databaseName    the target database name.
+     * @param delegation      true if the call is made by another agent, false if the call is made by a client.
+     * @throws KalumetException in case of update failure.
+     */
+    public static void update(String environmentName, String serverName, String applicationName, String databaseName, boolean delegation) throws KalumetException {
+        LOGGER.info("Database {} update requested by WS", databaseName);
+
+        // load configuration.
+        LOGGER.debug("Loading configuration");
+        Kalumet kalumet = Kalumet.digeste(Configuration.CONFIG_LOCATION);
+        Environment environment = kalumet.getEnvironment(environmentName);
+        if (environment == null) {
+            LOGGER.error("Environment {} is not found in the configuration", environmentName);
+            throw new KalumetException("Environment " + environmentName + " is not found in the configuration");
+        }
+        J2EEApplicationServer applicationServer = environment.getJ2EEApplicationServers().getJ2EEApplicationServer(serverName);
+        if (applicationServer == null) {
+            LOGGER.error("J2EE application server {} is not found in environment {}", serverName, environmentName);
+            throw new KalumetException("J2EE application server " + serverName + " is not found in environment " + environmentName);
+        }
+        J2EEApplication application = applicationServer.getJ2EEApplication(applicationName);
+        if (application == null) {
+            LOGGER.error("J2EE application {} is not found in J2EE application server {}", applicationName, serverName);
+            throw new KalumetException("J2EE application " + applicationName + " is not found in J2EE application server " + serverName);
+        }
+        Database database = application.getDatabase(databaseName);
+        if (database == null) {
+            LOGGER.error("Database {} is not found in J2EE application {}", databaseName, applicationName);
+            throw new KalumetException("Database " + databaseName + " is not found in J2EE application " + applicationName);
+        }
+
+        // update configuration cache.
+        LOGGER.debug("Updating configuration cache");
+        Configuration.CONFIG_CACHE = kalumet;
+
+        // post journal event
+        EventUtils.post(environment, "UPDATE", "Database " + databaseName + " update requested by WS");
+        // create an update logger
+        UpdateLog updateLog = new UpdateLog("Database " + databaseName + " update in progress ...", environment.getName(), environment);
+
+        if (!delegation) {
+            // the update is requested by a client
+            LOGGER.info("Send a notification and waiting for the count down");
+            EventUtils.post(environment, "UPDATE", "Send a notification and waiting for the count down");
+            NotifierUtils.waitAndNotify(environment);
+        }
+
+        try {
+            // call the updater
+            LOGGER.debug("Call database updater");
+            DatabaseUpdater.update(environment, applicationServer, application, database, updateLog);
+        } catch (Exception e) {
+            LOGGER.error("Database {} update failed", database.getName(), e);
+            EventUtils.post(environment, "ERROR", "Database " + database.getName() + " update failed: " + e.getMessage());
+            if (!delegation) {
+                updateLog.setStatus("Database " + database.getName() + " update failed");
+                updateLog.addUpdateMessage(new UpdateMessage("error", "Database " + database.getName() + " update failed: " + e.getMessage()));
+                PublisherUtils.publish(environment);
+            }
+            throw new UpdateException("Database " + database.getName() + " update failed", e);
+        }
+
+        // update completed
+        LOGGER.info("Database {} updated", database.getName());
+        EventUtils.post(environment, "UPDATE", "Database " + database.getName() + " updated");
+        if (!delegation) {
+            if (updateLog.isUpdated()) {
+                updateLog.setStatus("Database " + database.getName() + " updated");
+            } else {
+                updateLog.setStatus("Database " + database.getName() + " already up to date");
+            }
+            updateLog.addUpdateMessage(new UpdateMessage("info", "Database " + database.getName() + " updated"));
+            LOGGER.info("Publishing update report");
+            PublisherUtils.publish(environment);
+        }
+    }
+
+}