All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.gov.nasa.worldwindx.examples.util.SessionState Maven / Gradle / Ivy

Go to download

World Wind is a collection of components that interactively display 3D geographic information within Java applications or applets.

There is a newer version: 2.0.0-986
Show newest version
/*
 * Copyright (C) 2012 United States Government as represented by the Administrator of the
 * National Aeronautics and Space Administration.
 * All Rights Reserved.
 */

package gov.nasa.worldwindx.examples.util;

import gov.nasa.worldwind.*;
import gov.nasa.worldwind.layers.*;
import gov.nasa.worldwind.util.*;

import java.io.File;
import java.lang.reflect.Constructor;
import java.util.*;
import java.util.logging.Level;

/**
 * @author dcollins
 * @version $Id: SessionState.java 1171 2013-02-11 21:45:02Z dcollins $
 */
public class SessionState
{
    protected static class LayerStateFilename
    {
        protected String className;
        protected int index;

        public LayerStateFilename(String className, int index)
        {
            this.className = className;
            this.index = index;
        }
    }

    protected static final String VIEW_STATE_PATH = "SessionState/ViewState.xml";
    protected static final String LAYER_STATE_PATH = "SessionState/LayerState";
    protected static final String LAYER_STATE_FILENAME_DELIMITER = "-";
    protected static final Comparator LAYER_STATE_FILENAME_COMPARATOR = new Comparator()
    {
        @Override
        public int compare(String a, String b)
        {
            LayerStateFilename fna = parseLayerStateFilename(a);
            LayerStateFilename fnb = parseLayerStateFilename(b);

            if (fna == null || fnb == null)
                return fnb != null ? -1 : (fna != null ? 1 : 0);
            else
                return fna.index < fnb.index ? -1 : (fna.index > fnb.index ? 1 : 0);
        }
    };

    protected String sessionKey;

    public SessionState(String sessionKey)
    {
        if (WWUtil.isEmpty(sessionKey))
        {
            String msg = Logging.getMessage("nullValue.KeyIsNull");
            Logging.logger().severe(msg);
            throw new IllegalArgumentException(msg);
        }

        this.sessionKey = sessionKey;
    }

    public String getSessionKey()
    {
        return this.sessionKey;
    }

    public void saveSessionState(WorldWindow worldWindow)
    {
        if (worldWindow == null)
        {
            String msg = Logging.getMessage("nullValue.WorldWindow");
            Logging.logger().severe(msg);
            throw new IllegalArgumentException(msg);
        }

        this.saveViewState(worldWindow);
        this.saveLayerListState(worldWindow);
    }

    public void restoreSessionState(WorldWindow worldWindow)
    {
        if (worldWindow == null)
        {
            String msg = Logging.getMessage("nullValue.WorldWindow");
            Logging.logger().severe(msg);
            throw new IllegalArgumentException(msg);
        }

        this.restoreViewState(worldWindow);
        this.restoreLayerListState(worldWindow);
    }

    protected void saveViewState(WorldWindow worldWindow)
    {
        // There's nothing to save if the view is null. We treat this as an exceptional condition rather than a
        // supported case and leave the existing state file, if one exists.
        View view = worldWindow.getView();
        if (view == null)
            return;

        try
        {
            // There's nothing to do if the view does not provide restorable state. A null return value from
            // getRestorableState is valid, and indicates that the view does not support save/restore. We treat this as
            // an exceptional condition rather than a standard case and leave the existing state file, if one exists.
            String stateInXml = view.getRestorableState();
            if (WWUtil.isEmpty(stateInXml))
                return;

            // Save the View's restorable state XML to the view state path determined by this SessionState's session key
            // and the view state sub-path. This overwrites the contents of an existing state file, if any exists.
            WWIO.makeParentDirs(this.getViewStatePath());
            WWIO.writeTextFile(stateInXml, new File(this.getViewStatePath()));
        }
        catch (Exception e)
        {
            Logging.logger().log(Level.SEVERE, "Unable to save view state: " + view, e);
        }
    }

    protected void restoreViewState(WorldWindow worldWindow)
    {
        // There's nothing to restore if the view is null. We treat this as an exceptional condition rather than a
        // supported case and leave the existing state file, if one exists.
        View view = worldWindow.getView();
        if (view == null)
            return;

        // There's nothing to restore if the view state file does not exist.
        File stateFile = new File(this.getViewStatePath());
        if (!stateFile.exists())
            return;

        try
        {
            // Read the View's restorable state XML from the view state path determined by this SessionState's session
            // key and the view state sub-path.
            String stateInXml = WWIO.readTextFile(stateFile);
            if (WWUtil.isEmpty(stateInXml))
            {
                String msg = Logging.getMessage("nullValue.RestorableStateIsNull");
                Logging.logger().warning(msg);
                return;
            }

            worldWindow.getView().restoreState(stateInXml);
        }
        catch (Exception e)
        {
            Logging.logger().log(Level.SEVERE, "Unable to restore view state: " + stateFile, e);
        }
    }

    protected void saveLayerListState(WorldWindow worldWindow)
    {
        // There's nothing to save if the Model or the LayerList is null. We treat this as an exceptional condition
        // rather than a supported case and leave the existing state files, if any exist.
        if (worldWindow.getModel() == null || worldWindow.getModel().getLayers() == null)
            return;

        // Delete the contents of the layer state path directory, but not the directory itself.
        File stateFile = new File(this.getLayerStatePath());

        try
        {
            if (stateFile.exists())
                WWIO.deleteDirectory(stateFile);
            else
                stateFile.mkdirs();

            int index = 0;
            for (Layer layer : worldWindow.getModel().getLayers())
            {
                if (layer == null)
                    continue; // There's nothing to save if the Layer is null.

                String filename = composeLayerStateFilename(layer.getClass().getName(), index);
                this.saveLayerState(layer, new File(stateFile, filename));
                index++;
            }
        }
        catch (Exception e)
        {
            Logging.logger().log(Level.SEVERE, "Unable to save layer list state: " + stateFile, e);
        }
    }

    protected void restoreLayerListState(WorldWindow worldWindow)
    {
        // There's nothing to save if the Model or the LayerList is null. We treat this as an exceptional condition
        // rather than a supported case and leave the existing state files, if any exist.
        if (worldWindow.getModel() == null || worldWindow.getModel().getLayers() == null)
            return;

        File stateFile = new File(this.getLayerStatePath());

        String[] filenames = stateFile.list();
        if (filenames == null || filenames.length == 0)
            return;

        try
        {
            Arrays.sort(filenames, LAYER_STATE_FILENAME_COMPARATOR);
            LayerList layers = worldWindow.getModel().getLayers();

            for (String filename : filenames)
            {
                Layer layer = this.restoreLayerState(new File(stateFile, filename));
                if (layer == null)
                    continue;

                Layer existingLayer = this.findLayer(layers, layer.getName());
                if (existingLayer != null)
                    layers.remove(existingLayer);

                LayerStateFilename fn = parseLayerStateFilename(filename);
                if (fn != null && fn.index < layers.size())
                    layers.add(fn.index, layer);
                else
                    layers.add(layer);
            }
        }
        catch (Exception e)
        {
            Logging.logger().log(Level.SEVERE, "Unable to restore layer list state: " + stateFile, e);
        }
    }

    protected void saveLayerState(Layer layer, File stateFile)
    {
        try
        {
            // There's nothing to do if the Layer cannot be restored.
            if (!this.isLayerRestorable(layer))
                return;

            // There's nothing to do if the Layer does not provide restorable state. A null return value from
            // getRestorableState is valid, and indicates that the Layer does not support save/restore.
            String stateInXml = layer.getRestorableState();
            if (WWUtil.isEmpty(stateInXml))
                return;

            // Save the Layer's restorable state XML to the view state path determined by this SessionState's session
            // key and the layer state sub-path.
            WWIO.writeTextFile(stateInXml, stateFile);
        }
        catch (Exception e)
        {
            Logging.logger().log(Level.SEVERE, "Unable to save layer state: " + layer, e);
        }
    }

    protected Layer restoreLayerState(File stateFile)
    {
        try
        {
            // Read the Layer's restorable state XML from the layer state path determined by this SessionState's session
            // key and the layer state sub-path.
            String stateInXml = WWIO.readTextFile(stateFile);
            if (WWUtil.isEmpty(stateInXml))
            {
                String msg = Logging.getMessage("nullValue.RestorableStateIsNull");
                Logging.logger().warning(msg);
                return null;
            }

            // Get the Layer's class name fom its encoded filename.
            LayerStateFilename fn = parseLayerStateFilename(stateFile.getName());
            if (fn == null)
            {
                Logging.logger().warning("Invalid layer state filename: " + stateFile.getName());
                return null;
            }

            // Restore the Layer using a constructor that takes a restorable state XML string as its sole argument.
            Class c = Class.forName(fn.className);
            Constructor constructor = c.getConstructor(String.class);
            Object o = constructor.newInstance(stateInXml);

            return (o != null && o instanceof Layer) ? (Layer) o : null;
        }
        catch (Exception e)
        {
            Logging.logger().log(Level.SEVERE, "Unable to restore layer state: " + stateFile, e);
            return null;
        }
    }

    protected boolean isLayerRestorable(Layer layer)
    {
        try
        {
            if (layer.getClass().getConstructor(String.class) != null)
                return true;
        }
        catch (Exception e)
        {
            // Intentionally left blank. Class.getConstructor throws a NoSuchMethodError if the constructor does not
            // exist, in which case the return statement below is executed.
        }

        return false;
    }

    protected Layer findLayer(LayerList layers, String layerName)
    {
        if (layerName == null)
            return null;

        for (Layer layer : layers)
        {
            if (layer.getName() != null && layer.getName().equals(layerName))
                return layer;
        }

        return null;
    }

    protected String getSessionStatePath()
    {
        String appDataPath = Configuration.getCurrentUserAppDataDirectory();
        String sessionDataPath = this.getSessionKey();

        // The pattern for storing application data on all unix variants is to put those files in a hidden folder in the
        // current user's application data directory. Since the session key is our application data's folder name, we
        // ensure that it is hidden by inserting "." character at the beginning of the session key if one does not
        // already exist.
        if ((Configuration.isLinuxOS() || Configuration.isUnixOS() || Configuration.isSolarisOS())
            && !sessionDataPath.startsWith("."))
        {
            sessionDataPath = "." + sessionDataPath;
        }

        return WWIO.appendPathPart(appDataPath, sessionDataPath);
    }

    protected String getViewStatePath()
    {
        return WWIO.appendPathPart(this.getSessionStatePath(), VIEW_STATE_PATH);
    }

    protected String getLayerStatePath()
    {
        return WWIO.appendPathPart(this.getSessionStatePath(), LAYER_STATE_PATH);
    }

    protected static LayerStateFilename parseLayerStateFilename(String filename)
    {
        String filenameWithoutSuffix = WWIO.replaceSuffix(filename, "");
        String[] tokens = filenameWithoutSuffix.split(LAYER_STATE_FILENAME_DELIMITER);

        if (tokens == null || tokens.length < 2)
            return null;

        Integer index = WWUtil.makeInteger(tokens[0]);
        if (index == null)
            return null;

        String className = tokens[1].trim();

        return new LayerStateFilename(className, index);
    }

    protected static String composeLayerStateFilename(String className, int index)
    {
        StringBuilder sb = new StringBuilder();
        sb.append(index);
        sb.append(LAYER_STATE_FILENAME_DELIMITER);
        sb.append(className);
        sb.append(".xml");

        return sb.toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy