You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by gb...@apache.org on 2011/01/10 00:19:29 UTC
svn commit: r1057053 [4/12] - in /pivot/branches/3.x: ./ core/ core/src/
core/src/org/ core/src/org/apache/ core/src/org/apache/pivot/
core/src/org/apache/pivot/beans/ core/src/org/apache/pivot/bxml/
core/src/org/apache/pivot/csv/ core/src/org/apache/p...
Added: pivot/branches/3.x/core/src/org/apache/pivot/util/ListenerList.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/ListenerList.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/ListenerList.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/ListenerList.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,161 @@
+/*
+ * 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.pivot.util;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * Provides support for firing events to registered listeners.
+ */
+public abstract class ListenerList<T> {
+ // Node containing a listener in the list
+ private class Node {
+ private Node previous;
+ private Node next;
+ private T listener;
+
+ public Node(Node previous, Node next, T listener) {
+ this.previous = previous;
+ this.next = next;
+ this.listener = listener;
+ }
+ }
+
+ // Node iterator
+ private class NodeIterator implements Iterator<T> {
+ private Node node;
+
+ public NodeIterator() {
+ this.node = first;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return (node != null);
+ }
+
+ @Override
+ public T next() {
+ if (node == null) {
+ throw new NoSuchElementException();
+ }
+
+ T listener = node.listener;
+ node = node.next;
+
+ return listener;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ // First node in the list (we don't maintain a reference to the last
+ // node, since we need to walk the list looking for duplicates on add)
+ private Node first = null;
+
+ private Iterable<T> iterable = new Iterable<T>() {
+ public Iterator<T> iterator() {
+ return new NodeIterator();
+ }
+ };
+
+ /**
+ * Adds a listener to the list, if it has not previously been added.
+ *
+ * @param listener
+ */
+ public void add(T listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("listener is null.");
+ }
+
+ Node node = first;
+
+ if (node == null) {
+ first = new Node(null, null, listener);
+ } else {
+ while (node.next != null
+ && node.listener != listener) {
+ node = node.next;
+ }
+
+ if (node.next == null
+ && node.listener != listener) {
+ node.next = new Node(node, null, listener);
+ } else {
+ System.err.println("Duplicate listener " + listener + " added to " + this);
+ }
+ }
+ }
+
+ /**
+ * Removes a listener from the list, if it has previously been added.
+ *
+ * @param listener
+ */
+ public void remove(T listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("listener is null.");
+ }
+
+ Node node = first;
+ while (node != null
+ && node.listener != listener) {
+ node = node.next;
+ }
+
+ if (node == null) {
+ System.err.println("Nonexistent listener " + listener + " removed from " + this);
+ } else {
+ if (node.previous == null) {
+ first = node.next;
+
+ if (first != null) {
+ first.previous = null;
+ }
+ } else {
+ node.previous.next = node.next;
+
+ if (node.next != null) {
+ node.next.previous = node.previous;
+ }
+ }
+ }
+ }
+
+ /**
+ * Tests the emptiness of the list.
+ *
+ * @return
+ * <tt>true</tt> if the list contains no listeners; <tt>false</tt>,
+ * otherwise.
+ */
+ public boolean isEmpty() {
+ return (first == null);
+ }
+
+ /**
+ * Protected access to list contents; used by subclasses to fire events.
+ */
+ protected Iterable<T> listeners() {
+ return iterable;
+ }
+}
Added: pivot/branches/3.x/core/src/org/apache/pivot/util/MessageBus.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/MessageBus.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/MessageBus.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/MessageBus.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,90 @@
+/*
+ * 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.pivot.util;
+
+import java.util.HashMap;
+
+/**
+ * Provides support for basic intra-application message passing.
+ */
+public class MessageBus {
+ private static class TopicListenerList<T> extends ListenerList<MessageBusListener<T>>
+ implements MessageBusListener<T> {
+ @Override
+ public void messageSent(T message) {
+ for (MessageBusListener<T> listener : listeners()) {
+ listener.messageSent(message);
+ }
+ }
+ }
+
+ private static HashMap<Class<?>, TopicListenerList<?>> messageTopics =
+ new HashMap<Class<?>, TopicListenerList<?>>();
+
+ /**
+ * Subscribes a listener to a message topic.
+ *
+ * @param topic
+ * @param messageListener
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> void subscribe(Class<? super T> topic, MessageBusListener<T> messageListener) {
+ TopicListenerList<T> topicListeners = (TopicListenerList<T>)messageTopics.get(topic);
+
+ if (topicListeners == null) {
+ topicListeners = new TopicListenerList<T>() {};
+ messageTopics.put(topic, topicListeners);
+ }
+
+ topicListeners.add(messageListener);
+ }
+
+ /**
+ * Unsubscribes a listener from a message topic.
+ *
+ * @param topic
+ * @param messageListener
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> void unsubscribe(Class<? super T> topic, MessageBusListener<T> messageListener) {
+ TopicListenerList<T> topicListeners = (TopicListenerList<T>)messageTopics.get(topic);
+
+ if (topicListeners == null) {
+ throw new IllegalArgumentException(topic.getName() + " does not exist.");
+ }
+
+ topicListeners.remove(messageListener);
+ if (topicListeners.isEmpty()) {
+ messageTopics.remove(topic);
+ }
+ }
+
+ /**
+ * Sends a message to subscribed topic listeners.
+ *
+ * @param message
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> void sendMessage(T message) {
+ Class<?> topic = message.getClass();
+ TopicListenerList<T> topicListeners = (TopicListenerList<T>)messageTopics.get(topic);
+
+ if (topicListeners != null) {
+ topicListeners.messageSent(message);
+ }
+ }
+}
Added: pivot/branches/3.x/core/src/org/apache/pivot/util/MessageBusListener.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/MessageBusListener.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/MessageBusListener.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/MessageBusListener.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,29 @@
+/*
+ * 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.pivot.util;
+
+/**
+ * Message bus listener interface.
+ */
+public interface MessageBusListener<T> {
+ /**
+ * Called when a message has been sent via {@link MessageBus#sendMessage(Object)}.
+ *
+ * @param message
+ */
+ public void messageSent(T message);
+}
Added: pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableList.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableList.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableList.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableList.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,60 @@
+/*
+ * 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.pivot.util;
+
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * A list that fires events when its content changes.
+ */
+public interface ObservableList<E> extends List<E> {
+ /**
+ * Observable list listener list.
+ */
+ public static class ObservableListListenerList<E>
+ extends ListenerList<ObservableListListener<E>>
+ implements ObservableListListener<E> {
+ @Override
+ public void elementsAdded(ObservableList<E> list, int fromIndex, int toIndex) {
+ for (ObservableListListener<E> listener : listeners()) {
+ listener.elementsAdded(list, fromIndex, toIndex);
+ }
+ }
+
+ @Override
+ public void elementsRemoved(ObservableList<E> list, int fromIndex, List<E> elements) {
+ for (ObservableListListener<E> listener : listeners()) {
+ listener.elementsRemoved(list, fromIndex, elements);
+ }
+ }
+
+ @Override
+ public void elementsUpdated(ObservableList<E> list, int fromIndex, List<E> previousElements) {
+ for (ObservableListListener<E> listener : listeners()) {
+ listener.elementsUpdated(list, fromIndex, previousElements);
+ }
+ }
+ }
+
+ public List<E> setAll(int index, Collection<? extends E> collection);
+
+ public void sort(Comparator<E> comparator);
+
+ public ListenerList<ObservableListListener<E>> getObservableListListeners();
+}
Added: pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableListAdapter.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableListAdapter.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableListAdapter.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableListAdapter.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,147 @@
+/*
+ * 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.pivot.util;
+
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Observable list that is backed by an instance of {@link List}.
+ */
+public class ObservableListAdapter<E> extends AbstractList<E>
+ implements ObservableList<E> {
+ private List<E> list;
+ private ObservableListListenerList<E> observableListListeners =
+ new ObservableListListenerList<E>();
+
+ public ObservableListAdapter(List<E> list) {
+ if (list == null) {
+ throw new IllegalArgumentException();
+ }
+
+ this.list = list;
+ }
+
+ public List<E> getList() {
+ return list;
+ }
+
+ @Override
+ public void add(int index, E element) {
+ list.add(index, element);
+
+ observableListListeners.elementsAdded(this, index, index + 1);
+ }
+
+ @Override
+ public boolean addAll(int index, Collection<? extends E> collection) {
+ boolean added = list.addAll(index, collection);
+
+ if (added) {
+ observableListListeners.elementsAdded(this, index,
+ index + collection.size());
+ }
+
+ return added;
+ }
+
+ @Override
+ public E remove(int index) {
+ E element = list.remove(index);
+ observableListListeners.elementsRemoved(this, index,
+ Collections.singletonList(element));
+
+ return element;
+ }
+
+ @Override
+ protected void removeRange(int fromIndex, int toIndex) {
+ List<E> subList = list.subList(fromIndex, toIndex);
+ List<E> removed = new ArrayList<E>(subList);
+ subList.clear();
+
+ observableListListeners.elementsRemoved(this, fromIndex, removed);
+ }
+
+ @Override
+ public E get(int index) {
+ return list.get(index);
+ }
+
+ @Override
+ public E set(int index, E element) {
+ E previousElement = list.set(index, element);
+ observableListListeners.elementsUpdated(this, index,
+ Collections.singletonList(previousElement));
+
+ return previousElement;
+ }
+
+ @Override
+ public List<E> setAll(int index, Collection<? extends E> collection) {
+ ArrayList<E> previousElements = new ArrayList<E>(collection.size());
+
+ int i = index;
+ for (E element : collection) {
+ list.set(i++, element);
+ previousElements.add(element);
+ }
+
+ observableListListeners.elementsUpdated(this, index, previousElements);
+
+ return previousElements;
+ }
+
+ @Override
+ public void sort(Comparator<E> comparator) {
+ Collections.sort(list, comparator);
+ observableListListeners.elementsUpdated(this, 0, this);
+ }
+
+ @Override
+ public int size() {
+ return list.size();
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ return list.equals(object);
+ }
+
+ @Override
+ public int hashCode() {
+ return list.hashCode();
+ }
+
+ @Override
+ public ListenerList<ObservableListListener<E>> getObservableListListeners() {
+ return observableListListeners;
+ }
+
+ public static <E> ObservableList<E> observableArrayList() {
+ return new ObservableListAdapter<E>(new ArrayList<E>());
+ }
+
+ public static <E> ObservableList<E> observableLinkedList() {
+ return new ObservableListAdapter<E>(new LinkedList<E>());
+ }
+}
Added: pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableListListener.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableListListener.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableListListener.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableListListener.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,47 @@
+/*
+ * 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.pivot.util;
+
+import java.util.List;
+
+/**
+ * Observable list listener interface.
+ *
+ * @param <E>
+ */
+public interface ObservableListListener<E> {
+ /**
+ * Observable list listener adapter.
+ */
+ public static class Adapter<E> implements ObservableListListener<E> {
+ @Override
+ public void elementsAdded(ObservableList<E> list, int fromIndex, int toIndex) {
+ }
+
+ @Override
+ public void elementsRemoved(ObservableList<E> list, int fromIndex, List<E> elements) {
+ }
+
+ @Override
+ public void elementsUpdated(ObservableList<E> list, int fromIndex, List<E> previousElements) {
+ }
+ }
+
+ public void elementsAdded(ObservableList<E> list, int fromIndex, int toIndex);
+ public void elementsRemoved(ObservableList<E> list, int fromIndex, List<E> elements);
+ public void elementsUpdated(ObservableList<E> list, int fromIndex, List<E> previousElements);
+}
Added: pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableMap.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableMap.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableMap.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableMap.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,54 @@
+/*
+ * 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.pivot.util;
+
+import java.util.Map;
+
+/**
+ * A map that fires events when its content changes.
+ */
+public interface ObservableMap<K, V> extends Map<K, V> {
+ /**
+ * Observable map listener list.
+ */
+ public static class ObservableMapListenerList<K, V>
+ extends ListenerList<ObservableMapListener<K, V>>
+ implements ObservableMapListener<K, V> {
+ @Override
+ public void valueAdded(ObservableMap<K, V> map, K key) {
+ for (ObservableMapListener<K, V> listener : listeners()) {
+ listener.valueAdded(map, key);
+ }
+ }
+
+ @Override
+ public void valueUpdated(ObservableMap<K, V> map, K key, V previousValue) {
+ for (ObservableMapListener<K, V> listener : listeners()) {
+ listener.valueUpdated(map, key, previousValue);
+ }
+ }
+
+ @Override
+ public void valueRemoved(ObservableMap<K, V> map, Object key, V value) {
+ for (ObservableMapListener<K, V> listener : listeners()) {
+ listener.valueRemoved(map, key, value);
+ }
+ }
+ }
+
+ public ListenerList<ObservableMapListener<K, V>> getObservableMapListeners();
+}
Added: pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableMapAdapter.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableMapAdapter.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableMapAdapter.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableMapAdapter.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,196 @@
+/*
+ * 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.pivot.util;
+
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Observable map that is backed by an instance of {@link Map}.
+ */
+public class ObservableMapAdapter<K, V> extends AbstractMap<K, V>
+ implements ObservableMap<K, V> {
+ private class ObservableMapEntrySet extends AbstractSet<Entry<K, V>> {
+ @Override
+ public int size() {
+ return map.size();
+ }
+
+ @Override
+ public Iterator<Entry<K, V>> iterator() {
+ return new ObservableMapEntrySetIterator(map.entrySet().iterator());
+ }
+ }
+
+ private class ObservableMapEntrySetIterator implements Iterator<Entry<K, V>> {
+ private Iterator<Entry<K, V>> iterator;
+ private ObservableMapEntry entry = null;
+
+ public ObservableMapEntrySetIterator(Iterator<Entry<K, V>> iterator) {
+ this.iterator = iterator;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public Entry<K, V> next() {
+ entry = new ObservableMapEntry(iterator.next());
+ return entry;
+ }
+
+ @Override
+ public void remove() {
+ if (entry == null) {
+ throw new IllegalStateException();
+ }
+
+ iterator.remove();
+
+ observableMapListeners.valueRemoved(ObservableMapAdapter.this,
+ entry.getKey(), entry.getValue());
+
+ entry = null;
+ }
+ }
+
+ private class ObservableMapEntry implements Entry<K, V> {
+ private Entry<K, V> entry;
+
+ public ObservableMapEntry(Entry<K, V> entry) {
+ this.entry = entry;
+ }
+
+ @Override
+ public K getKey() {
+ return entry.getKey();
+ }
+
+ @Override
+ public V getValue() {
+ return entry.getValue();
+ }
+
+ @Override
+ public V setValue(V value) {
+ V previousValue = entry.setValue(value);
+
+ observableMapListeners.valueUpdated(ObservableMapAdapter.this,
+ getKey(), previousValue);
+
+ return previousValue;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ return entry.equals(object);
+ }
+
+ @Override
+ public int hashCode() {
+ return entry.hashCode();
+ }
+ }
+
+ private Map<K, V> map;
+ private ObservableMapEntrySet entrySet = new ObservableMapEntrySet();
+ private ObservableMapListenerList<K, V> observableMapListeners =
+ new ObservableMapListenerList<K, V>();
+
+ public ObservableMapAdapter(Map<K, V> map) {
+ if (map == null) {
+ throw new IllegalArgumentException();
+ }
+
+ this.map = map;
+ }
+
+ public Map<K, V> getMap() {
+ return map;
+ }
+
+ @Override
+ public V get(Object key) {
+ return map.get(key);
+ }
+
+ @Override
+ public V put(K key, V value) {
+ boolean update = containsKey(key);
+ V previousValue = map.put(key, value);
+
+ if (update) {
+ observableMapListeners.valueUpdated(this, key, previousValue);
+ } else {
+ observableMapListeners.valueAdded(this, key);
+ }
+
+ return previousValue;
+ }
+
+ @Override
+ public V remove(Object key) {
+ V value = null;
+
+ if (containsKey(key)) {
+ value = map.remove(key);
+ observableMapListeners.valueRemoved(this, key, value);
+ }
+
+ return value;
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ return map.containsKey(key);
+ }
+
+ @Override
+ public int size() {
+ return map.size();
+ }
+
+ @Override
+ public Set<Entry<K, V>> entrySet() {
+ return entrySet;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ return map.equals(object);
+ }
+
+ @Override
+ public int hashCode() {
+ return map.hashCode();
+ }
+
+ @Override
+ public ListenerList<ObservableMapListener<K, V>> getObservableMapListeners() {
+ return observableMapListeners;
+ }
+
+ public static <K, V> ObservableMapAdapter<K, V> observableHashMap() {
+ return new ObservableMapAdapter<K, V>(new HashMap<K, V>());
+ }
+}
Added: pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableMapListener.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableMapListener.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableMapListener.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableMapListener.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,43 @@
+/*
+ * 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.pivot.util;
+
+/**
+ * Observable map listener interface.
+ */
+public interface ObservableMapListener<K, V> {
+ /**
+ * Observable map listener adapter.
+ */
+ public static class Adapter<K, V> implements ObservableMapListener<K, V> {
+ @Override
+ public void valueAdded(ObservableMap<K, V> map, K key) {
+ }
+
+ @Override
+ public void valueUpdated(ObservableMap<K, V> map, K key, V previousValue) {
+ }
+
+ @Override
+ public void valueRemoved(ObservableMap<K, V> map, Object key, V value) {
+ }
+ }
+
+ public void valueAdded(ObservableMap<K, V> map, K key);
+ public void valueUpdated(ObservableMap<K, V> map, K key, V previousValue);
+ public void valueRemoved(ObservableMap<K, V> map, Object key, V value);
+}
Added: pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableSet.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableSet.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableSet.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableSet.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,45 @@
+/*
+ * 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.pivot.util;
+
+import java.util.Set;
+
+/**
+ * A set that fires events when its content changes.
+ */
+public interface ObservableSet<E> extends Set<E> {
+ /**
+ * Observable set listener list.
+ */
+ public static class ObservableSetListenerList<E>
+ extends ListenerList<ObservableSetListener<E>>
+ implements ObservableSetListener<E> {
+ public void elementAdded(ObservableSet<E> set, E element) {
+ for (ObservableSetListener<E> listener : listeners()) {
+ listener.elementAdded(set, element);
+ }
+ }
+
+ public void elementRemoved(ObservableSet<E> set, Object element) {
+ for (ObservableSetListener<E> listener : listeners()) {
+ listener.elementRemoved(set, element);
+ }
+ }
+ }
+
+ public ListenerList<ObservableSetListener<E>> getObservableSetListeners();
+}
Added: pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableSetAdapter.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableSetAdapter.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableSetAdapter.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableSetAdapter.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,134 @@
+/*
+ * 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.pivot.util;
+
+import java.util.AbstractSet;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * Observable set that is backed by an instance of {@link Set}.
+ */
+public class ObservableSetAdapter<E> extends AbstractSet<E>
+ implements ObservableSet<E> {
+ private class ObservableSetIterator implements Iterator<E> {
+ private Iterator<E> iterator;
+ private E element = null;
+
+ public ObservableSetIterator(Iterator<E> iterator) {
+ this.iterator = iterator;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public E next() {
+ element = iterator.next();
+ return element;
+ }
+
+ @Override
+ public void remove() {
+ if (element == null) {
+ throw new IllegalStateException();
+ }
+
+ iterator.remove();
+
+ observableSetListeners.elementRemoved(ObservableSetAdapter.this,
+ element);
+
+ element = null;
+ }
+ }
+
+ private Set<E> set;
+ private ObservableSetListenerList<E> observableSetListeners =
+ new ObservableSetListenerList<E>();
+
+ public ObservableSetAdapter(Set<E> set) {
+ if (set == null) {
+ throw new IllegalArgumentException();
+ }
+
+ this.set = set;
+ }
+
+ public Set<E> getSet() {
+ return set;
+ }
+
+ @Override
+ public boolean add(E element) {
+ boolean added = set.add(element);
+
+ if (added) {
+ observableSetListeners.elementAdded(this, element);
+ }
+
+ return added;
+ }
+
+ @Override
+ public boolean remove(Object element) {
+ boolean removed = set.remove(element);
+
+ if (removed) {
+ observableSetListeners.elementRemoved(this, element);
+ }
+
+ return removed;
+ }
+
+ @Override
+ public boolean contains(Object element) {
+ return set.contains(element);
+ }
+
+ @Override
+ public int size() {
+ return set.size();
+ }
+
+ @Override
+ public Iterator<E> iterator() {
+ return new ObservableSetIterator(set.iterator());
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ return set.equals(object);
+ }
+
+ @Override
+ public int hashCode() {
+ return set.hashCode();
+ }
+
+ @Override
+ public ListenerList<ObservableSetListener<E>> getObservableSetListeners() {
+ return observableSetListeners;
+ }
+
+ public static <E> ObservableSet<E> observableHashSet() {
+ return new ObservableSetAdapter<E>(new HashSet<E>());
+ }
+}
Added: pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableSetListener.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableSetListener.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableSetListener.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/ObservableSetListener.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,38 @@
+/*
+ * 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.pivot.util;
+
+/**
+ * Observable set listener interface.
+ */
+public interface ObservableSetListener<E> {
+ /**
+ * Observable set listener adapter.
+ */
+ public static class Adapter<E> implements ObservableSetListener<E> {
+ @Override
+ public void elementAdded(ObservableSet<E> set, E element) {
+ }
+
+ @Override
+ public void elementRemoved(ObservableSet<E> set, Object element) {
+ }
+ }
+
+ public void elementAdded(ObservableSet<E> set, E element);
+ public void elementRemoved(ObservableSet<E> set, Object element);
+}
Added: pivot/branches/3.x/core/src/org/apache/pivot/util/ReferenceCountedMap.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/ReferenceCountedMap.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/ReferenceCountedMap.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/ReferenceCountedMap.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,249 @@
+/*
+ * 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.pivot.util;
+
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * Map that maintains a reference-counted list of entries. When values are
+ * retrieved from the map, the reference count is incremented. When values
+ * are removed, the reference count is decremented. The value is removed
+ * from the map when the reference count reaches zero.
+ * <p>
+ * Internally, the map is backed by an instance of {@link HashMap}.
+ *
+ * @param <K>
+ * @param <V>
+ */
+public class ReferenceCountedMap<K, V> extends AbstractMap<K, V> {
+ /**
+ * Internal reference counter.
+ *
+ * @param <V>
+ */
+ private static class ReferenceCounter<V> {
+ public V value;
+ public int referenceCount = 0;
+
+ public ReferenceCounter(V value) {
+ this.value = value;
+ }
+ }
+
+ /**
+ * Reference-counted entry set.
+ */
+ private class ReferenceCountedMapEntrySet extends AbstractSet<Entry<K, V>> {
+ @Override
+ public int size() {
+ return map.size();
+ }
+
+ @Override
+ public Iterator<Entry<K, V>> iterator() {
+ return new ReferenceCountedEntrySetIterator(map.entrySet().iterator());
+ }
+ }
+
+ /**
+ * Reference-counted entry set iterator.
+ */
+ private class ReferenceCountedEntrySetIterator implements Iterator<Entry<K, V>> {
+ private Iterator<Entry<K, ReferenceCounter<V>>> iterator;
+ private ReferenceCountedMapEntry entry = null;
+
+ public ReferenceCountedEntrySetIterator(Iterator<Entry<K, ReferenceCounter<V>>> iterator) {
+ this.iterator = iterator;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public Entry<K, V> next() {
+ entry = new ReferenceCountedMapEntry(iterator.next());
+ return entry;
+ }
+
+ @Override
+ public void remove() {
+ if (entry == null) {
+ throw new IllegalStateException();
+ }
+
+ iterator.remove();
+
+ entry = null;
+ }
+ }
+
+ /**
+ * Reference-counted entry.
+ */
+ private class ReferenceCountedMapEntry implements Entry<K, V> {
+ private Entry<K, ReferenceCounter<V>> entry;
+
+ public ReferenceCountedMapEntry(Entry<K, ReferenceCounter<V>> entry) {
+ this.entry = entry;
+ }
+
+ @Override
+ public K getKey() {
+ return entry.getKey();
+ }
+
+ @Override
+ public V getValue() {
+ ReferenceCounter<V> referenceCounter = entry.getValue();
+ referenceCounter.referenceCount++;
+
+ return referenceCounter.value;
+ }
+
+ @Override
+ public V setValue(V value) {
+ ReferenceCounter<V> referenceCounter = entry.getValue();
+ referenceCounter.referenceCount = 0;
+
+ V previousValue = referenceCounter.value;
+ referenceCounter.value = value;
+
+ return previousValue;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ return entry.equals(object);
+ }
+
+ @Override
+ public int hashCode() {
+ return entry.hashCode();
+ }
+ }
+
+ private HashMap<K, ReferenceCounter<V>> map = new HashMap<K, ReferenceCounter<V>>();
+ private ReferenceCountedMapEntrySet entrySet = new ReferenceCountedMapEntrySet();
+
+ @Override
+ public V get(Object key) {
+ // Return the value and increment the reference count
+ ReferenceCounter<V> referenceCounter = map.get(key);
+
+ V value;
+ if (referenceCounter != null) {
+ referenceCounter.referenceCount++;
+ value = referenceCounter.value;
+ } else {
+ value = null;
+ }
+
+ return value;
+ }
+
+ @Override
+ public V put(K key, V value) {
+ // Add a new reference counter with no initial references
+ ReferenceCounter<V> previousReferenceCounter = map.put(key, new ReferenceCounter<V>(value));
+
+ V previousValue;
+ if (previousReferenceCounter != null) {
+ previousValue = previousReferenceCounter.value;
+ } else {
+ previousValue = null;
+ }
+
+ return previousValue;
+ }
+
+ @Override
+ public V remove(Object key) {
+ // Decremement the reference count, or remove the entry if no
+ // references remain; only return a value when the entry has
+ // actually been removed
+ ReferenceCounter<V> referenceCounter = map.get(key);
+
+ V value;
+ if (referenceCounter != null) {
+ if (referenceCounter.referenceCount == 0) {
+ map.remove(key);
+ value = referenceCounter.value;
+ } else {
+ referenceCounter.referenceCount--;
+ value = null;
+ }
+ } else {
+ value = null;
+ }
+
+ return value;
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ return map.containsKey(key);
+ }
+
+ /**
+ * Returns the reference count for an entry.
+ *
+ * @param key
+ *
+ * @return
+ * The current reference count for the given entry, or <tt>0</tt> if the
+ * entry does not exist in the map. {@link #containsKey(Object)} can be
+ * used to distinguish between these two cases.
+ */
+ public int countOf(K key) {
+ ReferenceCounter<V> referenceCounter = map.get(key);
+
+ int count;
+ if (referenceCounter != null) {
+ count = referenceCounter.referenceCount;
+ } else {
+ count = 0;
+ }
+
+ return count;
+ }
+
+ @Override
+ public int size() {
+ return map.size();
+ }
+
+ @Override
+ public Set<Entry<K, V>> entrySet() {
+ return entrySet;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ return map.equals(object);
+ }
+
+ @Override
+ public int hashCode() {
+ return map.hashCode();
+ }
+}
Added: pivot/branches/3.x/core/src/org/apache/pivot/util/Resources.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/Resources.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/Resources.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/Resources.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,212 @@
+/*
+ * 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.pivot.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.Charset;
+import java.util.AbstractMap;
+import java.util.Collections;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.Properties;
+import java.util.Set;
+
+/**
+ * Represents a set of localizable resources.
+ */
+public class Resources extends AbstractMap<String, String> {
+ private final Resources parent;
+ private final String baseName;
+ private final Locale locale;
+ private final Charset charset;
+
+ private Properties properties = null;
+
+ public static final String DEFAULT_CHARSET_NAME = "UTF-8";
+ public static final String PROPERTIES_EXTENSION = "properties";
+ public static final int BUFFER_SIZE = 2048;
+
+ public Resources(String baseName) throws IOException {
+ this(baseName, Locale.getDefault());
+ }
+
+ public Resources(String baseName, Locale locale) throws IOException {
+ this(baseName, locale, Charset.forName(DEFAULT_CHARSET_NAME));
+ }
+
+ public Resources(String baseName, Charset charset) throws IOException {
+ this(baseName, Locale.getDefault(), charset);
+ }
+
+ public Resources(String baseName, Locale locale, Charset charset) throws IOException {
+ this(null, baseName, locale, charset);
+ }
+
+ public Resources(Resources parent, String baseName) throws IOException {
+ this(parent, baseName, Locale.getDefault());
+ }
+
+ public Resources(Resources parent, String baseName, Locale locale) throws IOException {
+ this(parent, baseName, locale, Charset.forName(DEFAULT_CHARSET_NAME));
+ }
+
+ public Resources(Resources parent, String baseName, Charset charset) throws IOException {
+ this(parent, baseName, Locale.getDefault(), charset);
+ }
+
+ /**
+ * Creates a new resource bundle.
+ *
+ * @param parent
+ * The parent resource bundle. If a resource value cannot be located in
+ * this resource bundle, the parent bundle will be searched. May be
+ * <tt>null</tt> to specify no parent.
+ *
+ * @param baseName
+ * The base name of this resource bundle, as a fully qualified class name.
+ *
+ * @param locale
+ * The locale to use when loading this resource bundle.
+ *
+ * @param charset
+ * The character encoding to use when reading this resource bundle.
+ */
+ public Resources(Resources parent, String baseName, Locale locale, Charset charset)
+ throws IOException {
+ if (baseName == null) {
+ throw new IllegalArgumentException("baseName is null");
+ }
+
+ if (locale == null) {
+ throw new IllegalArgumentException("locale is null");
+ }
+
+ if (charset == null) {
+ throw new IllegalArgumentException("charset is null.");
+ }
+
+ if (parent != null
+ && !parent.locale.equals(locale)) {
+ throw new IllegalArgumentException("Parent locale is not the same as locale.");
+ }
+
+ this.parent = parent;
+ this.baseName = baseName;
+ this.locale = locale;
+ this.charset = charset;
+
+ String resourceName = baseName.replace('.', '/');
+ properties = readProperties(resourceName + "." + PROPERTIES_EXTENSION);
+
+ // Look for language-specific properties
+ Properties languageOverrides = readProperties(resourceName + "_" + locale.getLanguage()
+ + "." + PROPERTIES_EXTENSION);
+ if (languageOverrides != null) {
+ applyOverrides(languageOverrides);
+ }
+
+ // Look for region-specific properties
+ Properties regionOverrides = readProperties(resourceName + "_" + locale.toString()
+ + "." + PROPERTIES_EXTENSION);
+ if (regionOverrides != null) {
+ applyOverrides(regionOverrides);
+ }
+
+ if (properties == null) {
+ throw new MissingResourceException("Can't find resources for \"" + baseName + "\".",
+ null, null);
+ }
+ }
+
+ public Resources getParent() {
+ return parent;
+ }
+
+ public String getBaseName() {
+ return baseName;
+ }
+
+ public Locale getLocale() {
+ return locale;
+ }
+
+ public Charset getCharset() {
+ return charset;
+ }
+
+ @Override
+ public String get(Object key) {
+ return (properties.containsKey(key)) ?
+ (String)properties.get(key) : (parent == null) ? null : parent.get(key);
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ return properties.containsKey(key);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Set<String> keySet() {
+ Set<?> keys = Collections.unmodifiableSet(properties.keySet());
+ return (Set<String>)keys;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Set<Map.Entry<String, String>> entrySet() {
+ Set<?> entries = Collections.unmodifiableSet(properties.entrySet());
+ return (Set<Map.Entry<String, String>>)entries;
+ }
+
+ private Properties readProperties(String resourceName) throws IOException {
+ Properties properties = null;
+
+ ClassLoader classLoader = getClass().getClassLoader();
+ InputStream inputStream = classLoader.getResourceAsStream(resourceName);
+
+ if (inputStream != null) {
+ Reader reader = new BufferedReader(new InputStreamReader(inputStream, charset), BUFFER_SIZE);
+
+ properties = new Properties();
+ try {
+ properties.load(reader);
+ } finally {
+ reader.close();
+ }
+ }
+
+ return properties;
+ }
+
+ private void applyOverrides(Properties overrides) {
+ if (properties == null) {
+ properties = overrides;
+ } else {
+ for (Object key : overrides.keySet()) {
+ if (properties.containsKey(key)) {
+ properties.put(key, overrides.get(key));
+ }
+ }
+ }
+ }
+}
Added: pivot/branches/3.x/core/src/org/apache/pivot/util/Service.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/Service.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/Service.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/Service.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,106 @@
+/*
+ * 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.pivot.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+/**
+ * Utility class for locating and instantiating service providers.
+ */
+public class Service {
+ /**
+ * Attempts to load a service provider.
+ *
+ * @param providerName
+ * The name of the provider to load. The method first looks for a system
+ * property with this name. The value of the property is expected to be the
+ * name of a class that implements the expected provider interface.
+ * <p>
+ * If the system property does not exist, the method then attempts to load
+ * a resource with this name from the META-INF/services directory. The
+ * resource is expected to be a text file containing a single line that is
+ * the name of the provider class.
+ */
+ public static Object getProvider(String providerName) {
+ String providerClassName = null;
+
+ // First look for a system property
+ try {
+ providerClassName = System.getProperty(providerName);
+ } catch(SecurityException exception) {
+ // No-op
+ }
+
+ // Next look for a service descriptor on the classpath
+ if (providerClassName == null) {
+ String serviceName = "META-INF/services/" + providerName;
+
+ ClassLoader classLoader = Service.class.getClassLoader();
+ InputStream serviceInputStream = classLoader.getResourceAsStream(serviceName);
+
+ if (serviceInputStream != null) {
+ try {
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new InputStreamReader(serviceInputStream, "UTF-8"));
+ String line = reader.readLine();
+ while (line != null
+ && (line.length() == 0
+ || line.startsWith("#"))) {
+ line = reader.readLine();
+ }
+
+ providerClassName = line;
+ } finally {
+ if (reader != null) {
+ reader.close();
+ }
+ }
+ } catch(IOException exception) {
+ // No-op
+ }
+ }
+ }
+
+ // Try to load the provider class
+ Class<?> providerClass = null;
+
+ if (providerClassName != null) {
+ try {
+ providerClass = Class.forName(providerClassName);
+ } catch(ClassNotFoundException exception) {
+ // The specified class could not be found
+ }
+ }
+
+ Object provider = null;
+ if (providerClass != null) {
+ try {
+ provider = providerClass.newInstance();
+ } catch(InstantiationException exception) {
+ // No-op
+ } catch(IllegalAccessException exception) {
+ // No-op
+ }
+ }
+
+ return provider;
+ }
+}
Added: pivot/branches/3.x/core/src/org/apache/pivot/util/Time.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/Time.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/Time.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/Time.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,353 @@
+/*
+ * 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.pivot.util;
+
+import java.io.Serializable;
+import java.text.NumberFormat;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Class representing a time of day, independent of any particular time zone.
+ */
+public final class Time implements Comparable<Time>, Serializable {
+ private static final long serialVersionUID = 0;
+
+ /**
+ * Represents a range of times.
+ */
+ public static final class Range {
+ public final Time start;
+ public final Time end;
+
+ public Range(Time time) {
+ this(time, time);
+ }
+
+ public Range(Time start, Time end) {
+ this.start = start;
+ this.end = end;
+ }
+
+ public Range(String start, String end) {
+ this.start = Time.decode(start);
+ this.end = Time.decode(end);
+ }
+
+ public Range(Range range) {
+ if (range == null) {
+ throw new IllegalArgumentException("range is null.");
+ }
+
+ start = range.start;
+ end = range.end;
+ }
+
+ public int getLength() {
+ return Math.abs(start.subtract(end)) + 1;
+ }
+
+ public boolean contains(Range range) {
+ if (range == null) {
+ throw new IllegalArgumentException("range is null.");
+ }
+
+ Range normalizedRange = range.normalize();
+
+ boolean contains;
+ if (start.compareTo(end) < 0) {
+ contains = (start.compareTo(normalizedRange.start) <= 0
+ && end.compareTo(normalizedRange.end) >= 0);
+ } else {
+ contains = (end.compareTo(normalizedRange.start) <= 0
+ && start.compareTo(normalizedRange.end) >= 0);
+ }
+
+ return contains;
+ }
+
+ public boolean contains(Time time) {
+ if (time == null) {
+ throw new IllegalArgumentException("time is null.");
+ }
+
+ boolean contains;
+ if (start.compareTo(end) < 0) {
+ contains = (start.compareTo(time) <= 0
+ && end.compareTo(time) >= 0);
+ } else {
+ contains = (end.compareTo(time) <= 0
+ && start.compareTo(time) >= 0);
+ }
+
+ return contains;
+ }
+
+ public boolean intersects(Range range) {
+ if (range == null) {
+ throw new IllegalArgumentException("range is null.");
+ }
+
+ Range normalizedRange = range.normalize();
+
+ boolean intersects;
+ if (start.compareTo(end) < 0) {
+ intersects = (start.compareTo(normalizedRange.end) <= 0
+ && end.compareTo(normalizedRange.start) >= 0);
+ } else {
+ intersects = (end.compareTo(normalizedRange.end) <= 0
+ && start.compareTo(normalizedRange.start) >= 0);
+ }
+
+ return intersects;
+ }
+
+ public Range normalize() {
+ Time earlier = (start.compareTo(end) < 0 ? start : end);
+ Time later = (earlier == start ? end : start);
+ return new Range(earlier, later);
+ }
+ }
+
+ /**
+ * The hour value, in 24-hour format.
+ */
+ public final int hour;
+
+ /**
+ * The minute value.
+ */
+ public final int minute;
+
+ /**
+ * The second value.
+ */
+ public final int second;
+
+ /**
+ * The millisecond value.
+ */
+ public final int millisecond;
+
+ public static final int MILLISECONDS_PER_SECOND = 1000;
+ public static final int MILLISECONDS_PER_MINUTE = 60 * MILLISECONDS_PER_SECOND;
+ public static final int MILLISECONDS_PER_HOUR = 60 * MILLISECONDS_PER_MINUTE;
+ public static final int MILLISECONDS_PER_DAY = 24 * MILLISECONDS_PER_HOUR;
+
+ private static final Pattern PATTERN = Pattern.compile("^(\\d{2}):(\\d{2}):(\\d{2})(\\.(\\d{3}))?$");
+
+ public Time() {
+ this(new GregorianCalendar());
+ }
+
+ public Time(Calendar calendar) {
+ if (calendar == null) {
+ throw new IllegalArgumentException();
+ }
+
+ this.hour = calendar.get(Calendar.HOUR_OF_DAY);
+ this.minute = calendar.get(Calendar.MINUTE);
+ this.second = calendar.get(Calendar.SECOND);
+ this.millisecond = calendar.get(Calendar.MILLISECOND);
+ }
+
+ public Time(int hour, int minute, int second) {
+ this(hour, minute, second, 0);
+ }
+
+ public Time(int hour, int minute, int second, int millisecond) {
+ if (hour < 0 || hour > 23) {
+ throw new IllegalArgumentException("Invalid hour.");
+ }
+
+ if (minute < 0 || minute > 59) {
+ throw new IllegalArgumentException("Invalid minute.");
+ }
+
+ if (second < 0 || second > 59) {
+ throw new IllegalArgumentException("Invalid second.");
+ }
+
+ if (millisecond < 0 || millisecond > 999) {
+ throw new IllegalArgumentException("Invalid millisecond.");
+ }
+
+ this.hour = hour;
+ this.minute = minute;
+ this.second = second;
+ this.millisecond = millisecond;
+ }
+
+ public Time(int milliseconds) {
+ milliseconds %= MILLISECONDS_PER_DAY;
+ milliseconds = (milliseconds + MILLISECONDS_PER_DAY) % MILLISECONDS_PER_DAY;
+
+ hour = milliseconds / MILLISECONDS_PER_HOUR;
+ milliseconds %= MILLISECONDS_PER_HOUR;
+
+ minute = milliseconds / MILLISECONDS_PER_MINUTE;
+ milliseconds %= MILLISECONDS_PER_MINUTE;
+
+ second = milliseconds / MILLISECONDS_PER_SECOND;
+ milliseconds %= MILLISECONDS_PER_SECOND;
+
+ millisecond = milliseconds;
+ }
+
+ /**
+ * Adds the specified milliseconds of days to this time and returns the
+ * resulting time. The number of milliseconds may be negative, in which
+ * case the result will be a time prior to this time.
+ *
+ * @param milliseconds
+ * The number of milliseconds to add to this time.
+ *
+ * @return
+ * The resulting time.
+ */
+ public Time add(int milliseconds) {
+ return new Time(toMilliseconds() + milliseconds);
+ }
+
+ /**
+ * Gets the number of milliseconds in between this time and the specified
+ * time. If this time represents a time later than the specified time, the
+ * difference will be positive. If this time represents a time before the
+ * specified time, the difference will be negative. If the two times represent
+ * the same time, the difference will be zero.
+ *
+ * @param time
+ * The time to subtract from this time.
+ *
+ * @return
+ * The number of milliseconds in between this time and <tt>time</tt>.
+ */
+ public int subtract(Time time) {
+ if (time == null) {
+ throw new IllegalArgumentException();
+ }
+
+ return toMilliseconds() - time.toMilliseconds();
+ }
+
+ /**
+ * Returns the number of milliseconds since midnight represented by
+ * this time.
+ *
+ * @return
+ * The number of milliseconds since midnight represented by this time.
+ */
+ public int toMilliseconds() {
+ return hour * MILLISECONDS_PER_HOUR
+ + minute * MILLISECONDS_PER_MINUTE
+ + second * MILLISECONDS_PER_SECOND
+ + millisecond;
+ }
+
+ @Override
+ public int compareTo(Time time) {
+ int result = hour - time.hour;
+
+ if (result == 0) {
+ result = minute - time.minute;
+
+ if (result == 0) {
+ result = second - time.second;
+
+ if (result == 0) {
+ result = millisecond - time.millisecond;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return (o instanceof Time
+ && ((Time)o).hour == hour
+ && ((Time)o).minute == minute
+ && ((Time)o).second == second
+ && ((Time)o).millisecond == millisecond);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + hour;
+ result = prime * result + minute;
+ result = prime * result + second;
+ result = prime * result + millisecond;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buf = new StringBuilder();
+
+ NumberFormat format = NumberFormat.getIntegerInstance();
+ format.setGroupingUsed(false);
+ format.setMinimumIntegerDigits(2);
+
+ buf.append(format.format(hour));
+ buf.append(":");
+ buf.append(format.format(minute));
+ buf.append(":");
+ buf.append(format.format(second));
+
+ if (millisecond > 0) {
+ buf.append(".");
+
+ format.setMinimumIntegerDigits(3);
+ buf.append(format.format(millisecond));
+ }
+
+ return buf.toString();
+ }
+
+ /**
+ * Creates a new time representing the specified time string. The time
+ * string must be in the full <tt>ISO 8601</tt> extended "time" format,
+ * which is <tt>[hh]:[mm]:[ss]</tt>. An optional millisecond suffix of
+ * the form <tt>.[nnn]</tt> is also supported.
+ *
+ * @param value
+ * A string in the form of <tt>[hh]:[mm]:[ss]</tt> or
+ * <tt>[hh]:[mm]:[ss].[nnn]</tt> (e.g. 17:19:20 or 17:19:20.412).
+ */
+ public static Time decode(String value) {
+ Matcher matcher = PATTERN.matcher(value);
+
+ if (!matcher.matches()) {
+ throw new IllegalArgumentException("Invalid time format: " + value);
+ }
+
+ int hour = Integer.parseInt(matcher.group(1));
+ int minute = Integer.parseInt(matcher.group(2));
+ int second = Integer.parseInt(matcher.group(3));
+
+ String millisecondSequence = matcher.group(4);
+ int millisecond = (millisecondSequence == null) ?
+ 0 : Integer.parseInt(millisecondSequence.substring(1));
+
+ return new Time(hour, minute, second, millisecond);
+ }
+}
Added: pivot/branches/3.x/core/src/org/apache/pivot/util/TypeLiteral.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/TypeLiteral.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/TypeLiteral.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/TypeLiteral.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,63 @@
+/*
+ * 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.pivot.util;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+
+/**
+ * Represents a generic type {@code T}. Java doesn't yet provide a way to
+ * represent generic types, so this class does. Clients create a subclass
+ * of this class, which enables retrieval the type information even at runtime.
+ * <p>
+ * For example, to get a reference to a generic type {@code List<String>}, you
+ * create an empty anonymous inner class, like so:
+ * <p>
+ * {@code Type genericType = (new TypeLiteral<List<String>>() {}).getType();}
+ * <p>
+ * This class is a drastically reduced derivation from
+ * <a href="http://code.google.com/p/google-guice/">Google Guice</a>'s
+ * {@code TypeLiteral} class, written by Bob Lee and Jesse Wilson.
+ */
+public class TypeLiteral<T> {
+ private final Type type;
+
+ /**
+ * Constructs a new type literal. Derives represented class from type
+ * parameter.
+ * <p>
+ * Clients create an empty anonymous subclass. Doing so embeds the type
+ * parameter in the anonymous class's type hierarchy so we can reconstitute it
+ * at runtime despite erasure.
+ */
+ protected TypeLiteral() {
+ Type genericSuperclass = getClass().getGenericSuperclass();
+ if (!(genericSuperclass instanceof ParameterizedType)) {
+ throw new RuntimeException("Missing type parameter.");
+ }
+
+ ParameterizedType parameterizedType = (ParameterizedType)genericSuperclass;
+ this.type = parameterizedType.getActualTypeArguments()[0];
+ }
+
+ /**
+ * Gets underlying {@code Type} instance.
+ */
+ public final Type getType() {
+ return type;
+ }
+}
Added: pivot/branches/3.x/core/src/org/apache/pivot/util/Version.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/Version.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/Version.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/Version.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,171 @@
+/*
+ * 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.pivot.util;
+
+import java.io.Serializable;
+
+/**
+ * Represents a version number. Version numbers are defined as:
+ * <p>
+ * <i>major</i>.<i>minor</i>.<i>maintenance</i>_<i>update</i>
+ * <p>
+ * for example, "JDK 1.6.0_10".
+ */
+public class Version implements Comparable<Version>, Serializable {
+ private static final long serialVersionUID = -3677773163272115116L;
+
+ private byte majorRevision = 0;
+ private byte minorRevision = 0;
+ private byte maintenanceRevision = 0;
+ private byte updateRevision = 0;
+ private String build = null;
+
+ public Version(int majorRevision, int minorRevision, int maintenanceRevision,
+ int updateRevision) {
+ this(majorRevision, minorRevision, maintenanceRevision, updateRevision, null);
+ }
+
+ public Version(int majorRevision, int minorRevision, int maintenanceRevision,
+ int updateRevision, String build) {
+ if (majorRevision > 0x7f) {
+ throw new IllegalArgumentException("majorRevision must be less than "
+ + 0x7f + ".");
+ }
+
+ if (minorRevision > 0xff) {
+ throw new IllegalArgumentException("minorRevision must be less than "
+ + 0xff + ".");
+ }
+
+ if (maintenanceRevision > 0xff) {
+ throw new IllegalArgumentException("maintenanceRevision must be less than "
+ + 0xff + ".");
+ }
+
+ if (updateRevision > 0xff) {
+ throw new IllegalArgumentException("updateRevision must be less than "
+ + 0xff + ".");
+ }
+
+ this.majorRevision = (byte)majorRevision;
+ this.minorRevision = (byte)minorRevision;
+ this.maintenanceRevision = (byte)maintenanceRevision;
+ this.updateRevision = (byte)updateRevision;
+ this.build = build;
+ }
+
+ public byte getMajorRevision() {
+ return majorRevision;
+ }
+
+ public byte getMinorRevision() {
+ return minorRevision;
+ }
+
+ public byte getMaintenanceRevision() {
+ return maintenanceRevision;
+ }
+
+ public byte getUpdateRevision() {
+ return updateRevision;
+ }
+
+ public int getNumber() {
+ int number = ((majorRevision) & 0xff) << (8 * 3)
+ | ((minorRevision) & 0xff) << (8 * 2)
+ | ((maintenanceRevision) & 0xff) << (8 * 1)
+ | ((updateRevision) & 0xff) << (8 * 0);
+
+ return number;
+ }
+
+ @Override
+ public int compareTo(Version version) {
+ return (getNumber() - version.getNumber());
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ return (object instanceof Version
+ && compareTo((Version)object) == 0);
+ }
+
+ @Override
+ public int hashCode() {
+ return getNumber();
+ }
+
+ @Override
+ public String toString() {
+ String string = majorRevision
+ + "." + minorRevision
+ + "." + maintenanceRevision
+ + "_" + String.format("%02d", updateRevision);
+
+ if (build != null) {
+ string += "-" + build;
+ }
+
+ return string;
+ }
+
+ public static Version decode(String string) {
+ Version version = null;
+
+ byte majorRevision = 0;
+ byte minorRevision = 0;
+ byte maintenanceRevision = 0;
+ byte updateRevision = 0;
+ String build = null;
+
+ String revision;
+ int i = string.indexOf("-");
+ if (i == -1) {
+ revision = string;
+ } else {
+ revision = string.substring(0, i);
+ build = string.substring(i + 1);
+ }
+
+ String[] revisionNumbers = revision.split("\\.");
+
+ if (revisionNumbers.length > 0) {
+ majorRevision = Byte.parseByte(revisionNumbers[0]);
+
+ if (revisionNumbers.length > 1) {
+ minorRevision = Byte.parseByte(revisionNumbers[1]);
+
+ if (revisionNumbers.length > 2) {
+ String[] maintenanceRevisionNumbers = revisionNumbers[2].split("_");
+
+ if (maintenanceRevisionNumbers.length > 0) {
+ maintenanceRevision = Byte.parseByte(maintenanceRevisionNumbers[0]);
+
+ if (maintenanceRevisionNumbers.length > 1) {
+ updateRevision = Byte.parseByte(maintenanceRevisionNumbers[1]);
+ }
+ }
+ }
+ }
+
+ version = new Version(majorRevision, minorRevision, maintenanceRevision,
+ updateRevision, build);
+ }
+
+ return version;
+ }
+}
Added: pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/AbortException.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/AbortException.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/AbortException.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/AbortException.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,32 @@
+/*
+ * 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.pivot.util.concurrent;
+
+/**
+ * Thrown when a task is aborted.
+ */
+public class AbortException extends RuntimeException {
+ private static final long serialVersionUID = 0;
+
+ public AbortException() {
+ super();
+ }
+
+ public AbortException(String message) {
+ super(message);
+ }
+}
Added: pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/ParallelTaskGroup.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/ParallelTaskGroup.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/ParallelTaskGroup.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/ParallelTaskGroup.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,52 @@
+/*
+ * 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.pivot.util.concurrent;
+
+/**
+ * Class that runs a group of tasks in parallel and notifies listeners
+ * when all tasks are complete.
+ */
+public class ParallelTaskGroup extends TaskGroup {
+ @Override
+ @SuppressWarnings("unchecked")
+ public synchronized Void execute() throws TaskExecutionException {
+ TaskListener<Object> taskListener = new TaskListener<Object>() {
+ @Override
+ public void taskExecuted(Task<Object> task) {
+ synchronized (ParallelTaskGroup.this) {
+ complete++;
+ ParallelTaskGroup.this.notify();
+ }
+ }
+ };
+
+ complete = 0;
+ for (Task<?> task : tasks) {
+ ((Task<Object>)task).execute(taskListener);
+ }
+
+ while (complete < tasks.size()) {
+ try {
+ wait();
+ } catch (InterruptedException exception) {
+ throw new TaskExecutionException(exception);
+ }
+ }
+
+ return null;
+ }
+}
Added: pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/SerialTaskGroup.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/SerialTaskGroup.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/SerialTaskGroup.java (added)
+++ pivot/branches/3.x/core/src/org/apache/pivot/util/concurrent/SerialTaskGroup.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,54 @@
+/*
+ * 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.pivot.util.concurrent;
+
+/**
+ * Class that runs a sequence of tasks in series and notifies listeners
+ * when all tasks are complete.
+ */
+public class SerialTaskGroup extends TaskGroup {
+ @Override
+ @SuppressWarnings("unchecked")
+ public synchronized Void execute() throws TaskExecutionException {
+ TaskListener<Object> taskListener = new TaskListener<Object>() {
+ @Override
+ public void taskExecuted(Task<Object> task) {
+ synchronized (SerialTaskGroup.this) {
+ complete++;
+ SerialTaskGroup.this.notify();
+ }
+ }
+ };
+
+ complete = 0;
+ for (Task<?> task : tasks) {
+ if (abort) {
+ throw new AbortException();
+ }
+
+ ((Task<Object>)task).execute(taskListener);
+
+ try {
+ wait();
+ } catch (InterruptedException exception) {
+ throw new TaskExecutionException(exception);
+ }
+ }
+
+ return null;
+ }
+}