[gee-svn] SF.net SVN: gabel: [188] trunk/gee/war
Status: Alpha
Brought to you by:
alllee
|
From: <al...@us...> - 2006-06-18 18:34:54
|
Revision: 188 Author: alllee Date: 2006-06-18 11:34:40 -0700 (Sun, 18 Jun 2006) ViewCVS: http://svn.sourceforge.net/gabel/?rev=188&view=rev Log Message: ----------- * adding new forager images * NioDispatcher's connect() now blocks until it receives an Identifier from the server it's connecting to. * some more refactoring. Modified Paths: -------------- trunk/gee/lib/junit.jar trunk/gee/src/java/edu/indiana/psych/gee/event/AbstractEvent.java trunk/gee/src/java/edu/indiana/psych/gee/event/AbstractPersistableEvent.java trunk/gee/src/java/edu/indiana/psych/gee/event/Event.java trunk/gee/src/java/edu/indiana/psych/gee/event/EventChannel.java trunk/gee/src/java/edu/indiana/psych/gee/event/EventProcessor.java trunk/gee/src/java/edu/indiana/psych/gee/event/EventTypeProcessor.java trunk/gee/src/java/edu/indiana/psych/gee/forager/DebriefingAssistant.java trunk/gee/src/java/edu/indiana/psych/gee/forager/ForagerExperiment.java trunk/gee/src/java/edu/indiana/psych/gee/forager/ForagerServerGameState.java trunk/gee/src/java/edu/indiana/psych/gee/forager/client/ForagerClient.java trunk/gee/src/java/edu/indiana/psych/gee/forager/client/ForagerClientGameState.java trunk/gee/src/java/edu/indiana/psych/gee/forager/client/ForagerGameWindow.java trunk/gee/src/java/edu/indiana/psych/gee/forager/event/ClientUpdateEvent.java trunk/gee/src/java/edu/indiana/psych/gee/net/AbstractServerDispatcher.java trunk/gee/src/java/edu/indiana/psych/gee/net/ClientSocketDispatcher.java trunk/gee/src/java/edu/indiana/psych/gee/net/NioDispatcher.java trunk/gee/src/java/edu/indiana/psych/gee/net/ServerSocketDispatcher.java trunk/gee/src/java/edu/indiana/psych/gee/net/Worker.java trunk/gee/src/java/edu/indiana/psych/gee/net/WorkerPool.java trunk/gee/war/WEB-INF/classes/xwork.xml trunk/gee/war/index.jsp Added Paths: ----------- trunk/gee/src/test/edu/indiana/psych/gee/net/NioDispatcherTester.java trunk/gee/war/WEB-INF/lib/dwr.jar trunk/gee/war/images/forager-v2/ trunk/gee/war/images/forager-v2/bot-back.gif trunk/gee/war/images/forager-v2/bot-front.gif trunk/gee/war/images/forager-v2/bot-side-left.gif trunk/gee/war/images/forager-v2/bot-side-right.gif trunk/gee/war/images/forager-v2/grass-1.gif trunk/gee/war/images/forager-v2/grass-2.gif trunk/gee/war/images/forager-v2/grass-3.gif trunk/gee/war/images/forager-v2/grass-4.gif trunk/gee/war/images/forager-v2/others-back.gif trunk/gee/war/images/forager-v2/others-front.gif trunk/gee/war/images/forager-v2/others-side-left.gif trunk/gee/war/images/forager-v2/others-side-right.gif trunk/gee/war/images/forager-v2/you-back.gif trunk/gee/war/images/forager-v2/you-front.gif trunk/gee/war/images/forager-v2/you-side-left.gif trunk/gee/war/images/forager-v2/you-side-right.gif Removed Paths: ------------- trunk/gee/src/java/edu/indiana/psych/gee/net/event/ServerAssignedIdentifierEvent.java trunk/gee/src/test/edu/indiana/psych/gee/net/SocketIdentifierTester.java Modified: trunk/gee/lib/junit.jar =================================================================== (Binary files differ) Modified: trunk/gee/src/java/edu/indiana/psych/gee/event/AbstractEvent.java =================================================================== --- trunk/gee/src/java/edu/indiana/psych/gee/event/AbstractEvent.java 2006-05-31 23:57:30 UTC (rev 187) +++ trunk/gee/src/java/edu/indiana/psych/gee/event/AbstractEvent.java 2006-06-18 18:34:40 UTC (rev 188) @@ -43,7 +43,7 @@ /** * Returns the event's identifier */ - public Identifier id() { + public Identifier getId() { return id; } Modified: trunk/gee/src/java/edu/indiana/psych/gee/event/AbstractPersistableEvent.java =================================================================== --- trunk/gee/src/java/edu/indiana/psych/gee/event/AbstractPersistableEvent.java 2006-05-31 23:57:30 UTC (rev 187) +++ trunk/gee/src/java/edu/indiana/psych/gee/event/AbstractPersistableEvent.java 2006-06-18 18:34:40 UTC (rev 188) @@ -42,7 +42,6 @@ // ordinal to help impose a total ordering across all persistable events. int comparison = compare(getCreationTime(), e.getCreationTime()); if (comparison == 0) { - // this may cause problems with overflow if that should ever happen. return compare(ordinal, e.ordinal); } return comparison; Modified: trunk/gee/src/java/edu/indiana/psych/gee/event/Event.java =================================================================== --- trunk/gee/src/java/edu/indiana/psych/gee/event/Event.java 2006-05-31 23:57:30 UTC (rev 187) +++ trunk/gee/src/java/edu/indiana/psych/gee/event/Event.java 2006-06-18 18:34:40 UTC (rev 188) @@ -15,7 +15,7 @@ */ public interface Event extends Serializable { - public Identifier id(); + public Identifier getId(); // FIXME: use TimePoints instead. public long getCreationTime(); Modified: trunk/gee/src/java/edu/indiana/psych/gee/event/EventChannel.java =================================================================== --- trunk/gee/src/java/edu/indiana/psych/gee/event/EventChannel.java 2006-05-31 23:57:30 UTC (rev 187) +++ trunk/gee/src/java/edu/indiana/psych/gee/event/EventChannel.java 2006-06-18 18:34:40 UTC (rev 188) @@ -1,6 +1,7 @@ package edu.indiana.psych.gee.event; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -17,21 +18,17 @@ private final static EventChannel INSTANCE = new EventChannel(); - /** - * EventDispatcher helper class manages the EventChannel's EventGenerator - * duties (subscribe/unsubscribe) as well as dispatching requests. It - * installs new EventHandlers, removes extant EventHandlers, and propagates - * events generated by the pool or passed in via the handle(Event event) - * method. - */ - private final EventDispatcher assistant = new EventDispatcher(); + private final Map<EventHandler, EventConstraint> eventListeners = + new HashMap<EventHandler, EventConstraint>(); + // Maps a 'module' owner to a list of event processors (which encapsulate both EventHandling + // and an EventConstraint). private final Map<Object, List<EventProcessor>> owners = new HashMap<Object, List<EventProcessor>>(); /** * Provides access to a singleton version of the EventChannel. - * @return + * @return the EventChannel singleton */ public static EventChannel getInstance() { return INSTANCE; @@ -39,160 +36,162 @@ /** * Adds an event to the EventChannel which then propagates the event to - * all interested subscribers. + * all interested subscribers. EventHandler.handle(Event) is invoked in a separate + * thread of execution. * - * @param event The event to add to the Pool. + * @param event The event to distribute via this EventChannel. */ - public synchronized void handle(Event event) { - assistant.dispatch(event); + public void handle(final Event event) { + synchronized (eventListeners) { + for (final Map.Entry<EventHandler, EventConstraint> entry : eventListeners.entrySet()) { + if (entry.getValue().accepts(event)) { + new Thread() { + public void run() { + entry.getKey().handle(event); + } + }.start(); + } + } + } } - + /** * An EventTypeProcessor is a convenience type for subscribing to the pool and * provides localized event handling for a given constraint. * @param processor */ - public synchronized void add(EventProcessor processor) { + public void add(EventProcessor processor) { subscribe(processor, processor); } - + /** * An EventTypeProcessor is a convenience type for subscribing to the pool and * provides localized event handling for a given constraint. * @param processor */ - public synchronized void add(Object owner, EventProcessor processor) { + public void add(Object owner, EventProcessor processor) { getEventProcessorsFor(owner).add(processor); } - - @SuppressWarnings("serial") + private List<EventProcessor> getEventProcessorsFor(Object owner) { - List<EventProcessor> processors = owners.get(owner); - if (processors == null) { - // overrides the add method to auto-subscribe the EventProcessor - // with this EventChannel. Should probably override all other - // add/insert methods in the future. - processors = new ArrayList<EventProcessor>() { - public boolean add(EventProcessor processor) { - subscribe(processor, processor); - return super.add(processor); - } - }; - owners.put(owner, processors); + synchronized (owners) { + List<EventProcessor> processors = owners.get(owner); + if (processors == null) { + processors = new EventProcessorList(); + owners.put(owner, processors); + } + return processors; } - return processors; + } - + public List<EventProcessor> register(Object owner) { return getEventProcessorsFor(owner); } - - public synchronized void unregister(Object owner) { - List<EventProcessor> processors = owners.remove(owner); + + public void unregister(Object owner) { + List<EventProcessor> processors = null; + synchronized (owners) { + processors = owners.remove(owner); + } if (processors != null) { for (EventProcessor processor: processors) { unsubscribe(processor); } } } - - public synchronized void remove(Object owner) { + + public void remove(Object owner) { unregister(owner); } /** - * Informs the pool that the given handler should receive all Events added - * to the Pool satisfying the given EventConstraint. + * The given handler will receive all Events received by this EventChannel + * accept()-ed by the given EventConstraint. * * @param handler The EventHandler to subscribe. * @param constraint The constraint with which to filter events. */ - public synchronized void subscribe(EventHandler handler, EventConstraint constraint) { + public void subscribe(EventHandler handler, EventConstraint constraint) { if (handler == this) { throw new IllegalArgumentException( "Cannot subscribe the event channel to itself."); } - assistant.put(handler, constraint); + synchronized (eventListeners) { + eventListeners.put(handler, constraint); + } } - - public synchronized void subscribe(EventHandler handler) { - subscribe(handler, EventConstraint.NONE); + + public void subscribe(EventHandler handler) { + subscribe(handler, EventConstraint.NONE); } /** - * Unsubscribes an EventHandler. + * Unsubscribes an EventHandler from this EventChannel, stopping it from receiving any + * events from this EventChannel. * * @param handler The EventHandler to unsubscribe. - * - * @throws KnownspaceException */ - public synchronized void unsubscribe(EventHandler handler) { - assistant.remove(handler); + public void unsubscribe(EventHandler handler) { + synchronized (eventListeners) { + eventListeners.remove(handler); + } } - + /** - * Extract this class to top level if it turns out to be useful in more contexts. - * - * @see mud.engine.EventGenerator + * $Id$ + * + * FIXME: this class should support automatic subscription/unsubscription with all methods that + * add/remove to this List. Right now only the basic add/remove methods are supported. */ - private static class EventDispatcher { - private final Map<EventHandler, EventConstraint> eventListeners; - - /** - * Create a new EventDispatcher. - */ - protected EventDispatcher() { - eventListeners = new HashMap<EventHandler, EventConstraint>(); + private class EventProcessorList extends ArrayList<EventProcessor> { + private static final long serialVersionUID = -4756601346604320046L; + @Override + public boolean add(EventProcessor processor) { + subscribe(processor, processor); + return super.add(processor); } - - /** - * Associates a constraint with a given handler; whenever an Event passes - * through the EventChannel the constraint is applied to the event. If - * successful, the Event is passed to the EventHandler, otherwise it's - * skipped. Currently only supports 1-1 mappings between constraints - * and handlers. - * - * @param handler EventHandler to subscribe. - * @param constraint EventConstraint to filter with. - */ - protected synchronized void put(EventHandler handler, EventConstraint constraint) { - eventListeners.put(handler, constraint); + @Override + public void add(int index, EventProcessor processor) { + subscribe(processor, processor); + super.add(index, processor); } - - /** - * Removes an EventHandler and its associated constraint. This method - * provides access for removing EventHandlers. It should be used - * within the EventGenerator's unsubscribe() method. - * - * @param handler The EventHandler to remove. - */ - protected synchronized void remove(EventHandler handler) { - eventListeners.remove(handler); + @Override + public boolean addAll(Collection<? extends EventProcessor> c) { + for (EventProcessor processor: c) { + subscribe(processor, processor); + } + return super.addAll(c); } - - /** - * Fires the given event to all interested EventHandlers. This method - * provides a way for Events to be sent to all EventHandlers subscribed - * for them. - * - * @param event The event to fire. - */ - protected synchronized void dispatch(final Event event) { - for (Map.Entry<EventHandler, EventConstraint> entry : eventListeners.entrySet()) { - if (entry.getValue().accepts(event)) { - entry.getKey().handle(event); - } + @Override + public boolean addAll(int index, Collection<? extends EventProcessor> c) { + for (EventProcessor processor: c) { + subscribe(processor, processor); } - /* - for (Iterator handlers = eventListeners.keySet().iterator(); handlers.hasNext(); ) { - final EventHandler handler = (EventHandler) handlers.next(); - final EventConstraint constraint = eventListeners.get(handler); - if ( constraint.accepts(event) ) { - handler.handle(event); + return super.addAll(index, c); + } + @Override + public EventProcessor remove(int index) { + EventProcessor removed = super.remove(index); + unsubscribe(removed); + return removed; + } + @Override + public boolean remove(Object o) { + if (o instanceof EventProcessor) { + unsubscribe((EventProcessor) o); + } + return super.remove(o); + } + @Override + public boolean removeAll(Collection<?> c) { + for (Object o: c) { + if (o instanceof EventProcessor) { + unsubscribe((EventProcessor) o); } } - */ + return super.removeAll(c); } - + } } Modified: trunk/gee/src/java/edu/indiana/psych/gee/event/EventProcessor.java =================================================================== --- trunk/gee/src/java/edu/indiana/psych/gee/event/EventProcessor.java 2006-05-31 23:57:30 UTC (rev 187) +++ trunk/gee/src/java/edu/indiana/psych/gee/event/EventProcessor.java 2006-06-18 18:34:40 UTC (rev 188) @@ -4,7 +4,9 @@ /** * $Id$ * - * Support class for processing events by type. + * Support interface for processing events, encapsulating both an EventHandler and an EventConstraint + * in the same class/type. + * * * @author <a href='al...@cs...'>Allen Lee</a> * @version $Revision$ Modified: trunk/gee/src/java/edu/indiana/psych/gee/event/EventTypeProcessor.java =================================================================== --- trunk/gee/src/java/edu/indiana/psych/gee/event/EventTypeProcessor.java 2006-05-31 23:57:30 UTC (rev 187) +++ trunk/gee/src/java/edu/indiana/psych/gee/event/EventTypeProcessor.java 2006-06-18 18:34:40 UTC (rev 188) @@ -4,7 +4,8 @@ /** * $Id$ * - * Generified version of EventTypeProcessor. + * An EventTypeProcessor encapsulates both an EventHandler and an EventInstanceofConstraint + * within the same class for convenience sake. * * @author <a href='al...@cs...'>Allen Lee</a> * @version $Revision$ @@ -12,7 +13,7 @@ public abstract class EventTypeProcessor<E extends Event> implements EventProcessor<E> { - private final EventConstraint constraint; + private final EventInstanceofConstraint constraint; /** * FIXME: find a way to get around having to specify the type of the class @@ -29,5 +30,4 @@ public boolean accepts(Event event) { return constraint.accepts(event); } - } Modified: trunk/gee/src/java/edu/indiana/psych/gee/forager/DebriefingAssistant.java =================================================================== --- trunk/gee/src/java/edu/indiana/psych/gee/forager/DebriefingAssistant.java 2006-05-31 23:57:30 UTC (rev 187) +++ trunk/gee/src/java/edu/indiana/psych/gee/forager/DebriefingAssistant.java 2006-06-18 18:34:40 UTC (rev 188) @@ -50,7 +50,7 @@ List<EventProcessor> processors = channel.register(this); processors.add(new EventTypeProcessor<PersistableEvent>(PersistableEvent.class) { public boolean accepts(Event event) { - return super.accepts(event) && ! (event.id() instanceof AgentIdentifier); + return super.accepts(event) && ! (event.getId() instanceof AgentIdentifier); } public void handle(PersistableEvent event) { if (event instanceof FoodAddedEvent) { @@ -62,7 +62,7 @@ else { // otherwise, associate it with the actions of the given client // only. - TreeSet<PersistableEvent> actions = clientActions.get(event.id()); + TreeSet<PersistableEvent> actions = clientActions.get(event.getId()); if (actions == null) { // FIXME: should assert that there are no actions ONLY for bot // identifiers. Modified: trunk/gee/src/java/edu/indiana/psych/gee/forager/ForagerExperiment.java =================================================================== --- trunk/gee/src/java/edu/indiana/psych/gee/forager/ForagerExperiment.java 2006-05-31 23:57:30 UTC (rev 187) +++ trunk/gee/src/java/edu/indiana/psych/gee/forager/ForagerExperiment.java 2006-06-18 18:34:40 UTC (rev 188) @@ -92,9 +92,9 @@ processors.add(new EventTypeProcessor<ClientReadyEvent>(ClientReadyEvent.class) { public void handle(ClientReadyEvent event) { synchronized (queuedParticipants) { - if ( queuedParticipants.remove(event.id()) ) { - readyToJoinParticipants.add(event.id()); - sendRegistrationEvent(event.id()); + if ( queuedParticipants.remove(event.getId()) ) { + readyToJoinParticipants.add(event.getId()); + sendRegistrationEvent(event.getId()); } } } @@ -102,7 +102,7 @@ processors.add(new EventTypeProcessor<ClientUpdateEvent>(ClientUpdateEvent.class) { public void handle(ClientUpdateEvent event) { synchronized (currentParticipantHeadings) { - currentParticipantHeadings.put(event.id(), event.getDirection()); + currentParticipantHeadings.put(event.getId(), event.getDirection()); } } }); @@ -110,9 +110,9 @@ processors.add(new EventTypeProcessor<ConnectionEvent>(ConnectionEvent.class) { public void handle(ConnectionEvent event) { synchronized (queuedParticipants) { - queuedParticipants.add(event.id()); + queuedParticipants.add(event.getId()); } - sendRegistrationEvent(event.id()); + sendRegistrationEvent(event.getId()); } }); Modified: trunk/gee/src/java/edu/indiana/psych/gee/forager/ForagerServerGameState.java =================================================================== --- trunk/gee/src/java/edu/indiana/psych/gee/forager/ForagerServerGameState.java 2006-05-31 23:57:30 UTC (rev 187) +++ trunk/gee/src/java/edu/indiana/psych/gee/forager/ForagerServerGameState.java 2006-06-18 18:34:40 UTC (rev 188) @@ -95,11 +95,11 @@ // the ForagerServerGameState. if (event instanceof AddClientEvent) { AddClientEvent addClientEvent = (AddClientEvent) event; - addClient(addClientEvent.id(), addClientEvent.getPosition()); + addClient(addClientEvent.getId(), addClientEvent.getPosition()); } else if (event instanceof MovementEvent) { MovementEvent movementEvent = (MovementEvent) event; - moveClient(movementEvent.id(), movementEvent.getDirection()); + moveClient(movementEvent.getId(), movementEvent.getDirection()); } else if (event instanceof FoodAddedEvent) { FoodAddedEvent foodAddedEvent = (FoodAddedEvent) event; Modified: trunk/gee/src/java/edu/indiana/psych/gee/forager/client/ForagerClient.java =================================================================== --- trunk/gee/src/java/edu/indiana/psych/gee/forager/client/ForagerClient.java 2006-05-31 23:57:30 UTC (rev 187) +++ trunk/gee/src/java/edu/indiana/psych/gee/forager/client/ForagerClient.java 2006-06-18 18:34:40 UTC (rev 188) @@ -96,12 +96,12 @@ // FIXME: should state change should happen in a consistent way // by a consistent class? state = READY; - if (event.id().equals(id)) { + if (event.getId().equals(id)) { dispatcher.transmit(event); } else { error("Invalid client id ready, expected [" + id + "] actual [" - + event.id() + "]"); + + event.getId() + "]"); } } }); @@ -294,7 +294,7 @@ private ClientMessageQueueHandler(EventChannel channel) { channel.add(new EventTypeProcessor<ClientUpdateEvent>(ClientUpdateEvent.class) { public void handle(ClientUpdateEvent event) { - assert event.id().equals(ForagerClient.this.id); + assert event.getId().equals(ForagerClient.this.id); if (ForagerClient.this.state != RUNNING) { info("game is currently not running, ignoring: " + event + " state: " + ForagerClient.this.state); return; Modified: trunk/gee/src/java/edu/indiana/psych/gee/forager/client/ForagerClientGameState.java =================================================================== --- trunk/gee/src/java/edu/indiana/psych/gee/forager/client/ForagerClientGameState.java 2006-05-31 23:57:30 UTC (rev 187) +++ trunk/gee/src/java/edu/indiana/psych/gee/forager/client/ForagerClientGameState.java 2006-06-18 18:34:40 UTC (rev 188) @@ -74,7 +74,7 @@ clientState.setPosition(point); } if (event.didConsumeFood()) { - ClientState clientState = clients.get(event.id()); + ClientState clientState = clients.get(event.getId()); clientState.incrementFoodEaten(); // FIXME: drop an event into the event channel to signal the ForagerGameWindow // instead of doing this. Modified: trunk/gee/src/java/edu/indiana/psych/gee/forager/client/ForagerGameWindow.java =================================================================== --- trunk/gee/src/java/edu/indiana/psych/gee/forager/client/ForagerGameWindow.java 2006-05-31 23:57:30 UTC (rev 187) +++ trunk/gee/src/java/edu/indiana/psych/gee/forager/client/ForagerGameWindow.java 2006-06-18 18:34:40 UTC (rev 188) @@ -160,7 +160,7 @@ // reading through the debriefing! } setSpecialInstructions(event.toString()); - clientIdentifier = event.id(); + clientIdentifier = event.getId(); } private synchronized void setSpecialInstructions(String specialInstructions) { Modified: trunk/gee/src/java/edu/indiana/psych/gee/forager/event/ClientUpdateEvent.java =================================================================== --- trunk/gee/src/java/edu/indiana/psych/gee/forager/event/ClientUpdateEvent.java 2006-05-31 23:57:30 UTC (rev 187) +++ trunk/gee/src/java/edu/indiana/psych/gee/forager/event/ClientUpdateEvent.java 2006-06-18 18:34:40 UTC (rev 188) @@ -32,6 +32,6 @@ } public String toString() { - return "Client update: " + id() + "\n\tDirection: " + direction; + return "Client update: " + getId() + "\n\tDirection: " + direction; } } Modified: trunk/gee/src/java/edu/indiana/psych/gee/net/AbstractServerDispatcher.java =================================================================== --- trunk/gee/src/java/edu/indiana/psych/gee/net/AbstractServerDispatcher.java 2006-05-31 23:57:30 UTC (rev 187) +++ trunk/gee/src/java/edu/indiana/psych/gee/net/AbstractServerDispatcher.java 2006-06-18 18:34:40 UTC (rev 188) @@ -37,8 +37,8 @@ super(channel); channel.add(this, new EventTypeProcessor<DisconnectionRequest>(DisconnectionRequest.class) { public void handle(DisconnectionRequest request) { - logger.warn("disconnecting: " + request.id(), request.getException()); - disconnectedClients.add( request.id() ); + logger.warn("disconnecting: " + request.getId(), request.getException()); + disconnectedClients.add( request.getId() ); } }); } @@ -68,7 +68,6 @@ port, listeningPort)); return; } - listening = true; listeningPort = port; dispatcherThread = createDispatcherThread(); dispatcherThread.start(); @@ -93,7 +92,7 @@ } private Thread createDispatcherThread() { - return new Thread(new Runnable() { + return new Thread() { /** * Template method controlling the flow of execution for this Dispatcher. * Subclasses should implement bind(int port) and processIncomingConnections() @@ -104,6 +103,7 @@ logger.debug(getClass() + " listening on port:" + port); try { bind(port); + listening = true; while ( listening ) { processIncomingConnections(); // disconnect any pending disconnected clients and so on. @@ -116,9 +116,13 @@ shutdown(); } } - }); + }; } + public boolean isListening() { + return listening; + } + private void performConnectionMaintenance() { for (Iterator<Identifier> iter = disconnectedClients.iterator(); iter.hasNext(); ) { Identifier id = iter.next(); Modified: trunk/gee/src/java/edu/indiana/psych/gee/net/ClientSocketDispatcher.java =================================================================== --- trunk/gee/src/java/edu/indiana/psych/gee/net/ClientSocketDispatcher.java 2006-05-31 23:57:30 UTC (rev 187) +++ trunk/gee/src/java/edu/indiana/psych/gee/net/ClientSocketDispatcher.java 2006-06-18 18:34:40 UTC (rev 188) @@ -10,22 +10,13 @@ import edu.indiana.psych.gee.event.EventTypeProcessor; import edu.indiana.psych.gee.net.event.ConnectionEvent; import edu.indiana.psych.gee.net.event.DisconnectionRequest; -import edu.indiana.psych.gee.net.event.ServerAssignedIdentifierEvent; /** * $Id$ * - * FIXME: Confused class hierarchy needs some work. Both ClientSocketDispatcher - * and ServerSocketDispatcher have common code for reading and transmitting - * Events across the network that should live somewhere common. Perhaps this is - * the case for SocketDispatcherWorker being its bona fide class. - * across the network - where should this live? The AbstractServerDispatcher - * has additional helper methods that it can use. + * The client dispatcher only implements the connecting part of the network business. * - * Perhaps this is a sign that we should be using composition instead of - * inheritance. * - * - * + * * @author Allen Lee * @version $Revision$ */ @@ -37,7 +28,7 @@ super(channel); channel.add(new EventTypeProcessor<DisconnectionRequest>(DisconnectionRequest.class) { public void handle(DisconnectionRequest event) { - disconnect(event.id()); + disconnect(event.getId()); } }); } @@ -58,11 +49,11 @@ // block while we wait for the ServerSocketDispatcher to assign an // Identifier to us. Event event = SocketDispatcherWorker.readEvent(socket); - assert event instanceof ServerAssignedIdentifierEvent; - Identifier id = event.id(); + assert event instanceof ConnectionEvent; + Identifier id = event.getId(); worker = new SocketDispatcherWorker(this, id, socket); worker.start(); - getLocalEventHandler().handle(new ConnectionEvent(event.id())); + getLocalEventHandler().handle((ConnectionEvent) event); return id; } catch (IOException e) { Modified: trunk/gee/src/java/edu/indiana/psych/gee/net/NioDispatcher.java =================================================================== --- trunk/gee/src/java/edu/indiana/psych/gee/net/NioDispatcher.java 2006-05-31 23:57:30 UTC (rev 187) +++ trunk/gee/src/java/edu/indiana/psych/gee/net/NioDispatcher.java 2006-06-18 18:34:40 UTC (rev 188) @@ -3,6 +3,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.InetSocketAddress; @@ -16,15 +17,11 @@ import java.util.LinkedList; import java.util.Map; -import org.apache.commons.collections.BidiMap; -import org.apache.commons.collections.bidimap.DualHashBidiMap; - import edu.indiana.psych.gee.Identifier; import edu.indiana.psych.gee.event.Event; import edu.indiana.psych.gee.event.EventChannel; import edu.indiana.psych.gee.net.event.ConnectionEvent; import edu.indiana.psych.gee.net.event.DisconnectionEvent; -import edu.indiana.psych.gee.net.event.ServerAssignedIdentifierEvent; /** * $Id$ @@ -32,6 +29,8 @@ * This class manages network connections via the java.nio package and can be * used by both clients and servers. Network connection descriptors (Identifiers) * are used to uniformly refer to the individual connections across the network. + * The NioDispatcher is both a client and a server dispatcher, allowing p2p + * connections. * * @author <a href='al...@cs...'>Allen Lee</a> * @version $Revision$ @@ -40,7 +39,7 @@ private final static int READ_BUFFER_SIZE = 8192; - private final static int INT_SIZE = 4; + private final static int BYTES_PER_INT = 4; private ServerSocketChannel server; @@ -56,7 +55,8 @@ // SocketChannel. // bidirectional map of Identifier <-> SocketChannel - private final BidiMap connections = new DualHashBidiMap(); + private final Map<Identifier, SocketChannel> connections = + new HashMap<Identifier, SocketChannel>(); // maps Identifiers of clients that are in the process of // sending an Object across the stream but only got there halfway private Map<Identifier, PendingDataBuffer> pendingClients = @@ -70,6 +70,13 @@ initWorkerPool(workerPoolSize); } + /** + * package private to enforce access via the DispatcherFactory. + */ + NioDispatcher(EventChannel channel) { + this(channel, 10); + } + private void initWorkerPool(int size) { // XXX: special case worker pool of size 1 to just be a single Worker. if (size > 1) { @@ -84,6 +91,7 @@ worker = new NioDispatcherWorker(); } } + public boolean isConnected(Identifier id) { return true; } @@ -95,11 +103,12 @@ public Identifier connect(InetSocketAddress address) { try { SocketChannel connection = SocketChannel.open(address); - connection.configureBlocking(false); +// block until we've read the socket identifier from server. + System.err.println("connection: " + connection); + Identifier id = readConnectionEvent(connection); worker.process(connection); // XXX: we return an Identifier that's .equals() with the // Identifiers used on the Server side. - Identifier id = new SocketIdentifier(connection.socket()); addMapping(id, connection); return id; } @@ -110,17 +119,29 @@ } } + private Identifier readConnectionEvent(SocketChannel connection) throws IOException { + connection.configureBlocking(true); + InputStream in = connection.socket().getInputStream(); + // read past the int header + in.read(); in.read(); in.read(); in.read(); + ObjectInputStream ois = new ObjectInputStream(in); + try { + ConnectionEvent event = (ConnectionEvent) ois.readObject(); + return event.getId(); + } + catch (Exception e) { + e.printStackTrace(); + } + return null; + } + private void addMapping(Identifier id, SocketChannel channel) { connections.put(id, channel); } private SocketChannel getConnection(Identifier id) { - return (SocketChannel) connections.get(id); + return connections.get(id); } - - private Identifier getIdentifier(Object channel) { - return (Identifier) connections.getKey(channel); - } public void disconnect(Identifier id) { SocketChannel channel = getConnection(id); @@ -149,7 +170,7 @@ } catch (IOException e) { e.printStackTrace(); - requestDisconnection(event.id(), e); + requestDisconnection(event.getId(), e); } // FIXME: improve exception handling. throw new RuntimeException("Unable to convert event into raw byte data: " + event); @@ -178,11 +199,11 @@ public void transmit(Event event) { try { byte[] data = marshal(event); - write(event.id(), data); + write(event.getId(), data); } catch (IOException e) { e.printStackTrace(); - requestDisconnection(event.id(), e); + requestDisconnection(event.getId(), e); } } @@ -198,21 +219,23 @@ disconnect(id); throw new IllegalArgumentException("Attempting to write with an Identifier that doesn't exist: " + id); } - final int objectSize = data.length; - // FIXME: could be a performance bottle-neck in the future, allocation - // can be expensive. - // allocate enough space for the object and the int header, which is - // defined by the language spec to be 32-bits (4 bytes). See if - // there's a way to dynamically/reliably determine the size of an int - // in Java, i.e., equivalent to sizeof operator in C. Then again, - // maybe Java will never change from having 32-bit ints. - ByteBuffer buffer = ByteBuffer.allocate(objectSize + INT_SIZE); - // int header specifying how big the object is is needed so that the - // other side can know how much data to expect to read. - buffer.putInt(objectSize); - buffer.put(data); - buffer.clear(); - channel.write(buffer); + synchronized (channel) { + final int objectSize = data.length; + // FIXME: could be a performance bottle-neck in the future, allocation + // can be expensive. + // allocate enough space for the object and the int header, which is + // defined by the language spec to be 32-bits (4 bytes). See if + // there's a way to dynamically/reliably determine the size of an int + // in Java, i.e., equivalent to sizeof operator in C. Then again, + // maybe Java will never change from having 32-bit ints. + ByteBuffer buffer = ByteBuffer.allocate(objectSize + BYTES_PER_INT); + // int header specifying how big the object is is needed so that the + // other side can know how much data to expect to read. + buffer.putInt(objectSize); + buffer.put(data); + buffer.clear(); + channel.write(buffer); + } } /** @@ -229,8 +252,9 @@ // something larger than the set READ_BUFFER_SIZE? We have to // deal with chunking that up. SocketChannel channel = (SocketChannel) key.channel(); - Identifier id = getIdentifier(channel); + Identifier id = getIdentifier(key); + // clear out the original buffer. buffer.clear(); channel.read(buffer); buffer.flip(); @@ -255,10 +279,14 @@ } catch (IOException e) { e.printStackTrace(); - requestDisconnection(getIdentifier(key.channel()), e); + requestDisconnection(getIdentifier(key), e); } } + private Identifier getIdentifier(SelectionKey key) { + return (Identifier) key.attachment(); + } + // XXX: assumes that pendingClients has been locked private void handleRequest(Identifier id, ByteBuffer buffer) { // get the size of the Object so we know how much data we expect to @@ -354,18 +382,22 @@ } protected void processIncomingConnections() throws IOException { - SocketChannel incoming = server.accept(); + final SocketChannel incoming = server.accept(); getLogger().debug("incoming connection: " + incoming); - // this takes care of the case where server is configured to non-block - if (incoming != null) { - incoming.configureBlocking(false); - Identifier id = new SocketIdentifier(incoming.socket()); - // write the identifier to the client - addMapping(id, incoming); - worker.process(incoming); - transmit(new ServerAssignedIdentifierEvent(id)); - getLocalEventHandler().handle(new ConnectionEvent(id)); - } + new Thread() { + public void run() { + Identifier id = worker.process(incoming); + System.err.println("generated id" + id); + addMapping(id, incoming); + // send the newly generated Identifier to the client dispatcher, + // which should be blocked, waiting for it. + ConnectionEvent connectionEvent = new ConnectionEvent(id); + transmit(connectionEvent); + // notify any interested parties that a new connection has been + // made with the given Identifier. + getLocalEventHandler().handle(connectionEvent); + } + }.start(); } private class NioDispatcherWorker implements Worker<SocketChannel> { @@ -395,11 +427,25 @@ return selector.keys().size(); } - public void process(SocketChannel o) { + /** + * Adds the incoming socket channel to the queue of channels to be registered + * and then blocks the currently executing thread. This call will block until + * the incoming SocketChannel has successfully registered with the Selector. + */ + + public Identifier process(SocketChannel incoming) { synchronized (channels) { - channels.add(o); + channels.add(incoming); } - selector.wakeup(); + synchronized (incoming) { + selector.wakeup(); + try { + incoming.wait(); + } catch (InterruptedException e) {} + } + Identifier id = new SocketIdentifier(incoming.socket()); + incoming.keyFor(selector).attach(id); + return id; } public void remove(SocketChannel channel) { @@ -428,7 +474,6 @@ StringBuilder msg = new StringBuilder(); msg.append(this + " has " + selector.keys().size() + " channels\n"); for (SocketChannel channel : channels) { -// SocketChannel channel = (SocketChannel) iter.next(); msg.append(" "); msg.append(channel.toString()); msg.append('\n'); @@ -461,7 +506,7 @@ } public void run() { - // assumesthat we don't need to worry about + // assumes that we don't need to worry about // multiple threads starting this, otherwise we need to lock // on the test-and-set here. if (running) return; @@ -483,13 +528,17 @@ e.printStackTrace(); continue; } + finally { + synchronized (incoming) { + incoming.notifyAll(); + } + } } } // handle incoming data. try { if ( selector.select() >= 0 ) { - for (Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); - iterator.hasNext(); ) + for (Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); iterator.hasNext(); ) { SelectionKey key = iterator.next(); NioDispatcher.this.readData(key, buffer); Modified: trunk/gee/src/java/edu/indiana/psych/gee/net/ServerSocketDispatcher.java =================================================================== --- trunk/gee/src/java/edu/indiana/psych/gee/net/ServerSocketDispatcher.java 2006-05-31 23:57:30 UTC (rev 187) +++ trunk/gee/src/java/edu/indiana/psych/gee/net/ServerSocketDispatcher.java 2006-06-18 18:34:40 UTC (rev 188) @@ -11,7 +11,6 @@ import edu.indiana.psych.gee.event.EventChannel; import edu.indiana.psych.gee.net.event.ConnectionEvent; import edu.indiana.psych.gee.net.event.DisconnectionEvent; -import edu.indiana.psych.gee.net.event.ServerAssignedIdentifierEvent; /** * $Id$ @@ -58,7 +57,7 @@ } public void transmit(Event event) { - Identifier id = event.id(); + Identifier id = event.getId(); if (id == null || id == Identifier.NULL) { // transmit to all connected clients if the target identifier is // not specified. @@ -93,11 +92,12 @@ Identifier id = new SocketIdentifier(incoming); // FIXME: consider pooling socket connections SocketDispatcherWorker worker = new SocketDispatcherWorker(this, id, incoming); - // immediately write a ServerAssignedIdentifierEvent to the incoming connection. - worker.write(new ServerAssignedIdentifierEvent(id)); + // immediately write a ConnectionEvent to the incoming connection. + ConnectionEvent event = new ConnectionEvent(id); + worker.write(event); workers.put(id, worker); worker.start(); - getLocalEventHandler().handle(new ConnectionEvent(id)); + getLocalEventHandler().handle(event); } protected void cleanup() { Modified: trunk/gee/src/java/edu/indiana/psych/gee/net/Worker.java =================================================================== --- trunk/gee/src/java/edu/indiana/psych/gee/net/Worker.java 2006-05-31 23:57:30 UTC (rev 187) +++ trunk/gee/src/java/edu/indiana/psych/gee/net/Worker.java 2006-06-18 18:34:40 UTC (rev 188) @@ -1,5 +1,7 @@ package edu.indiana.psych.gee.net; +import edu.indiana.psych.gee.Identifier; + // import java.nio.channels.SocketChannel; /** @@ -12,7 +14,7 @@ * @version $Revision$ */ public interface Worker<T> extends Runnable, Comparable { - public void process(T object); + public Identifier process(T object); public int numberOfJobs(); Modified: trunk/gee/src/java/edu/indiana/psych/gee/net/WorkerPool.java =================================================================== --- trunk/gee/src/java/edu/indiana/psych/gee/net/WorkerPool.java 2006-05-31 23:57:30 UTC (rev 187) +++ trunk/gee/src/java/edu/indiana/psych/gee/net/WorkerPool.java 2006-06-18 18:34:40 UTC (rev 188) @@ -5,11 +5,15 @@ import java.util.Map; import java.util.TreeSet; +import edu.indiana.psych.gee.Identifier; + /** * $Id$ * - * Pooled implementation for worker threads. The WorkerPool is a composite of - * the Worker. + * Very basic pooled implementation for worker threads. The WorkerPool is a composite of + * the Worker. + * + * FIXME: should just use Java 1.5 thread pools, i.e., ThreadPoolExecutor * * @author <a href='mailto:al...@cs...'>Allen Lee</a> * @version $Revision$ @@ -69,7 +73,7 @@ } } - public synchronized void process(T object) { + public synchronized Identifier process(T object) { Worker<T> worker = workers.first(); // this should always grab the first worker out. if (growable) { @@ -78,8 +82,8 @@ workers.add(worker); } } - worker.process(object); objectToWorkerMap.put(object, worker); + return worker.process(object); } public void report() { Deleted: trunk/gee/src/java/edu/indiana/psych/gee/net/event/ServerAssignedIdentifierEvent.java =================================================================== --- trunk/gee/src/java/edu/indiana/psych/gee/net/event/ServerAssignedIdentifierEvent.java 2006-05-31 23:57:30 UTC (rev 187) +++ trunk/gee/src/java/edu/indiana/psych/gee/net/event/ServerAssignedIdentifierEvent.java 2006-06-18 18:34:40 UTC (rev 188) @@ -1,23 +0,0 @@ -package edu.indiana.psych.gee.net.event; - -import edu.indiana.psych.gee.Identifier; -import edu.indiana.psych.gee.event.AbstractEvent; - -/** - * $Id$ - * - * Used to inform the client of the server assigned Identifier. - * - * - * @author Allen Lee - * @version $Revision$ - */ -public class ServerAssignedIdentifierEvent extends AbstractEvent -implements ExperimentUpdateEvent { - - private static final long serialVersionUID = -2258127108062718367L; - - public ServerAssignedIdentifierEvent(Identifier id) { - super(id); - } -} Added: trunk/gee/src/test/edu/indiana/psych/gee/net/NioDispatcherTester.java =================================================================== --- trunk/gee/src/test/edu/indiana/psych/gee/net/NioDispatcherTester.java (rev 0) +++ trunk/gee/src/test/edu/indiana/psych/gee/net/NioDispatcherTester.java 2006-06-18 18:34:40 UTC (rev 188) @@ -0,0 +1,68 @@ +package edu.indiana.psych.gee.net; + +import junit.framework.TestCase; +import edu.indiana.psych.gee.Identifier; +import edu.indiana.psych.gee.event.EventChannel; +import edu.indiana.psych.gee.event.EventTypeProcessor; +import edu.indiana.psych.gee.net.event.ConnectionEvent; + +/** + * $Id$ + * + * @author <a href='ano...@gm...'>Allen Lee</a> + * @version $Revision$ + */ + +public class NioDispatcherTester extends TestCase { + + private final static int DEFAULT_PORT = 16237; + + private NioDispatcher serverDispatcher; + private NioDispatcher clientDispatcher; + private EventChannel serverEventChannel; + private EventChannel clientEventChannel; + + private final Object notifier = new Object(); + private Identifier id; + + @Override + public void setUp() { + serverEventChannel = new EventChannel(); + clientEventChannel = new EventChannel(); + serverDispatcher = new NioDispatcher(serverEventChannel); + clientDispatcher = new NioDispatcher(clientEventChannel, 1); + } + + public void testConnect() throws Exception { + serverEventChannel.add(new EventTypeProcessor<ConnectionEvent>(ConnectionEvent.class) { + public void handle(ConnectionEvent event) { + synchronized (notifier) { + setIdentifier(event.getId()); + assertNotNull(event.getId()); + notifier.notifyAll(); + } + } + }); + serverDispatcher.listen(DEFAULT_PORT); + while (! serverDispatcher.isListening()) { + Thread.sleep(100); + } + synchronized (notifier) { + final Identifier clientId = connect(); + assertNotNull(clientId); + notifier.wait(); + assertEquals(clientId, id); + assertNotNull(id); + } + } + + private void setIdentifier(Identifier id) { + this.id = id; + } + + private Identifier connect() { + return clientDispatcher.connect("localhost", DEFAULT_PORT); + } + +} + Property changes on: trunk/gee/src/test/edu/indiana/psych/gee/net/NioDispatcherTester.java ___________________________________________________________________ Name: svn:keywords + Date Revision Id Deleted: trunk/gee/src/test/edu/indiana/psych/gee/net/SocketIdentifierTester.java =================================================================== --- trunk/gee/src/test/edu/indiana/psych/gee/net/SocketIdentifierTester.java 2006-05-31 23:57:30 UTC (rev 187) +++ trunk/gee/src/test/edu/indiana/psych/gee/net/SocketIdentifierTester.java 2006-06-18 18:34:40 UTC (rev 188) @@ -1,85 +0,0 @@ -package edu.indiana.psych.gee.net; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.util.Stack; - -import junit.framework.TestCase; - -/** - * $Id$ - * - * - * Exercises SocketIdentifier semantics. - * - * - * - * @author Team - * @version $Revision$ - */ -public class SocketIdentifierTester extends TestCase { - - private final static InetSocketAddress SERVER_SOCKET_ADDRESS = new InetSocketAddress(23732); - private ServerSocket serverSocket; - private Thread serverThread; - private Stack<Socket> acceptedSockets = new Stack<Socket>(); - - public SocketIdentifierTester(String name) { - super(name); - } - - public void setUp() throws IOException { - serverSocket = new ServerSocket(23732); - serverThread = new Thread() { - public void run() { - try { - while (serverThread != null) { - acceptedSockets.push(serverSocket.accept()); - } - } - catch (IOException e) { - throw new RuntimeException(e); - } - finally { - try { - serverSocket.close(); - } - catch (IOException e) { - throw new RuntimeException(e); - } - serverThread = null; - } - } - }; - serverThread.start(); - } - - public void tearDown() { - serverThread = null; - } - - public void testCollectionability() throws Exception { - Socket socket = new Socket(); - socket.connect(SERVER_SOCKET_ADDRESS); - SocketIdentifier localSocketIdentifier = new SocketIdentifier(socket); - SocketIdentifier remoteSocketIdentifier = new SocketIdentifier(acceptedSockets.pop()); - assertEquals("local socket identifier should .equals remote socket identifier", - remoteSocketIdentifier, localSocketIdentifier); - assertEquals("local socket identifier should .equals itself socket identifier", - localSocketIdentifier, localSocketIdentifier); - assertEquals(new SocketIdentifier(socket), localSocketIdentifier); - assertEquals(new SocketIdentifier(socket), remoteSocketIdentifier); - assertEquals("local and remote identifiers should hash the same", - localSocketIdentifier.hashCode(), - remoteSocketIdentifier.hashCode()); - socket = new Socket(); - socket.connect(SERVER_SOCKET_ADDRESS); - assertFalse(new SocketIdentifier(socket).equals(localSocketIdentifier)); - - assertFalse(new SocketIdentifier(socket).hashCode() == localSocketIdentifier.hashCode()); - - } - -} Modified: trunk/gee/war/WEB-INF/classes/xwork.xml =================================================================== --- trunk/gee/war/WEB-INF/classes/xwork.xml 2006-05-31 23:57:30 UTC (rev 187) +++ trunk/gee/war/WEB-INF/classes/xwork.xml 2006-06-18 18:34:40 UTC (rev 188) @@ -51,4 +51,5 @@ </package> <include file="gee-ajax.xml"/> <include file="gee-admin.xml"/> + <include file="gee-csan.xml"/> </xwork> Added: trunk/gee/war/WEB-INF/lib/dwr.jar =================================================================== (Binary files differ) Property changes on: trunk/gee/war/WEB-INF/lib/dwr.jar ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/gee/war/images/forager-v2/bot-back.gif =================================================================== (Binary files differ) Property changes on: trunk/gee/war/images/forager-v2/bot-back.gif ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/gee/war/images/forager-v2/bot-front.gif =================================================================== (Binary files differ) Property changes on: trunk/gee/war/images/forager-v2/bot-front.gif ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/gee/war/images/forager-v2/bot-side-left.gif =================================================================== (Binary files differ) Property changes on: trunk/gee/war/images/forager-v2/bot-side-left.gif ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/gee/war/images/forager-v2/bot-side-right.gif =================================================================== (Binary files differ) Property changes on: trunk/gee/war/images/forager-v2/bot-side-right.gif ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/gee/war/images/forager-v2/grass-1.gif =================================================================== (Binary files differ) Property changes on: trunk/gee/war/images/forager-v2/grass-1.gif ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/gee/war/images/forager-v2/grass-2.gif =================================================================== (Binary files differ) Property changes on: trunk/gee/war/images/forager-v2/grass-2.gif ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/gee/war/images/forager-v2/grass-3.gif =================================================================== (Binary files differ) Property changes on: trunk/gee/war/images/forager-v2/grass-3.gif ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/gee/war/images/forager-v2/grass-4.gif =================================================================== (Binary files differ) Property changes on: trunk/gee/war/images/forager-v2/grass-4.gif ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/gee/war/images/forager-v2/others-back.gif =================================================================== (Binary files differ) Property changes on: trunk/gee/war/images/forager-v2/others-back.gif ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/gee/war/images/forager-v2/others-front.gif =================================================================== (Binary files differ) Property changes on: trunk/gee/war/images/forager-v2/others-front.gif ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/gee/war/images/forager-v2/others-side-left.gif =================================================================== (Binary files differ) Property changes on: trunk/gee/war/images/forager-v2/others-side-left.gif ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/gee/war/images/forager-v2/others-side-right.gif =================================================================== (Binary files differ) Property changes on: trunk/gee/war/images/forager-v2/others-side-right.gif ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/gee/war/images/forager-v2/you-back.gif =================================================================== (Binary files differ) Property changes on: trunk/gee/war/images/forager-v2/you-back.gif ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/gee/war/images/forager-v2/you-front.gif =================================================================== (Binary files differ) Property changes on: trunk/gee/war/images/forager-v2/you-front.gif ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/gee/war/images/forager-v2/you-side-left.gif =================================================================== (Binary files differ) Property changes on: trunk/gee/war/images/forager-v2/you-side-left.gif ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/gee/war/images/forager-v2/you-side-right.gif =================================================================== (Binary files differ) Property changes on: trunk/gee/war/ima... [truncated message content] |