Package ca.eandb.util.jnlp

Source Code of ca.eandb.util.jnlp.PersistenceMap$Entry

/*
* Copyright (c) 2008 Bradley W. Kimmel
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/

package ca.eandb.util.jnlp;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;

import javax.jnlp.FileContents;
import javax.jnlp.PersistenceService;
import javax.jnlp.ServiceManager;
import javax.jnlp.UnavailableServiceException;

import ca.eandb.util.UnexpectedException;

/**
* A <code>Map</code> to be used by Java Web Start applications that
* persists its entries across invocations of the application using the JNLP
* <code>PersistenceService</code> service.
* @author Brad Kimmel
*/
public final class PersistenceMap extends AbstractMap<String, ByteBuffer> {

  /**
   * The root <code>URL</code> at which the map entries should be stored.
   */
  private final URL baseUrl;

  /**
   * The <code>PersistenceService</code> to use to load and store the map
   * entries.
   */
  private final PersistenceService service;

  /**
   * Creates a new <code>PersistenceMap</code>.
   * @param baseUrl The root <code>URL</code> at which the map entries should
   *     be stored.
   * @throws UnavailableServiceException If the
   *     <code>javax.jnlp.PersistenceService</code> service is unavailable.
   */
  public PersistenceMap(URL baseUrl) throws UnavailableServiceException {
    this(baseUrl, (PersistenceService) ServiceManager.lookup("javax.jnlp.PersistenceService"));
  }

  /**
   * Creates a new <code>PersistenceMap</code>.
   * @param baseUrl The root <code>URL</code> at which the map entries should
   *     be stored.
   * @param service The <code>PersistenceService</code> to use to load and
   *     store the map entries.
   */
  public PersistenceMap(URL baseUrl, PersistenceService service) {
    this.baseUrl = baseUrl;
    this.service = service;
  }

  /**
   * Gets the URL, relative to {@link #baseUrl}, at which to store an entry
   * with the given key.
   * @param key The key for which to obtain the associated URL.
   * @return The associated URL.
   */
  private static final String getEntryNameForKey(String key) {
    // FIXME Modify the key so that the result is a valid URL.
    return key;
  }

  /**
   * Gets the key associated with an entry stored at the given URL relative
   * to {@link #baseUrl}.
   * @param name The URL of the entry, relative to {@link #baseUrl}.
   * @return The associated key.
   */
  private static final String getKeyForEntryName(String name) {
    // TODO Perform inverse operation of getEntryNameForKey.
    return name;
  }

  /* (non-Javadoc)
   * @see java.util.AbstractMap#containsKey(java.lang.Object)
   */
  @Override
  public boolean containsKey(Object key) {
    return containsKey((String) key);
  }

  /**
   * Determine if this <code>PersistenceMap</code> contains an entry with the
   * given key.
   * @param key The key to look up.
   * @return A value indicating if an entry with the key <code>key</code> is
   *     stored in this <code>PersistenceMap</code>.
   */
  public boolean containsKey(String key) {
    try {
      URL url = new URL(baseUrl, getEntryNameForKey((String) key));
      return service.get(url) != null;
    } catch (Exception e) {
      return false;
    }
  }

  /**
   * Gets the <code>URL</code> at which to store the entry with the given
   * key.
   * @param key The key for which to get the <code>URL</code>.
   * @return The <code>URL</code> at which to store an entry with the given
   *     key.
   * @throws MalformedURLException If {@link #baseUrl} is inaccessible.
   */
  private URL getUrlForKey(Object key) throws MalformedURLException {
    return new URL(baseUrl, getEntryNameForKey((String) key));
  }

  /* (non-Javadoc)
   * @see java.util.AbstractMap#get(java.lang.Object)
   */
  @Override
  public ByteBuffer get(Object key) {
    return get((String) key);
  }

  /**
   * Gets an entry from the map.
   * @param key The key identifying the entry.
   * @return The <code>ByteBuffer</code> stored at the entry with the
   *     specified key.
   */
  public ByteBuffer get(String key) {

    try {

      URL url = getUrlForKey(key);
      FileContents contents = service.get(url);
      byte[] data = new byte[(int) contents.getLength()];
      InputStream in = contents.getInputStream();

      in.read(data);

      return ByteBuffer.wrap(data);

    } catch (FileNotFoundException e) {

      return null;

    } catch (Exception e) {

      e.printStackTrace();
      throw new RuntimeException(e);

    }

  }

  /* (non-Javadoc)
   * @see java.util.AbstractMap#put(java.lang.Object, java.lang.Object)
   */
  @Override
  public ByteBuffer put(String key, ByteBuffer value) {

    if (this.containsKey(key)) {
      this.remove(key);
    }

    try {

      URL url = getUrlForKey(key);

      value.reset();
      if (service.create(url, value.remaining()) < value.remaining()) {
        throw new RuntimeException("Could not allocate enough space in persistence store.");
      }

      FileContents contents = service.get(url);
      OutputStream out = contents.getOutputStream(true);
      byte[] data = new byte[value.remaining()];
      value.get(data);

      out.write(data);
      out.flush();
      out.close();

      return value;

    } catch (Exception e) {

      // TODO Auto-generated catch block
      e.printStackTrace();
      throw new RuntimeException("Failed to add item.", e);

    }

  }

  /* (non-Javadoc)
   * @see java.util.AbstractMap#remove(java.lang.Object)
   */
  @Override
  public ByteBuffer remove(Object key) {
    ByteBuffer value = this.get(key);
    this.remove((String) key);
    return value;
  }

  /**
   * Removes an entry from this map.
   * @param key The key identifying the entry to remove.
   */
  private void remove(String key) {

    try {

      String name = getEntryNameForKey(key);
      service.delete(new URL(baseUrl, name));

    } catch (MalformedURLException e) {

      /*
       * This should not happen, getEntryNameForKey should ensure that
       * the URL is valid.
       */
      e.printStackTrace();
      throw new UnexpectedException(e);

    } catch (IOException e) {

      /* Could not delete the entry. */
      e.printStackTrace();

    }

  }

  /* (non-Javadoc)
   * @see java.util.AbstractMap#entrySet()
   */
  @Override
  public Set<Map.Entry<String, ByteBuffer>> entrySet() {

    try {

      return new EntrySet(service.getNames(baseUrl));

    } catch (MalformedURLException e) {

      e.printStackTrace();
      throw new UnexpectedException(e);

    } catch (IOException e) {

      e.printStackTrace();

    }

    return new EntrySet();

  }

  /**
   * The <code>Set</code> of entries in a <code>PersistenceMap</code>.
   * @author Brad Kimmel
   */
  private final class EntrySet extends AbstractSet<Map.Entry<String, ByteBuffer>> {

    /** The <code>List</code> of the names of the entries. */
    private final List<String> names;

    /**
     * Creates an empty <code>EntrySet</code>.
     */
    public EntrySet() {
      this(new String[0]);
    }

    /**
     * Creates an <code>EntrySet</code> containing the entries named by
     * the elements of the given array.
     * @param names The names of the entries.
     */
    public EntrySet(String[] names) {
      this.names = Arrays.asList(names);
    }

    /* (non-Javadoc)
     * @see java.util.AbstractCollection#iterator()
     */
    @Override
    public Iterator<Map.Entry<String, ByteBuffer>> iterator() {

      return new Iterator<Map.Entry<String, ByteBuffer>>() {

        /**
         * The underlying <code>Iterator</code> used to iterate through
         * the names.
         */
        private final Iterator<String> iter = names.iterator();

        /**
         * The last <code>Entry</code> returned by {@link #next()}.
         */
        private Entry entry = null;

        /* (non-Javadoc)
         * @see java.util.Iterator#hasNext()
         */
        public boolean hasNext() {
          return iter.hasNext();
        }

        /* (non-Javadoc)
         * @see java.util.Iterator#next()
         */
        public Map.Entry<String, ByteBuffer> next() {
          try {
            String name = iter.next();
            String key = getKeyForEntryName(name);
            return (entry = new Entry(key));
          } catch (NoSuchElementException e) {
            entry = null;
            throw e;
          }
        }

        /* (non-Javadoc)
         * @see java.util.Iterator#remove()
         */
        public void remove() {
          if (entry != null) {
            PersistenceMap.this.remove(entry.getKey());
          } else {
            throw new IllegalStateException();
          }
        }

      };

    }

    /* (non-Javadoc)
     * @see java.util.AbstractCollection#size()
     */
    @Override
    public int size() {
      return names.size();
    }

  } // class EntrySet

  /**
   * A map entry in a <code>PersistenceMap</code>.
   * @author Brad Kimmel
   */
  private final class Entry implements Map.Entry<String, ByteBuffer> {

    /** The key identifying this entry. */
    private final String key;

    /**
     * Creates a new <code>Entry</code>.
     * @param key The key identifying this entry.
     */
    private Entry(String key) {
      this.key = key;
    }

    /* (non-Javadoc)
     * @see java.util.Map$Entry#getKey()
     */
    public String getKey() {
      return key;
    }

    /* (non-Javadoc)
     * @see java.util.Map$Entry#getValue()
     */
    public ByteBuffer getValue() {
      return PersistenceMap.this.get(key);
    }

    /* (non-Javadoc)
     * @see java.util.Map$Entry#setValue(java.lang.Object)
     */
    public ByteBuffer setValue(ByteBuffer value) {
      return PersistenceMap.this.put(key, value);
    }

  } // class Entry

}
TOP

Related Classes of ca.eandb.util.jnlp.PersistenceMap$Entry

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.