alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Glassfish example source code file (ServerSynchronizer.java)

This example Glassfish source code file (ServerSynchronizer.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Glassfish tags/keywords

application, file, file, io, ioexception, ioexception, list, log, logging, modtime, net, network, server, serversynchronizer, serversynchronizer, string, syncrequest, urisyntaxexception, urisyntaxexception, util

The Glassfish ServerSynchronizer.java source code

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package com.sun.enterprise.v3.admin.cluster;

import java.io.*;
import java.util.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.logging.Logger;
import java.util.logging.Level;

import org.glassfish.api.admin.*;
import org.jvnet.hk2.annotations.*;
import org.jvnet.hk2.component.*;

import org.glassfish.api.ActionReport;
import org.glassfish.api.ActionReport.ExitCode;
import org.glassfish.api.admin.config.ApplicationName;
import com.sun.enterprise.config.serverbeans.Applications;
import com.sun.enterprise.config.serverbeans.Application;
import com.sun.enterprise.config.serverbeans.ApplicationRef;
import com.sun.enterprise.config.serverbeans.Config;
import com.sun.enterprise.config.serverbeans.Domain;
import com.sun.enterprise.config.serverbeans.Server;
import com.sun.enterprise.config.serverbeans.SecurityService;
import com.sun.enterprise.util.cluster.SyncRequest;
import com.sun.enterprise.util.cluster.SyncRequest.ModTime;
import com.sun.enterprise.security.auth.realm.file.FileRealm;
import com.sun.enterprise.util.LocalStringManagerImpl;
import org.glassfish.deployment.versioning.VersioningUtils;

/**
 * The core server synchronization logic.  Given a request from
 * the client, it fills the payload with the files the client needs.
 *
 * The list of files in the config directory to synchronize is in
 * META-INF/config-files in this module, or in config/config-files
 * in te domain directory.
 *
 * @author Bill Shannon
 */
@Service
@Scoped(PerLookup.class)
public class ServerSynchronizer implements PostConstruct {

    @Inject
    private ServerEnvironment env;

    @Inject
    private Domain domain;

    @Inject(optional = true)
    private Applications applications;

    private static boolean syncArchive = false;

    private URI domainRootUri;  // URI of the domain's root directory

    private Logger logger;

    private static enum SyncLevel { TOP, DIRECTORY, RECURSIVE };

    private final static LocalStringManagerImpl strings =
        new LocalStringManagerImpl(ServerSynchronizer.class);

    @Override
    public void postConstruct() {
        domainRootUri = env.getDomainRoot().toURI();
    }

    /**
     * Handle a single syncrhonization request for the given server
     * by adding the needed files to the payload.
     */
    public void synchronize(Server server, SyncRequest sr,
                            Payload.Outbound payload,
                            ActionReport report, Logger logger) {
        this.logger = logger;
        try {
            logger.fine("ServerSynchronizer: synchronization request for " +
                        "server " + server.getName() + ", directory " + sr.dir);
            // handle the request appropriately based on the directory
            if (sr.dir.equals("config"))
                synchronizeConfig(payload, server, sr);
            else if (sr.dir.equals("applications"))
                synchronizeApplications(payload, server, sr);
            else if (sr.dir.equals("lib"))
                synchronizeLib(payload, server, sr);
            else if (sr.dir.equals("docroot"))
                synchronizeDocroot(payload, server, sr);
            else if (sr.dir.equals("config-specific"))
                synchronizeConfigSpecificDir(payload, server, sr);
            else {
                report.setActionExitCode(ExitCode.FAILURE);
                report.setMessage(
                        strings.getLocalString("serversync.unknown.dir",
                            "Unknown directory: {0}", sr.dir));
                return;
            }
            report.setActionExitCode(ExitCode.SUCCESS);
        } catch (URISyntaxException ex) {
            logger.fine("ServerSynchronizer: Exception processing request");
            logger.fine(ex.toString());
            report.setActionExitCode(ExitCode.FAILURE);
            report.setMessage(
                    strings.getLocalString("serversync.exception.processing",
                        "ServerSynchronizer: Exception processing request"));
            report.setFailureCause(ex);
        }
    }

    /**
     * Synchronize files in the config directory.
     * If the domain.xml file is up to date, don't worry
     * about any of the other files.
     */
    private void synchronizeConfig(Payload.Outbound payload, Server server,
                                    SyncRequest sr) throws URISyntaxException {
        logger.finer("ServerSynchronizer: synchronize config");
        // find the domain.xml entry
        ModTime domainXmlMT = null;
        for (ModTime mt : sr.files) {
            if (mt.name.equals("domain.xml")) {
                domainXmlMT = mt;
                break;
            }
        }
        if (domainXmlMT == null)        // couldn't find it, fake it
            domainXmlMT = new ModTime("domain.xml", 0);

        File configDir = env.getConfigDirPath();
        if (!syncFile(domainRootUri, configDir, domainXmlMT, payload)) {
            logger.fine("ServerSynchronizer: domain.xml HAS NOT CHANGED, " +
                        "thus no files will be synchronized");
            return;
        }

        // get the set of all the config files we need to consider
        Set<String> configFileSet = getConfigFileNames();
        configFileSet.remove("domain.xml");     // already handled it

        // add the list of file realm files
        getRealmFileNames(server, configFileSet);

        for (ModTime mt : sr.files) {
            if (mt.name.equals("domain.xml"))   // did domain.xml above
                continue;
            if (configFileSet.contains(mt.name)) {
                // if client has file, remove it from set
                configFileSet.remove(mt.name);
                syncFile(domainRootUri, configDir, mt, payload);
            } else
                removeFile(domainRootUri, configDir, mt, payload);
        }

        // now do all the remaining files the client doesn't have
        for (String name : configFileSet)
            syncFile(domainRootUri, configDir, new ModTime(name, 0), payload);
    }

    /**
     * Return the names of the config files we need to consider.
     * Names are all relative to the config directory.
     */
    private Set<String> getConfigFileNames() {
        Set<String> files = new LinkedHashSet();
        BufferedReader in = null;
        try {
            File configDir = env.getConfigDirPath();
            File f = new File(configDir, "config-files");
            if (f.exists())
                in = new BufferedReader(new InputStreamReader(
                                                new FileInputStream(f)));
            else {
                InputStream res =
                    getClass().getResourceAsStream("/META-INF/config-files");
                if (res != null)
                    in = new BufferedReader(new InputStreamReader(res));
                else
                    logger.severe("ServerSynchronizer: can't find list of " +
                                "config files to synchronize!");
            }
            String line;
            if (in != null) {
                while ((line = in.readLine()) != null) {
                    if (line.startsWith("#"))
                        continue;
                    files.add(line.trim());
                }
            }
        } catch (IOException ex) {
            logger.fine(
                "ServerSynchronizer: IOException in getConfigFileNames");
            logger.fine(ex.toString());
        } finally {
            try {
                if (in != null)
                    in.close();
            } catch (IOException cex) {
            }
        }
        return files;
    }

    /**
     * Get the names of any realm files in the config directory
     * and add them to the set of file names.  This will normally
     * find at least the "admin-keyfile" and "keyfile" files.
     */
    private void getRealmFileNames(Server server, Set<String> files) {
        File configDir = env.getConfigDirPath();
        URI configURI = configDir.toURI();
        Config config = domain.getConfigNamed(server.getConfigRef());
        for (String file : FileRealm.getRealmFileNames(config)) {
            File rfile = new File(file);
            if (!rfile.exists())        // skip if file doesn't exist
                continue;
            URI rURI = rfile.toURI();
            URI f = configURI.relativize(rfile.toURI());
            if (!f.isAbsolute())        // if file is in config dir, add it
                files.add(f.toString());
        }
    }

    /**
     * Sync an individual file.  Return true if the file changed.
     * The file is named by mt.name, relative to base.  The name
     * used in the response will be relative to root.
     */
    private boolean syncFile(URI root, File base, ModTime mt,
                            Payload.Outbound payload)
                            throws URISyntaxException {
        File f = fileOf(base, mt.name);
        if (!f.exists())
            return false;
        if (mt.time != 0 && f.lastModified() == mt.time)
            return false;     // success, nothing to do
        if (logger.isLoggable(Level.FINEST))
            logger.finest("ServerSynchronizer: file " + mt.name +
                            " out of date, time " + f.lastModified());
        try {
            if (mt.time == 0)
                logger.fine("ServerSynchronizer: sending file " + f +
                            " because it doesn't exist on the instance");
            else
                logger.fine("ServerSynchronizer: sending file " + f +
                            " because it was out of date");
            payload.attachFile("application/octet-stream",
                root.relativize(f.toURI()),
                "configChange", f);
        } catch (IOException ioex) {
            logger.fine("ServerSynchronizer: IOException attaching file: " + f);
            logger.fine(ioex.toString());
        }
        return true;
    }

    /**
     * Send a request to the client to remove the specified file.
     * The file is named by mt.name, relative to base.  The name
     * used in the response will be relative to root.
     */
    private void removeFile(URI root, File base, ModTime mt,
                            Payload.Outbound payload)
                            throws URISyntaxException {
        File f = fileOf(base, mt.name);
        if (logger.isLoggable(Level.FINEST))
            logger.finest("ServerSynchronizer: file " + mt.name +
                            " removed from client");
        try {
            logger.fine("ServerSynchronizer: removing file " + f +
                        " because it does not exist on the DAS");
            payload.requestFileRemoval(
                root.relativize(f.toURI()),
                "configChange", null);
        } catch (IOException ioex) {
            logger.fine("ServerSynchronizer: IOException removing file: " + f);
            logger.fine(ioex.toString());
        }
    }

    /**
     * Synchronize all the applications in the applications directory.
     * We use the mod time of the application directory to decide if
     * the application has changed.  If it has changed, we also send
     * any of the generated content.
     */
    private void synchronizeApplications(Payload.Outbound payload,
                                    Server server, SyncRequest sr)
                                    throws URISyntaxException {
        logger.finer("ServerSynchronizer: synchronize application instance " +
                                                                sr.instance);
        Map<String, Application> apps = getApps(server);
        File appsDir = env.getApplicationRepositoryPath();

        for (ModTime mt : sr.files) {
            if (apps.containsKey(mt.name)) {
                syncApp(apps.get(mt.name), appsDir, mt, payload);
                // if client has app, remove it from set
                apps.remove(mt.name);
            } else
                removeApp(apps.get(mt.name), appsDir, mt, payload);
        }

        // now do all the remaining apps the client doesn't have
        for (Map.Entry<String, Application> e : apps.entrySet())
            syncApp(e.getValue(), appsDir, new ModTime(e.getKey(), 0),
                                                        payload);
    }

    /**
     * Get the applications that should be
     * available to the specified server instance.
     */
    private Map<String, Application> getApps(Server server) {
        /*
        if (syncAllApps)
            return getAllApps();
        */

        Map<String, Application> apps = new HashMap();
        if (applications == null)
            return apps;        // no apps

        // all apps are under <server>, even in a cluster
        for (ApplicationRef ref : server.getApplicationRef()) {
            Application app = applications.getApplication(ref.getRef());
            if (app != null) {
                logger.finest("ServerSynchronizer: got app " + app.getName());
                if (Boolean.parseBoolean(app.getDirectoryDeployed()))
                    logger.finest("ServerSynchronizer: skipping directory " +
                                "deployed app: " + app.getName());
                else
                    apps.put(VersioningUtils.getRepositoryName(app.getName()), app);
            }
        }
        return apps;
    }

    private Map<String, Application> getAllApps() {
        Map<String, Application> apps = new HashMap();
        if (applications == null)
            return apps;        // no apps

        for (ApplicationName module : applications.getModules()) {
            logger.finest("ServerSynchronizer: found module " +
                                                            module.getName());
            if (module instanceof Application) {
                final Application app = (Application)module;
                if (app.getObjectType().equals("user")) {
                    logger.finest("ServerSynchronizer: got app " +
                                                                app.getName());
                    if (Boolean.parseBoolean(app.getDirectoryDeployed()))
                        logger.fine("ServerSynchronizer: skipping directory " +
                                    "deployed app: " + app.getName());
                    else
                        apps.put(app.getName(), app);
                } else
                    logger.finest("ServerSynchronizer: found wrong app " +
                            app.getName() + ", type " + app.getObjectType());
            }
        }
        return apps;
    }

    /**
     * Synchronize the application named by mt.name in the
     * base directory.  If the application is out of date,
     * add the application files to the payload, including
     * the generated files.
     */
    private boolean syncApp(Application app, File base, ModTime mt,
                            Payload.Outbound payload)
                            throws URISyntaxException {
        logger.finer("ServerSynchronizer: sync app " + mt.name);
        try {
            File appDir = fileOf(base, mt.name);
            if (syncArchive) {
                File archive = app.application();
                logger.finest("ServerSynchronizer: check archive " + archive);
                if (mt.time != 0 && archive.lastModified() == mt.time)
                    return false;     // success, nothing to do

                // attach the archive file
                attachAppArchive(archive, payload);
                /*
                 * Note that we don't need the deployment plan because
                 * we're not going to actually deploy it on the server
                 * instance, we're just going to unzip it.
                 */
            } else {
                logger.finest("ServerSynchronizer: check app dir " + appDir);
                if (mt.time != 0 && appDir.lastModified() == mt.time)
                    return false;     // success, nothing to do

                /*
                 * Recursively attach the application directory and
                 * all the generated directories.  The client will
                 * remove the old versions before installing the new ones.
                 */
                if (mt.time == 0)
                    logger.fine("ServerSynchronizer: sending files for " +
                                "application " + mt.name +
                                " because it doesn't exist on the instance");
                else
                    logger.fine("ServerSynchronizer: sending files for " +
                                "application " + mt.name +
                                " because it was out of date");
                attachAppDir(appDir, payload);
            }

            // in either case, we attach the generated artifacts
            File gdir;
            gdir = env.getApplicationCompileJspPath();
            attachAppDir(fileOf(gdir, mt.name), payload);
            gdir = env.getApplicationGeneratedXMLPath();
            attachAppDir(fileOf(gdir, mt.name), payload);
            gdir = env.getApplicationEJBStubPath();
            attachAppDir(fileOf(gdir, mt.name), payload);
            gdir = new File(env.getApplicationStubPath(), "policy");
            attachAppDir(fileOf(gdir, mt.name), payload);
        } catch (IOException ioex) {
            logger.fine("ServerSynchronizer: IOException syncing app " +
                                                                    mt.name);
            logger.fine(ioex.toString());
        }
        return true;
    }

    /**
     * Synchronize the lib directory.
     */
    private void synchronizeLib(Payload.Outbound payload,
                                    Server server, SyncRequest sr)
                                    throws URISyntaxException {
        List<String> skip = new ArrayList();
        skip.add("databases");
        synchronizeDirectory(payload, server, sr,
                                env.getLibPath(), skip, SyncLevel.RECURSIVE);
    }

    /**
     * Synchronize the docroot directory.
     */
    private void synchronizeDocroot(Payload.Outbound payload,
                                    Server server, SyncRequest sr)
                                    throws URISyntaxException {
        synchronizeDirectory(payload, server, sr,
                                new File(env.getDomainRoot(), "docroot"), null,
                                SyncLevel.DIRECTORY);
    }

    /**
     * Synchronize a directory.
     */
    private void synchronizeDirectory(Payload.Outbound payload,
            Server server, SyncRequest sr, File dir, List<String> skip,
            SyncLevel level) throws URISyntaxException {
        logger.finest("ServerSynchronizer: directory is " + dir);
        List<String> fileSet = getFileNames(dir, skip, level);
        synchronizeDirectory(payload, server, sr, dir, fileSet);
    }

    private void synchronizeDirectory(Payload.Outbound payload,
            Server server, SyncRequest sr, File dir, List<String> fileSet)
            throws URISyntaxException {

        for (ModTime mt : sr.files) {
            if (fileSet.contains(mt.name)) {
                // if client has file, remove it from set
                fileSet.remove(mt.name);
                syncFile(domainRootUri, dir, mt, payload);
            } else
                removeFile(domainRootUri, dir, mt, payload);
        }

        // now do all the remaining files the client doesn't have
        for (String name : fileSet)
            syncFile(domainRootUri, dir, new ModTime(name, 0), payload);
    }

    /**
     * Synchronize the config-specific directory.
     * The directory for the instance is in the instance-config-specific
     * config directory, which is in the main config directory.
     * The instance-config-specific config directory is named
     * <config-name>.
     */
    private void synchronizeConfigSpecificDir(Payload.Outbound payload,
            Server server, SyncRequest sr)
            throws URISyntaxException {
        String configDirName = server.getConfigRef();
        File configDir = env.getConfigDirPath();
        File configSpecificDir = new File(configDir, configDirName);
        logger.finest("ServerSynchronizer: " +
                    "config-specific directory is " + configSpecificDir);
        if (!configSpecificDir.exists()) {
            logger.fine("ServerSynchronizer: no config-specific directory " +
                        " to synchronize: " + configSpecificDir);
            return;             // nothing to do
        }

        List<String> fileSet = new ArrayList();
        getFileNames(configSpecificDir, configDir, null, fileSet,
                                                        SyncLevel.DIRECTORY);
        synchronizeDirectory(payload, server, sr, configDir, fileSet);
    }

    /**
     * Return a list with the names of all the
     * files in the specified directory.
     */
    private List<String> getFileNames(File dir, List skip,
                                        SyncLevel level) {
        List<String> names = new ArrayList();
        if (dir.exists())
            getFileNames(dir, dir, skip, names, level);
        else
            logger.finest("ServerSynchronizer: directory doesn't exist: " +
                                                                        dir);
        return names;
    }

    /**
     * Get the mod times for the entries in dir and add them to the
     * SyncRequest, using names relative to baseDir.  If level is
     * RECURSIVE, check subdirectories and only include times for files,
     * not directories.
     */
    private void getFileNames(File dir, File baseDir, List<String> skip,
                                List<String> names, SyncLevel level) {
        if (level == SyncLevel.TOP) {
            String name = baseDir.toURI().relativize(dir.toURI()).getPath();
            // if name is a directory, it will end with "/"
            if (name.endsWith("/"))
                name = name.substring(0, name.length() - 1);
            names.add(name);
            return;     // nothing else
        }
        for (String file : dir.list()) {
            File f = new File(dir, file);
            String name = baseDir.toURI().relativize(f.toURI()).getPath();
            // if name is a directory, it will end with "/"
            if (name.endsWith("/"))
                name = name.substring(0, name.length() - 1);
            if (skip != null && skip.contains(name))
                continue;
            if (f.isDirectory() && level == SyncLevel.RECURSIVE) {
                getFileNames(f, baseDir, skip, names, level);
            } else {
                names.add(name);
            }
        }
    }

    /**
     * Attach the application archive file to the payload.
     */
    private void attachAppArchive(File file, Payload.Outbound payload)
                                throws IOException {
        if (logger.isLoggable(Level.FINER)) {
            logger.finer("ServerSynchronizer: domainRootUri " + domainRootUri);
            logger.finer("ServerSynchronizer: file.toURI() " + file.toURI());
            logger.finer("ServerSynchronizer: attach file " +
                            domainRootUri.relativize(file.toURI()));
        }
        payload.attachFile("application/octet-stream",
            domainRootUri.relativize(file.toURI()),
            "configChange", file);
    }

    /**
     * Attach the application directory and all its contents to the payload.
     */
    private void attachAppDir(File dir, Payload.Outbound payload)
                                throws IOException {
        if (logger.isLoggable(Level.FINER))
            logger.finer("ServerSynchronizer: attach directory " +
                            domainRootUri.relativize(dir.toURI()));
        if (!dir.exists()) {
            logger.finer("ServerSynchronizer: nothing to attach");
            return;
        }
        payload.requestFileReplacement("application/octet-stream",
            domainRootUri.relativize(dir.toURI()),
            "configChange", null, dir, true);
    }

    /**
     * Send requests to the client to remove the specified app directory
     * and all the generated directories.
     */
    private void removeApp(Application app, File base, ModTime mt,
                            Payload.Outbound payload)
                            throws URISyntaxException {
        logger.fine("ServerSynchronizer: removing files for application " +
                    mt.name +
                    " because it is no longer deployed to this instance");
        try {
            File dir = fileOf(base, mt.name);
            removeDir(dir, payload);
            dir = env.getApplicationCompileJspPath();
            removeDir(fileOf(dir, mt.name), payload);
            dir = env.getApplicationGeneratedXMLPath();
            removeDir(fileOf(dir, mt.name), payload);
            dir = env.getApplicationEJBStubPath();
            removeDir(fileOf(dir, mt.name), payload);
            dir = new File(env.getApplicationStubPath(), "policy");
            removeDir(fileOf(dir, mt.name), payload);
        } catch (IOException ioex) {
            logger.fine("ServerSynchronizer: IOException removing app " +
                                                                    mt.name);
            logger.fine(ioex.toString());
        }
    }

    /**
     * Request recursive removal of the specified directory.
     */
    private void removeDir(File file, Payload.Outbound payload)
                                throws IOException {
        payload.requestFileRemoval(
            domainRootUri.relativize(file.toURI()),
            "configChange", null, true);    // recursive removal
    }

    /**
     * Return a File representing the URI relative to the base directory.
     */
    private File fileOf(File base, String uri) throws URISyntaxException {
        // have to use string concatenation to combine the relative URI
        // with the base URI because URI.resolve() ignores the last
        // component of the base URI
        return new File(new URI(base.toURI().toString() + "/" + uri));
    }
}

Other Glassfish examples (source code examples)

Here is a short list of links related to this Glassfish ServerSynchronizer.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.