| /** |
| * 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); |
| } |
| } |