blob: c589812acf974a248332c2507fcdefa048ad17f5 [file] [log] [blame]
/**
* Copyright (c) 2006 Parity Communications, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Sergey Yakovlev - initial API and implementation
*/
package org.eclipse.ecf.internal.provider.rss.container;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.ecf.core.ContainerFactory;
import org.eclipse.ecf.core.ContainerTypeDescription;
import org.eclipse.ecf.core.IContainerListener;
import org.eclipse.ecf.core.events.ContainerConnectedEvent;
import org.eclipse.ecf.core.events.IContainerEvent;
import org.eclipse.ecf.core.identity.ID;
import org.eclipse.ecf.core.identity.IDCreateException;
import org.eclipse.ecf.core.identity.IDFactory;
import org.eclipse.ecf.core.identity.Namespace;
import org.eclipse.ecf.core.identity.StringID;
import org.eclipse.ecf.core.sharedobject.ISharedObject;
import org.eclipse.ecf.core.sharedobject.SharedObjectCreateException;
import org.eclipse.ecf.core.sharedobject.SharedObjectDescription;
import org.eclipse.ecf.core.sharedobject.SharedObjectFactory;
import org.eclipse.ecf.core.sharedobject.SharedObjectTypeDescription;
import org.eclipse.ecf.core.sharedobject.events.ISharedObjectActivatedEvent;
import org.eclipse.ecf.core.sharedobject.events.ISharedObjectDeactivatedEvent;
import org.eclipse.ecf.core.util.ECFException;
import org.eclipse.ecf.core.util.Trace;
import org.eclipse.ecf.datashare.IChannel;
import org.eclipse.ecf.datashare.IChannelConfig;
import org.eclipse.ecf.datashare.IChannelContainerListener;
import org.eclipse.ecf.datashare.IChannelListener;
import org.eclipse.ecf.datashare.events.IChannelContainerChannelActivatedEvent;
import org.eclipse.ecf.datashare.events.IChannelContainerChannelDeactivatedEvent;
import org.eclipse.ecf.datashare.events.IChannelContainerEvent;
import org.eclipse.ecf.datashare.events.IChannelEvent;
import org.eclipse.ecf.datashare.mergeable.IMergeableChannel;
import org.eclipse.ecf.datashare.mergeable.IMergeableChannelContainerAdapter;
import org.eclipse.ecf.internal.provider.rss.RssDebugOptions;
import org.eclipse.ecf.internal.provider.rss.RssPlugin;
import org.eclipse.ecf.internal.provider.rss.http.HttpClient;
import org.eclipse.ecf.provider.comm.ConnectionCreateException;
import org.eclipse.ecf.provider.comm.ISynchAsynchConnection;
import org.eclipse.ecf.provider.generic.ClientSOContainer;
import org.eclipse.ecf.provider.generic.SOContainerConfig;
import org.eclipse.higgins.rsse.RssFeed;
import org.eclipse.higgins.rsse.RssItem;
import org.eclipse.higgins.rsse.parser.FeedParser;
import org.eclipse.higgins.rsse.parser.ParseException;
import org.eclipse.higgins.rsse.util.RssVersion;
/**
* The RssClientSOContainer implements the basic RSS client functionality.
*
*/
public class RssClientSOContainer extends ClientSOContainer implements IMergeableChannelContainerAdapter {
public static final String DEFAULT_COMM_NAME = org.eclipse.ecf.internal.provider.rss.http.HttpClient.class.getName();
public static final int DEFAULT_KEEPALIVE = 30000;
int keepAlive = 0;
protected List channelContainerListener = Collections.synchronizedList(new ArrayList());
protected void fireChannelContainerListeners(IChannelContainerEvent event) {
synchronized (channelContainerListener) {
for (final Iterator i = channelContainerListener.iterator(); i.hasNext();) {
final IChannelContainerListener l = (IChannelContainerListener) i.next();
if (l != null)
l.handleChannelContainerEvent(event);
}
}
}
/**
* The constructors
*
* @throws IDCreateException
*/
public RssClientSOContainer() throws IDCreateException {
this(DEFAULT_KEEPALIVE);
}
public RssClientSOContainer(int keepAlive) throws IDCreateException {
this(IDFactory.getDefault().createGUID(), keepAlive);
}
public RssClientSOContainer(String userhost) throws IDCreateException {
this(userhost, DEFAULT_KEEPALIVE);
}
public RssClientSOContainer(String userhost, int keepAlive) throws IDCreateException {
this(IDFactory.getDefault().createStringID(userhost), keepAlive);
}
public RssClientSOContainer(ID containerId, int keepAlive) throws IDCreateException {
super(new SOContainerConfig(containerId));
this.keepAlive = keepAlive;
this.addListener(new ContainerListener());
}
protected class ContainerListener implements IContainerListener {
public void handleEvent(final IContainerEvent evt) {
if (evt instanceof ISharedObjectActivatedEvent) {
final ISharedObjectActivatedEvent soae = (ISharedObjectActivatedEvent) evt;
fireChannelContainerListeners(new IChannelContainerChannelActivatedEvent() {
public ID getChannelID() {
return soae.getActivatedID();
}
public ID getChannelContainerID() {
return soae.getLocalContainerID();
}
public String toString() {
final StringBuffer buf = new StringBuffer("ChannelActivatedEvent[");
buf.append("channelid=").append(soae.getActivatedID()).append(";");
buf.append("containerid=").append(soae.getLocalContainerID()).append("]");
return buf.toString();
}
});
} else if (evt instanceof ISharedObjectDeactivatedEvent) {
final ISharedObjectDeactivatedEvent sode = (ISharedObjectDeactivatedEvent) evt;
fireChannelContainerListeners(new IChannelContainerChannelDeactivatedEvent() {
public ID getChannelID() {
return sode.getDeactivatedID();
}
public ID getChannelContainerID() {
return sode.getLocalContainerID();
}
public String toString() {
final StringBuffer buf = new StringBuffer("ChannelDeactivatedEvent[");
buf.append("channelid=").append(sode.getDeactivatedID()).append(";");
buf.append("containerid=").append(sode.getLocalContainerID()).append("]");
return buf.toString();
}
});
}
}
}
protected void trace(String msg) {
Trace.trace(RssPlugin.PLUGIN_ID, RssDebugOptions.DEBUG, msg);
}
protected void dumpStack(String msg, Throwable e) {
Trace.catching(RssPlugin.PLUGIN_ID, RssDebugOptions.EXCEPTIONS_CATCHING, this.getClass(), "", e);
}
protected ISynchAsynchConnection createConnection(ID remoteSpace, Object data) throws ConnectionCreateException {
trace("createConnection:" + remoteSpace + ":" + data);
// Object[] args = { new Integer(keepAlive) };
final ISynchAsynchConnection conn = new HttpClient(receiver);
return conn;
}
protected ID handleConnectResponse(ID originalTarget, Object serverData) throws Exception {
trace("handleConnectResponse:" + originalTarget + ":" + serverData);
if (originalTarget != null && !originalTarget.equals(getID())) {
addNewRemoteMember(originalTarget, null);
// notify listeners
fireContainerEvent(new ContainerConnectedEvent(this.getID(), originalTarget));
}
return originalTarget;
}
public RssFeed receiveFeed(String feedPath) throws IOException {
RssFeed feed = null;
final ISynchAsynchConnection connection = getConnection();
synchronized (connection) {
if (connection.isConnected()) {
try {
feed = FeedParser.parse((byte[]) connection.sendSynch(null, feedPath.getBytes()));
} catch (final ParseException e) {
throw new IOException(e.getMessage());
}
}
}
return feed;
}
public Object getAdapter(Class clazz) {
if (clazz.equals(IMergeableChannelContainerAdapter.class)) {
return this;
} else {
return super.getAdapter(clazz);
}
}
public Namespace getChannelNamespace() {
return IDFactory.getDefault().getNamespaceByName(StringID.class.getName());
}
public IMergeableChannel createMergeableChannel(ID channelID, IChannelListener listener, Map properties) throws ECFException {
return createChannel(channelID, listener, properties);
}
public IMergeableChannel createChannel(final ID channelID, final IChannelListener listener, final Map properties) throws ECFException {
return createChannel(new IChannelConfig() {
public ID getID() {
return channelID;
}
public IChannelListener getListener() {
return listener;
}
public Object getAdapter(Class adapter) {
return null;
}
public Map getProperties() {
return properties;
}
});
}
public IMergeableChannel createChannel(IChannelConfig newChannelConfig) throws ECFException {
final IChannelListener listener = newChannelConfig.getListener();
final SharedObjectDescription sodesc = new SharedObjectDescription(FeedSharedObject.class, IDFactory.getDefault().createGUID(), new HashMap());
final SharedObjectTypeDescription sotypedesc = sodesc.getTypeDescription();
ISharedObject sharedObject = null;
if (sotypedesc.getName() != null) {
sharedObject = SharedObjectFactory.getDefault().createSharedObject(sotypedesc, new Object[] {listener});
} else {
sharedObject = createSharedObject(sotypedesc, listener);
}
final IMergeableChannel channel = (IMergeableChannel) sharedObject.getAdapter(IMergeableChannel.class);
if (channel == null) {
throw new SharedObjectCreateException("Cannot coerce object " + channel + " to be of type IChannel");
}
ID newID = sodesc.getID();
if (newID == null) {
newID = IDFactory.getDefault().createGUID();
}
Map properties = sodesc.getProperties();
if (properties == null) {
properties = new HashMap();
}
// Now add channel to container...this will block
getSharedObjectManager().addSharedObject(newID, sharedObject, properties);
return channel;
}
private ISharedObject createSharedObject(SharedObjectTypeDescription sotypedesc, IChannelListener listener) throws SharedObjectCreateException {
Class clazz;
try {
clazz = Class.forName(sotypedesc.getClassName());
} catch (final ClassNotFoundException e) {
throw new SharedObjectCreateException("No constructor for shared object of class " + sotypedesc.getClassName(), e);
}
Constructor cons = null;
try {
cons = clazz.getDeclaredConstructor(new Class[] {IChannelListener.class});
} catch (final NoSuchMethodException e) {
throw new SharedObjectCreateException("No constructor for shared object of class " + sotypedesc.getClassName(), e);
}
ISharedObject so = null;
try {
so = (ISharedObject) cons.newInstance(new Object[] {listener});
} catch (final Exception e) {
throw new SharedObjectCreateException("Cannot create instance of class " + sotypedesc.getClassName(), e);
}
return so;
}
public IChannel getChannel(ID channelID) {
return (IChannel) getSharedObjectManager().getSharedObject(channelID);
}
public boolean removeChannel(ID channelID) {
return (getSharedObjectManager().removeSharedObject(channelID) != null);
}
public static final void main(String[] args) throws Exception {
// Get server identity
// String targetURL =
// "http://"+java.net.InetAddress.getLocalHost().getHostName();
String targetURL = "http://feeds.feedburner.com";
if (args.length > 0) {
targetURL = args[0];
}
final ContainerTypeDescription contd = new ContainerTypeDescription(RssContainerInstantiator.class.getName(), RssContainerInstantiator.class.getName(), null);
ContainerFactory.getDefault().addDescription(contd);
final RssClientSOContainer container = new RssClientSOContainer();
// now connect to rss service
final ID serverID = IDFactory.getDefault().createStringID(targetURL);
container.connect(serverID, null);
// get IMergeableChannelContainer adapter
final IMergeableChannelContainerAdapter channelContainer = (IMergeableChannelContainerAdapter) container.getAdapter(IMergeableChannelContainerAdapter.class);
// create channel listener
final IChannelListener listener = new IChannelListener() {
public void handleChannelEvent(IChannelEvent event) {
System.out.println("listener.handleChannelEvent(" + event + ")");
}
};
// create a new channel
final ID channelID = IDFactory.getDefault().createStringID("/reuters/worldNews/");
// ID channelID = IDFactory.getDefault().createStringID("/feed.xml");
final IMergeableChannel channel = channelContainer.createMergeableChannel(channelID, listener, new HashMap());
if (channel instanceof FeedSharedObject) {
// get remote feed (subscribed)
final RssFeed remoteFeed = ((FeedSharedObject) channel).getFeed();
// get local feed (published)
final File feedFile = new File("feed.xml");
RssFeed localFeed = RssFeed.load(feedFile);
if (localFeed == null) {
localFeed = new RssFeed(remoteFeed.getTitle(), remoteFeed.getLink(), remoteFeed.getDescription());
localFeed.setVersion(RssVersion.RSS_2_0);
}
// merge remote feed with local one
localFeed.merge(remoteFeed);
// add a new item to feed
localFeed.addItem(new RssItem("New Google Item", "This is a new item", "http://www.google.com"));
// publish updated feed
localFeed.save(feedFile);
// print item titles
final java.util.List items = localFeed.getItems();
for (int i = 0; i < items.size(); i++) {
System.out.println(" " + i + " " + ((RssItem) items.get(i)).getTitle());
}
}
// remove the channel
channelContainer.removeChannel(channelID);
// disconnect the service
container.disconnect();
container.dispose();
System.out.println("Exiting.");
}
public void addListener(IChannelContainerListener listener) {
channelContainerListener.add(listener);
}
public void removeListener(IChannelContainerListener listener) {
channelContainerListener.add(listener);
}
}