Initial checkin of Propono

This commit is contained in:
kebernet 2011-04-01 04:48:20 +00:00
parent 1bea9af2e1
commit c1c4dd5923
78 changed files with 10647 additions and 0 deletions

58
CHANGES Normal file
View file

@ -0,0 +1,58 @@
ROME Propono Subproject
ROME Propono 0.6, September 30, 2007
------------------------------------
* Updated for APP final (draft #17) w/new APP URI "http://www.w3.org/2007/app"
* Tested file-based server against Tim Bray's Ape (from CVS September 30, 2007)
with some warning and one error that is apparently due to a bug in Ape.
* Now includes pre-release of ROME 0.9.1 with key Atom parse fixes.
* Changed arguements in Atom server's AtomHandler interface to accept
AtomRequest objects instead of String[] pathinfo arrays.
* Added support for relative URIs in the Service Document
- Fixes https://rome.dev.java.net/issues/show_bug.cgi?id=67
- Added Collection.getHrefResolved()
- Added Categories.getHrefResolved()
* Added new options to the file-based server's propono.properties file so you
can turn on/off relative URIs and inline categories.
propono.atomserver.filebased.relativeURIs=true
propono.atomserver.filebased.inlineCategories=true
* Added support for out-of-line categories in Atom client classes
- Added new Categories.href property
- New ClientCategories classes can fetch remote categories from href URI
- Fixes https://rome.dev.java.net/issues/show_bug.cgi?id=68
* Added support for out-of-line categories in Atom server classes
- New AtomHandler.getCategoriesDocument(String[] pathInfo) method
- New AtomHandler.isCategoriesDocumentURI(String[] pathInfo) method
* Renamed Introspection to Service Document
- AtomHandler.isIntrospectionURI() -> AtomHandler.isSerivceDocumentURI()
- AtomHandler.getIntrospection() -> AtomHandler.getServiceDocument()
- Added String[] pathInfo argument to getServiceDocument()
* Renamed PubControlModule to AppModule becuase it also supports app:edited
- Added rome.properties file to configure AppModule
ROME Propono 0.5, April 23, 2007
--------------------------------
* Fixes in Blog Client constructors
* AtomServlet uses application/atomsvc+xml for the Service Document
* Fixed issue #66: don't expect entry to be returned from update
* Made example builds more configurable
ROME Propono 0.4, April 10, 2007
--------------------------------
* Initial release

203
LICENSE Normal file
View file

@ -0,0 +1,203 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed 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.

26
NOTICE Normal file
View file

@ -0,0 +1,26 @@
Portions of the Propono code are Copyright (C) 2007 Sun Microsystems, Inc.
Sun Microsystems, Inc.
4150 Network Circle, Santa Clara, California 95054, U.S.A.
All rights reserved.
U.S. Government Rights - Commercial software. Government users are subject to
the Sun Microsystems, Inc. standard license agreement and applicable provisions
of the FAR and its supplements.
Use is subject to license terms.
This distribution may include materials developed by third parties.
Sun, Sun Microsystems, the Sun logo and Java are trademarks or registered
trademarks of Sun Microsystems, Inc. in the U.S. and other countries.
This product is covered and controlled by U.S. Export Control laws and may be
subject to the export or import laws in other countries. Nuclear, missile,
chemical biological weapons or nuclear maritime end uses or end users, whether
direct or indirect, are strictly prohibited. Export or reexport to countries
subject to U.S. embargo or to entities identified on U.S. export exclusion
lists, including, but not limited to, the denied persons and specially
designated nationals lists is strictly prohibited.

292
pom.xml Normal file
View file

@ -0,0 +1,292 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.rometools</groupId>
<artifactId>rome-propono</artifactId>\
<name>rome-propono</name>
<version>1.1-SNAPSHOT</version>
<packaging>jar</packaging>
<description>The ROME Propono subproject is a Java class library that
supports publishing protocols, specifically the Atom Publishing Protocol
and the legacy MetaWeblog API. Propono includes an Atom client library,
Atom server framework and a Blog client that supports both Atom protocol
and the MetaWeblog API.
</description>
<url>http://www.rometools.org</url>
<issueManagement>
<url>https://rometools.jira.com/browse/PROPONO</url>
</issueManagement>
<ciManagement>
<notifiers>
<notifier>
<configuration>
<address>dev@rome.dev.java.net</address>
</configuration>
</notifier>
</notifiers>
</ciManagement>
<inceptionYear>2007</inceptionYear>
<mailingLists>
<mailingList>
<name>dev@rome.dev.java.net</name>
<subscribe>
https://rome.dev.java.net/servlets/ProjectMailingListList
</subscribe>
<unsubscribe>
https://rome.dev.java.net/servlets/ProjectMailingListList
</unsubscribe>
<archive>
https://rome.dev.java.net/servlets/SummarizeList?listName=dev
</archive>
</mailingList>
</mailingLists>
<developers>
<developer>
<name>Dave Johnson</name>
<url>http://rollerweblogger.org/roller</url>
<timezone>-5</timezone>
</developer>
<developer>
<name>Robert Cooper</name>
<url>http://www.screaming-penguin.com</url>
<timezone>-4</timezone>
<email>kebernet@gmail.com</email>
</developer>
</developers>
<organization>
<name>ROME Project</name>
<url>http://www.rometools.org</url>
</organization>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<scm>
<connection>scm:svn:https://rometools.jira.com/svn/MODULES/trunk</connection>
<developerConnection>scm:svn:https://rometools.jira.com/svn/MODULES/trunk</developerConnection>
<url>https://rometools.jira.com/source/browse/MODULES</url>
</scm>
<repositories>
<repository>
<id>oauth</id>
<url>http://oauth.googlecode.com/svn/code/maven/</url>
</repository>
</repositories>
<build>
<defaultGoal>install</defaultGoal>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.0-beta-9</version>
<configuration>
<mavenExecutorId>forked-path</mavenExecutorId>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<excludePackageNames>com.sun.syndication.propono.atom.server.impl</excludePackageNames>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/Test*.java</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.rometools</groupId>
<artifactId>rome</artifactId>
<version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.0.4</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>ws-commons-util</groupId>
<artifactId>ws-commons-util</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>xmlrpc</groupId>
<artifactId>xmlrpc-client</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>xmlrpc</groupId>
<artifactId>xmlrpc-common</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>net.oauth.core</groupId>
<artifactId>oauth</artifactId>
<version>20090531</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.oauth.core</groupId>
<artifactId>oauth-provider</artifactId>
<version>20090531</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
<version>4.2.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<reporting>
<plugins>
<plugin>
<artifactId>maven-changes-plugin</artifactId>
<configuration>
<xmlPath>${basedir}/xdocs/changes.xml</xmlPath>
</configuration>
</plugin>
</plugins>
</reporting>
<distributionManagement>
<repository>
<id>sonatype-nexus-staging</id>
<name>Nexus Release Repository</name>
<url>http://oss.sonatype.org/service/local/staging/deploy/maven2</url>
</repository>
<snapshotRepository>
<id>sonatype-nexus-snapshots</id>
<name>Sonatype Nexus Snapshots</name>
<url>http://oss.sonatype.org/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>
<profiles>
<profile>
<id>release-sign-artifacts</id>
<activation>
<property>
<name>performRelease</name>
<value>true</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.0-alpha-4</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View file

@ -0,0 +1,47 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.client;
import com.sun.syndication.propono.utils.ProponoException;
import com.sun.syndication.io.impl.Atom10Parser;
/**
* Creates AtomService or ClientCollection based on username, password and
* end-point URI of Atom protocol service.
*/
public class AtomClientFactory {
static {
Atom10Parser.setResolveURIs(true);
}
/**
* Create AtomService by reading service doc from Atom Server.
*/
public static ClientAtomService getAtomService(
String uri, AuthStrategy authStrategy) throws ProponoException {
return new ClientAtomService(uri, authStrategy);
}
/**
* Create ClientCollection bound to URI.
*/
public static ClientCollection getCollection(
String uri, AuthStrategy authStrategy) throws ProponoException {
return new ClientCollection(uri, authStrategy);
}
}

View file

@ -0,0 +1,30 @@
/*
* Copyright 2007 Dave Johnson (Blogapps project)
*
* Licensed 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 com.sun.syndication.propono.atom.client;
import com.sun.syndication.propono.utils.ProponoException;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethodBase;
public interface AuthStrategy {
/**
* Add authentication credenticals, tokens, etc. to HTTP method
*/
void addAuthentication(HttpClient httpClient, HttpMethodBase method)
throws ProponoException;
}

View file

@ -0,0 +1,41 @@
/*
* Copyright 2009 Dave Johnson (Blogapps project)
*
* Licensed 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 com.sun.syndication.propono.atom.client;
import com.sun.syndication.io.impl.Base64;
import com.sun.syndication.propono.utils.ProponoException;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethodBase;
public class BasicAuthStrategy implements AuthStrategy {
private String credentials;
public BasicAuthStrategy(String username, String password) {
this.credentials =
new String(new Base64().encode((username + ":" + password).getBytes()));
}
public void init() throws ProponoException {
// op-op
}
public void addAuthentication(HttpClient httpClient, HttpMethodBase method) throws ProponoException {
httpClient.getParams().setAuthenticationPreemptive(true);
String header = "Basic " + credentials;
method.setRequestHeader("Authorization", header);
}
}

View file

@ -0,0 +1,138 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.client;
import com.sun.syndication.feed.atom.Entry;
import com.sun.syndication.io.impl.Atom10Parser;
import com.sun.syndication.propono.utils.ProponoException;
import com.sun.syndication.propono.atom.common.AtomService;
import java.io.InputStreamReader;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
/**
* This class models an Atom Publising Protocol Service Document.
* It extends the common
* {@link com.sun.syndication.propono.atom.common.Collection}
* class to add a <code>getEntry()</code> method and to return
* {@link com.sun.syndication.propono.atom.client.ClientWorkspace}
* objects instead of common
* {@link com.sun.syndication.propono.atom.common.Workspace}s.
*/
public class ClientAtomService extends AtomService {
private static Log logger = LogFactory.getLog(ClientAtomService.class);
private String uri = null;
private HttpClient httpClient = null;
private AuthStrategy authStrategy = null;
/**
* Create Atom blog service instance for specified URL and user account.
* @param url End-point URL of Atom service
*/
ClientAtomService(String uri, AuthStrategy authStrategy)
throws ProponoException {
this.uri = uri;
this.authStrategy = authStrategy;
Document doc = getAtomServiceDocument();
parseAtomServiceDocument(doc);
}
/**
* Get full entry from service by entry edit URI.
*/
public ClientEntry getEntry(String uri) throws ProponoException {
GetMethod method = new GetMethod(uri);
authStrategy.addAuthentication(httpClient, method);
try {
httpClient.executeMethod(method);
if (method.getStatusCode() != 200) {
throw new ProponoException("ERROR HTTP status code=" + method.getStatusCode());
}
Entry romeEntry = Atom10Parser.parseEntry(
new InputStreamReader(method.getResponseBodyAsStream()), uri);
if (!romeEntry.isMediaEntry()) {
return new ClientEntry(this, null, romeEntry, false);
} else {
return new ClientMediaEntry(this, null, romeEntry, false);
}
} catch (Exception e) {
throw new ProponoException("ERROR: getting or parsing entry/media", e);
} finally {
method.releaseConnection();
}
}
void addAuthentication(HttpMethodBase method) throws ProponoException {
authStrategy.addAuthentication(httpClient, method);
}
AuthStrategy getAuthStrategy() {
return authStrategy;
}
private Document getAtomServiceDocument() throws ProponoException {
GetMethod method = null;
int code = -1;
try {
httpClient = new HttpClient(new MultiThreadedHttpConnectionManager());
// TODO: make connection timeout configurable
httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(30000);
method = new GetMethod(uri);
authStrategy.addAuthentication(httpClient, method);
httpClient.executeMethod(method);
SAXBuilder builder = new SAXBuilder();
return builder.build(method.getResponseBodyAsStream());
} catch (Throwable t) {
String msg = "ERROR retrieving Atom Service Document, code: "+code;
logger.debug(msg, t);
throw new ProponoException(msg, t);
} finally {
if (method != null) method.releaseConnection();
}
}
/** Deserialize an Atom service XML document into an object */
private void parseAtomServiceDocument(Document document) throws ProponoException {
Element root = document.getRootElement();
List spaces = root.getChildren("workspace", AtomService.ATOM_PROTOCOL);
Iterator iter = spaces.iterator();
while (iter.hasNext()) {
Element e = (Element) iter.next();
addWorkspace(new ClientWorkspace(e, this, uri));
}
}
/**
* Package access to httpClient.
*/
HttpClient getHttpClient() {
return httpClient;
}
}

View file

@ -0,0 +1,70 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. 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. For additional information regarding
* copyright in this work, please see the NOTICE file in the top level
* directory of this distribution.
*/
package com.sun.syndication.propono.atom.client;
import com.sun.syndication.feed.atom.Category;
import com.sun.syndication.propono.atom.common.*;
import com.sun.syndication.propono.utils.ProponoException;
import java.io.IOException;
import java.io.InputStreamReader;
import org.apache.commons.httpclient.methods.GetMethod;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
/**
* Models an Atom protocol Categories element, which may contain ROME Atom
* {@link com.sun.syndication.feed.atom.Category} elements.
*/
public class ClientCategories extends Categories {
private ClientCollection clientCollection = null;
/** Load select from XML element */
public ClientCategories(Element e, ClientCollection clientCollection) throws ProponoException {
this.clientCollection = clientCollection;
parseCategoriesElement(e);
if (getHref() != null) fetchContents();
}
public void fetchContents() throws ProponoException {
GetMethod method = new GetMethod(getHrefResolved());
clientCollection.addAuthentication(method);
try {
clientCollection.getHttpClient().executeMethod(method);
if (method.getStatusCode() != 200) {
throw new ProponoException("ERROR HTTP status code=" + method.getStatusCode());
}
SAXBuilder builder = new SAXBuilder();
Document catsDoc = builder.build(
new InputStreamReader(method.getResponseBodyAsStream()));
parseCategoriesElement(catsDoc.getRootElement());
} catch (IOException ioe) {
throw new ProponoException(
"ERROR: reading out-of-line categories", ioe);
} catch (JDOMException jde) {
throw new ProponoException(
"ERROR: parsing out-of-line categories", jde);
} finally {
method.releaseConnection();
}
}
}

View file

@ -0,0 +1,217 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.client;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.io.InputStreamReader;
import com.sun.syndication.feed.atom.Entry;
import com.sun.syndication.io.impl.Atom10Parser;
import com.sun.syndication.propono.atom.common.AtomService;
import com.sun.syndication.propono.atom.common.Categories;
import com.sun.syndication.propono.utils.ProponoException;
import com.sun.syndication.propono.atom.common.Collection;
import com.sun.syndication.propono.atom.common.Workspace;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.methods.GetMethod;
import org.jdom.Element;
/**
* Models an Atom collection, extends Collection and adds methods for adding,
* retrieving, updateing and deleting entries.
*/
public class ClientCollection extends Collection {
static final Log logger = LogFactory.getLog(ClientCollection.class);
private List categories = new ArrayList();
private HttpClient httpClient = null;
private AuthStrategy authStrategy = null;
private boolean writable = true;
private ClientWorkspace workspace = null;
private ClientAtomService service = null;
ClientCollection(Element e, ClientWorkspace workspace, String baseURI) throws ProponoException {
super(e, baseURI);
this.workspace = workspace;
this.service = workspace.getAtomService();
this.httpClient = workspace.getAtomService().getHttpClient();
this.authStrategy = workspace.getAtomService().getAuthStrategy();
parseCollectionElement(e);
}
ClientCollection(String href, AuthStrategy authStrategy) throws ProponoException {
super("Standalone connection", "text", href);
this.authStrategy = authStrategy;
try {
httpClient = new HttpClient(new MultiThreadedHttpConnectionManager());
// TODO: make connection timeout configurable
httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(30000);
} catch (Throwable t) {
throw new ProponoException("ERROR creating HTTPClient", t);
}
}
void addAuthentication(HttpMethodBase method) throws ProponoException {
authStrategy.addAuthentication(httpClient, method);
}
/**
* Package access to httpClient to allow use by ClientEntry and ClientMediaEntry.
*/
HttpClient getHttpClient() {
return httpClient;
}
/**
* Get iterator over entries in this collection. Entries returned are
* considered to be partial entries cannot be saved/updated.
*/
public Iterator getEntries() throws ProponoException {
return new EntryIterator(this);
}
/**
* Get full entry specified by entry edit URI.
* Note that entry may or may not be associated with this collection.
* @return ClientEntry or ClientMediaEntry specified by URI.
*/
public ClientEntry getEntry(String uri) throws ProponoException {
GetMethod method = new GetMethod(uri);
authStrategy.addAuthentication(httpClient, method);
try {
httpClient.executeMethod(method);
if (method.getStatusCode() != 200) {
throw new ProponoException("ERROR HTTP status code=" + method.getStatusCode());
}
Entry romeEntry = Atom10Parser.parseEntry(
new InputStreamReader(method.getResponseBodyAsStream()), uri);
if (!romeEntry.isMediaEntry()) {
return new ClientEntry(service, this, romeEntry, false);
} else {
return new ClientMediaEntry(service, this, romeEntry, false);
}
} catch (Exception e) {
throw new ProponoException("ERROR: getting or parsing entry/media, HTTP code: ", e);
} finally {
method.releaseConnection();
}
}
/**
* Get workspace or null if collection is not associated with a workspace.
*/
public Workspace getWorkspace() {
return workspace;
}
/**
* Determines if collection is writable.
*/
public boolean isWritable() {
return writable;
}
/**
* Create new entry associated with collection, but do not save to server.
* @throws ProponoException if collecton is not writable.
*/
public ClientEntry createEntry() throws ProponoException {
if (!isWritable()) throw new ProponoException("Collection is not writable");
return new ClientEntry(service, this);
}
/**
* Create new media entry assocaited with collection, but do not save.
* server. Depending on the Atom server, you may or may not be able to
* persist the properties of the entry that is returned.
* @param title Title to used for uploaded file.
* @param slug String to be used in file-name of stored file
* @param contentType MIME content-type of file.
* @param bytes Data to be uploaded as byte array.
* @throws ProponoException if collecton is not writable
*/
public ClientMediaEntry createMediaEntry(
String title, String slug, String contentType, byte[] bytes)
throws ProponoException {
if (!isWritable()) throw new ProponoException("Collection is not writable");
return new ClientMediaEntry(service, this, title, slug, contentType, bytes);
}
/**
* Create new media entry assocaited with collection, but do not save.
* server. Depending on the Atom server, you may or may not be able to.
* persist the properties of the entry that is returned.
* @param title Title to used for uploaded file.
* @param slug String to be used in file-name of stored file
* @param contentType MIME content-type of file.
* @param is Data to be uploaded as InputStream.
* @throws ProponoException if collecton is not writable
*/
public ClientMediaEntry createMediaEntry(
String title, String slug, String contentType, InputStream is)
throws ProponoException {
if (!isWritable()) throw new ProponoException("Collection is not writable");
return new ClientMediaEntry(service, this, title, slug, contentType, is);
}
/**
* Save to collection a new entry that was created by a createEntry()
* or createMediaEntry() and save it to the server.
* @param entry Entry to be saved.
* @throws ProponoException on error, if collection is not writable or if entry is partial.
*/
public void addEntry(ClientEntry entry) throws ProponoException {
if (!isWritable()) throw new ProponoException("Collection is not writable");
entry.addToCollection(this);
}
protected void parseCollectionElement(Element element) throws ProponoException {
if (workspace == null) return;
setHref(element.getAttribute("href").getValue());
Element titleElem = element.getChild("title", AtomService.ATOM_FORMAT);
if (titleElem != null) {
setTitle(titleElem.getText());
if (titleElem.getAttribute("type", AtomService.ATOM_FORMAT) != null) {
setTitleType(titleElem.getAttribute("type", AtomService.ATOM_FORMAT).getValue());
}
}
List acceptElems = element.getChildren("accept", AtomService.ATOM_PROTOCOL);
if (acceptElems != null && acceptElems.size() > 0) {
for (Iterator it = acceptElems.iterator(); it.hasNext();) {
Element acceptElem = (Element)it.next();
addAccept(acceptElem.getTextTrim());
}
}
// Loop to parse <app:categories> element to Categories objects
List catsElems = element.getChildren("categories", AtomService.ATOM_PROTOCOL);
for (Iterator catsIter = catsElems.iterator(); catsIter.hasNext();) {
Element catsElem = (Element) catsIter.next();
Categories cats = new ClientCategories(catsElem, this);
addCategories(cats);
}
}
}

View file

@ -0,0 +1,259 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.client;
import com.sun.syndication.feed.atom.Content;
import com.sun.syndication.feed.atom.Link;
import com.sun.syndication.feed.atom.Entry;
import com.sun.syndication.io.impl.Atom10Generator;
import com.sun.syndication.io.impl.Atom10Parser;
import com.sun.syndication.propono.utils.ProponoException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import org.apache.commons.httpclient.methods.DeleteMethod;
import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.sun.syndication.propono.utils.Utilities;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.commons.httpclient.methods.PostMethod;
/**
* Client implementation of Atom entry, extends ROME Entry to add methods for
* easily getting/setting content, updating and removing the entry from the server.
*/
public class ClientEntry extends Entry {
private static final Log logger = LogFactory.getLog(ClientEntry.class);
boolean partial = false;
private ClientAtomService service = null;
private ClientCollection collection = null;
public ClientEntry(ClientAtomService service, ClientCollection collection) {
super();
this.service = service;
this.collection = collection;
}
public ClientEntry(ClientAtomService service, ClientCollection collection,
Entry entry, boolean partial) throws ProponoException {
super();
this.service = service;
this.collection = collection;
this.partial = partial;
try {
BeanUtils.copyProperties(this, entry);
} catch (Exception e) {
throw new ProponoException("ERROR: copying fields from ROME entry", e);
}
}
/**
* Set content of entry.
* @param contentString content string.
* @param type Must be "text" for plain text, "html" for escaped HTML,
* "xhtml" for XHTML or a valid MIME content-type.
*/
public void setContent(String contentString, String type) {
Content newContent = new Content();
newContent.setType(type == null ? Content.HTML : type);
newContent.setValue(contentString);
ArrayList contents = new ArrayList();
contents.add(newContent);
setContents(contents);
}
/**
* Convenience method to set first content object in content collection.
* Atom 1.0 allows only one content element per entry.
*/
public void setContent(Content c) {
ArrayList contents = new ArrayList();
contents.add(c);
setContents(contents);
}
/**
* Convenience method to get first content object in content collection.
* Atom 1.0 allows only one content element per entry.
*/
public Content getContent() {
if (getContents() != null && getContents().size() > 0) {
Content c = (Content)getContents().get(0);
return c;
}
return null;
}
/**
* Determines if entries are equal based on edit URI.
*/
public boolean equals(Object o) {
if (o instanceof ClientEntry) {
ClientEntry other = (ClientEntry)o;
if (other.getEditURI() != null && getEditURI() != null) {
return other.getEditURI().equals(getEditURI());
}
}
return false;
}
/**
* Update entry by posting new representation of entry to server.
* Note that you should not attempt to update entries that you get from
* iterating over a collection they may be "partial" entries. If you want
* to update an entry, you must get it via one of the <code>getEntry()</code>
* methods in
* {@link com.sun.syndication.propono.atom.common.Collection} or
* {@link com.sun.syndication.propono.atom.common.AtomService}.
* @throws ProponoException If entry is a "partial" entry.
*/
public void update() throws ProponoException {
if (partial) throw new ProponoException("ERROR: attempt to update partial entry");
EntityEnclosingMethod method = new PutMethod(getEditURI());
addAuthentication(method);
StringWriter sw = new StringWriter();
int code = -1;
try {
Atom10Generator.serializeEntry(this, sw);
method.setRequestEntity(new StringRequestEntity(sw.toString()));
method.setRequestHeader(
"Content-type", "application/atom+xml; charset=utf-8");
getHttpClient().executeMethod(method);
InputStream is = method.getResponseBodyAsStream();
if (method.getStatusCode() != 200 && method.getStatusCode() != 201) {
throw new ProponoException(
"ERROR HTTP status=" + method.getStatusCode() + " : " + Utilities.streamToString(is));
}
} catch (Exception e) {
String msg = "ERROR: updating entry, HTTP code: " + code;
logger.debug(msg, e);
throw new ProponoException(msg, e);
} finally {
method.releaseConnection();
}
}
/**
* Remove entry from server.
*/
public void remove() throws ProponoException {
if (getEditURI() == null) {
throw new ProponoException("ERROR: cannot delete unsaved entry");
}
DeleteMethod method = new DeleteMethod(getEditURI());
addAuthentication(method);
try {
getHttpClient().executeMethod(method);
} catch (IOException ex) {
throw new ProponoException("ERROR: removing entry, HTTP code", ex);
} finally {
method.releaseConnection();
}
}
void setCollection(ClientCollection collection) {
this.collection = collection;
}
ClientCollection getCollection() {
return collection;
}
/**
* Get the URI that can be used to edit the entry via HTTP PUT or DELETE.
*/
public String getEditURI() {
for (int i=0; i<getOtherLinks().size(); i++) {
Link link = (Link)getOtherLinks().get(i);
if (link.getRel() != null && link.getRel().equals("edit")) {
return link.getHrefResolved();
}
}
return null;
}
void addToCollection(ClientCollection col) throws ProponoException {
setCollection(col);
EntityEnclosingMethod method = new PostMethod(getCollection().getHrefResolved());
addAuthentication(method);
StringWriter sw = new StringWriter();
int code = -1;
try {
Atom10Generator.serializeEntry(this, sw);
method.setRequestEntity(new StringRequestEntity(sw.toString()));
method.setRequestHeader(
"Content-type", "application/atom+xml; charset=utf-8");
getHttpClient().executeMethod(method);
InputStream is = method.getResponseBodyAsStream();
code = method.getStatusCode();
if (code != 200 && code != 201) {
throw new ProponoException(
"ERROR HTTP status=" + code + " : " + Utilities.streamToString(is));
}
Entry romeEntry = Atom10Parser.parseEntry(
new InputStreamReader(is), getCollection().getHrefResolved());
BeanUtils.copyProperties(this, romeEntry);
} catch (Exception e) {
String msg = "ERROR: saving entry, HTTP code: " + code;
logger.debug(msg, e);
throw new ProponoException(msg, e);
} finally {
method.releaseConnection();
}
Header locationHeader = method.getResponseHeader("Location");
if (locationHeader == null) {
logger.warn("WARNING added entry, but no location header returned");
} else if (getEditURI() == null) {
List links = getOtherLinks();
Link link = new Link();
link.setHref(locationHeader.getValue());
link.setRel("edit");
links.add(link);
setOtherLinks(links);
}
}
void addAuthentication(HttpMethodBase method) throws ProponoException {
if (service != null) {
service.addAuthentication(method);
} else if (collection != null) {
collection.addAuthentication(method);
}
}
HttpClient getHttpClient() {
if (service != null) {
return service.getHttpClient();
} else if (collection != null) {
return collection.getHttpClient();
}
return null;
}
}

View file

@ -0,0 +1,322 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.client;
import com.sun.syndication.feed.atom.Content;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import com.sun.syndication.feed.atom.Entry;
import com.sun.syndication.feed.atom.Link;
import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.impl.Atom10Generator;
import com.sun.syndication.io.impl.Atom10Parser;
import com.sun.syndication.propono.utils.ProponoException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringWriter;
import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import com.sun.syndication.propono.utils.Utilities;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdom.JDOMException;
/**
* Client implementation of Atom media-link entry, an Atom entry that provides
* meta-data for a media file (e.g. uploaded image or audio file).
*/
public class ClientMediaEntry extends ClientEntry {
private static final Log logger = LogFactory.getLog(ClientMediaEntry.class);
private String slug = null;
private byte[] bytes;
private InputStream inputStream;
/**
* Create ClientMedieEntry for service and collection.
*/
public ClientMediaEntry(ClientAtomService service, ClientCollection collection) {
super(service, collection);
}
public ClientMediaEntry(ClientAtomService service, ClientCollection collection,
Entry entry, boolean partial) throws ProponoException {
super(service, collection, entry, partial);
}
public ClientMediaEntry(ClientAtomService service, ClientCollection collection,
String title, String slug, String contentType, InputStream is) {
this(service, collection);
this.inputStream = is;
setTitle(title);
setSlug(slug);
Content content = new Content();
content.setType(contentType);
List contents = new ArrayList();
contents.add(content);
setContents(contents);
}
public ClientMediaEntry(ClientAtomService service, ClientCollection collection,
String title, String slug, String contentType, byte[] bytes) {
this(service, collection);
this.bytes = bytes;
setTitle(title);
setSlug(slug);
Content content = new Content();
content.setType(contentType);
List contents = new ArrayList();
contents.add(content);
setContents(contents);
}
/**
* Get bytes of media resource associated with entry.
* @return Bytes or null if none available or if entry uses an InputStream instead.
*/
public byte[] getBytes() {
return bytes;
}
/**
* Set media resource data as a byte array, don't try this if you have already
* set the data as an InputStream.
*/
public void setBytes(byte[] bytes) {
if (inputStream != null) {
throw new IllegalStateException("ERROR: already has inputStream, cannot set both inputStream and bytes");
}
this.bytes = bytes;
}
/**
* Get input stream for media resource associated with this entry.
* @return InputStream or null if none available or if entry uses bytes instead.
*/
public InputStream getInputStream() {
return inputStream;
}
/**
* Set media resource data as an input stream, don't try this if you have already
* set the data as a byte array.
*/
public void setInputStream(InputStream inputStream) {
if (bytes != null) {
throw new IllegalStateException("ERROR: already has bytes, cannot set both bytes and inputStream");
}
this.inputStream = inputStream;
}
/**
* Get media link URI for editing the media resource associated with this
* entry via HTTP PUT or DELETE.
*/
public String getMediaLinkURI() {
for (int i=0; i<getOtherLinks().size(); i++) {
Link link = (Link)getOtherLinks().get(i);
if (link.getRel() != null && link.getRel().equals("edit-media")) {
return link.getHrefResolved();
}
}
return null;
}
/**
* Get media resource as an InputStream, should work regardless of whether
* you set the media resource data as an InputStream or as a byte array.
*/
public InputStream getAsStream() throws ProponoException {
if (getContents() != null && getContents().size() > 0) {
Content c = (Content)getContents().get(0);
if (c.getSrc() != null) {
return getResourceAsStream();
} else if (inputStream != null) {
return inputStream;
} else if (bytes != null) {
return new ByteArrayInputStream(bytes);
} else {
throw new ProponoException("ERROR: no src URI or binary data to return");
}
}
else {
throw new ProponoException("ERROR: no content found in entry");
}
}
private InputStream getResourceAsStream() throws ProponoException {
if (getEditURI() == null) {
throw new ProponoException("ERROR: not yet saved to server");
}
GetMethod method = new GetMethod(((Content)getContents()).getSrc());
try {
getCollection().getHttpClient().executeMethod(method);
if (method.getStatusCode() != 200) {
throw new ProponoException("ERROR HTTP status=" + method.getStatusCode());
}
return method.getResponseBodyAsStream();
} catch (IOException e) {
throw new ProponoException("ERROR: getting media entry", e);
}
}
/**
* Update entry on server.
*/
public void update() throws ProponoException {
if (partial) throw new ProponoException("ERROR: attempt to update partial entry");
EntityEnclosingMethod method = null;
Content updateContent = (Content)getContents().get(0);
try {
if (getMediaLinkURI() != null && getBytes() != null) {
// existing media entry and new file, so PUT file to edit-media URI
method = new PutMethod(getMediaLinkURI());
if (inputStream != null) {
method.setRequestEntity(new InputStreamRequestEntity(inputStream));
} else {
method.setRequestEntity(new InputStreamRequestEntity(new ByteArrayInputStream(getBytes())));
}
method.setRequestHeader("Content-type", updateContent.getType());
}
else if (getEditURI() != null) {
// existing media entry and NO new file, so PUT entry to edit URI
method = new PutMethod(getEditURI());
StringWriter sw = new StringWriter();
Atom10Generator.serializeEntry(this, sw);
method.setRequestEntity(new StringRequestEntity(sw.toString()));
method.setRequestHeader(
"Content-type", "application/atom+xml; charset=utf8");
} else {
throw new ProponoException("ERROR: media entry has no edit URI or media-link URI");
}
this.getCollection().addAuthentication(method);
method.addRequestHeader("Title", getTitle());
getCollection().getHttpClient().executeMethod(method);
if (inputStream != null) inputStream.close();
InputStream is = method.getResponseBodyAsStream();
if (method.getStatusCode() != 200 && method.getStatusCode() != 201) {
throw new ProponoException(
"ERROR HTTP status=" + method.getStatusCode() + " : " + Utilities.streamToString(is));
}
} catch (Exception e) {
throw new ProponoException("ERROR: saving media entry");
}
if (method.getStatusCode() != 201) {
throw new ProponoException("ERROR HTTP status=" + method.getStatusCode());
}
}
/** Package access, to be called by DefaultClientCollection */
void addToCollection(ClientCollection col) throws ProponoException {
setCollection(col);
EntityEnclosingMethod method = new PostMethod(col.getHrefResolved());
getCollection().addAuthentication(method);
StringWriter sw = new StringWriter();
boolean error = false;
try {
Content c = (Content)getContents().get(0);
if (inputStream != null) {
method.setRequestEntity(new InputStreamRequestEntity(inputStream));
} else {
method.setRequestEntity(new InputStreamRequestEntity(new ByteArrayInputStream(getBytes())));
}
method.setRequestHeader("Content-type", c.getType());
method.setRequestHeader("Title", getTitle());
method.setRequestHeader("Slug", getSlug());
getCollection().getHttpClient().executeMethod(method);
if (inputStream != null) inputStream.close();
InputStream is = method.getResponseBodyAsStream();
if (method.getStatusCode() == 200 || method.getStatusCode() == 201) {
Entry romeEntry = Atom10Parser.parseEntry(
new InputStreamReader(is), col.getHrefResolved());
BeanUtils.copyProperties(this, romeEntry);
} else {
throw new ProponoException(
"ERROR HTTP status-code=" + method.getStatusCode()
+ " status-line: " + method.getStatusLine());
}
} catch (IOException ie) {
throw new ProponoException("ERROR: saving media entry", ie);
} catch (JDOMException je) {
throw new ProponoException("ERROR: saving media entry", je);
} catch (FeedException fe) {
throw new ProponoException("ERROR: saving media entry", fe);
} catch (IllegalAccessException ae) {
throw new ProponoException("ERROR: saving media entry", ae);
} catch (InvocationTargetException te) {
throw new ProponoException("ERROR: saving media entry", te);
}
Header locationHeader = method.getResponseHeader("Location");
if (locationHeader == null) {
logger.warn("WARNING added entry, but no location header returned");
} else if (getEditURI() == null) {
List links = getOtherLinks();
Link link = new Link();
link.setHref(locationHeader.getValue());
link.setRel("edit");
links.add(link);
setOtherLinks(links);
}
}
/** Set string to be used in file name of new media resource on server. */
public String getSlug() {
return slug;
}
/** Get string to be used in file name of new media resource on server. */
public void setSlug(String slug) {
this.slug = slug;
}
}

View file

@ -0,0 +1,66 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.client;
import com.sun.syndication.propono.atom.common.AtomService;
import com.sun.syndication.propono.atom.common.Workspace;
import com.sun.syndication.propono.atom.common.Workspace;
import com.sun.syndication.propono.utils.ProponoException;
import java.util.Iterator;
import java.util.List;
import org.jdom.Element;
/**
* Represents Atom protocol workspace on client-side.
* It extends the common
* {@link com.sun.syndication.propono.atom.common.Workspace}
* to return
* {@link com.sun.syndication.propono.atom.client.ClientCollection}
* objects instead of common
* {@link com.sun.syndication.propono.atom.common.Collection}s.
*/
public class ClientWorkspace extends Workspace {
private ClientAtomService atomService = null;
ClientWorkspace(Element e, ClientAtomService atomService, String baseURI) throws ProponoException {
super("dummy", "dummy");
this.atomService = atomService;
parseWorkspaceElement(e, baseURI);
}
/**
* Package access to parent service.
*/
ClientAtomService getAtomService() {
return atomService;
}
/** Deserialize a Atom workspace XML element into an object */
protected void parseWorkspaceElement(Element element, String baseURI) throws ProponoException {
Element titleElem = element.getChild("title", AtomService.ATOM_FORMAT);
setTitle(titleElem.getText());
if (titleElem.getAttribute("type", AtomService.ATOM_FORMAT) != null) {
setTitleType(titleElem.getAttribute("type", AtomService.ATOM_FORMAT).getValue());
}
List collections = element.getChildren("collection", AtomService.ATOM_PROTOCOL);
Iterator iter = collections.iterator();
while (iter.hasNext()) {
Element e = (Element) iter.next();
addCollection(new ClientCollection(e, this, baseURI));
}
}
}

View file

@ -0,0 +1,124 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.client;
import com.sun.syndication.feed.atom.Entry;
import com.sun.syndication.feed.atom.Feed;
import com.sun.syndication.feed.atom.Link;
import com.sun.syndication.io.WireFeedInput;
import com.sun.syndication.propono.utils.ProponoException;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdom.Document;
import org.jdom.input.SAXBuilder;
/**
* Enables iteration over entries in Atom protocol collection.
*/
public class EntryIterator implements Iterator {
static final Log logger = LogFactory.getLog(EntryIterator.class);
private final ClientCollection collection;
int maxEntries = 20;
int offset = 0;
Iterator members = null;
Feed col = null;
String collectionURI;
String nextURI;
EntryIterator(ClientCollection collection) throws ProponoException {
this.collection = collection;
collectionURI = collection.getHrefResolved();
nextURI = collectionURI;
getNextEntries();
}
/**
* Returns true if more entries are available.
*/
public boolean hasNext() {
if (!members.hasNext()) {
try {
getNextEntries();
} catch (Exception ignored) {
logger.error("ERROR getting next entries", ignored);
}
}
return members.hasNext();
}
/**
* Get next entry in collection.
*/
public Object next() {
if (hasNext()) {
Entry romeEntry = (Entry)members.next();
try {
if (!romeEntry.isMediaEntry()) {
return new ClientEntry(null, collection, romeEntry, true);
} else {
return new ClientMediaEntry(null, collection, romeEntry, true);
}
} catch (ProponoException e) {
throw new RuntimeException("Unexpected exception creating ClientEntry or ClientMedia", e);
}
}
throw new NoSuchElementException();
}
/**
* Remove entry is not implemented.
*/
public void remove() {
// optional method, not implemented
}
private void getNextEntries() throws ProponoException {
if (nextURI == null) return;
GetMethod colGet = new GetMethod( collection.getHrefResolved(nextURI) );
collection.addAuthentication(colGet);
try {
collection.getHttpClient().executeMethod(colGet);
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(colGet.getResponseBodyAsStream());
WireFeedInput feedInput = new WireFeedInput();
col = (Feed) feedInput.build(doc);
} catch (Exception e) {
throw new ProponoException("ERROR: fetching or parsing next entries, HTTP code: " + (colGet != null ? colGet.getStatusCode() : -1), e);
} finally {
colGet.releaseConnection();
}
members = col.getEntries().iterator();
offset += col.getEntries().size();
nextURI = null;
List altLinks = col.getOtherLinks();
if (altLinks != null) {
Iterator iter = altLinks.iterator();
while (iter.hasNext()) {
Link link = (Link)iter.next();
if ("next".equals(link.getRel())) {
nextURI = link.getHref();
}
}
}
}
}

View file

@ -0,0 +1,67 @@
/*
* Copyright 2009 Dave Johnson (Blogapps project)
*
* Licensed 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 com.sun.syndication.propono.atom.client;
import com.sun.syndication.propono.utils.ProponoException;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.PostMethod;
public class GDataAuthStrategy implements AuthStrategy {
private String email;
private String password;
private String service;
private String authToken;
public GDataAuthStrategy(String email, String password, String service) throws ProponoException {
this.email = email;
this.password = password;
this.service = service;
init();
}
private void init() throws ProponoException {
try {
HttpClient httpClient = new HttpClient();
PostMethod method = new PostMethod("https://www.google.com/accounts/ClientLogin");
NameValuePair[] data = {
new NameValuePair("Email", email),
new NameValuePair("Passwd", password),
new NameValuePair("accountType", "GOOGLE"),
new NameValuePair("service", service),
new NameValuePair("source", "ROME Propono Atompub Client")
};
method.setRequestBody(data);
httpClient.executeMethod(method);
String responseBody = method.getResponseBodyAsString();
int authIndex = responseBody.indexOf("Auth=");
authToken = "GoogleLogin auth=" + responseBody.trim().substring(authIndex + 5);
} catch (Throwable t) {
t.printStackTrace();
throw new ProponoException("ERROR obtaining Google authentication string", t);
}
}
public void addAuthentication(HttpClient httpClient, HttpMethodBase method) throws ProponoException {
httpClient.getParams().setAuthenticationPreemptive(true);
method.setRequestHeader("Authorization", authToken);
}
}

View file

@ -0,0 +1,31 @@
/*
* Copyright 2009 Dave Johnson (Blogapps project)
*
* Licensed 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 com.sun.syndication.propono.atom.client;
import com.sun.syndication.propono.utils.ProponoException;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethodBase;
/**
* No authentication
*/
public class NoAuthStrategy implements AuthStrategy {
public void addAuthentication(HttpClient httpClient, HttpMethodBase method) throws ProponoException {
// no-op
}
}

View file

@ -0,0 +1,302 @@
/*
* Copyright 2009 Dave Johnson (Blogapps project)
*
* Licensed 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 com.sun.syndication.propono.atom.client;
import com.sun.syndication.propono.utils.ProponoException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import net.oauth.OAuth;
import net.oauth.OAuthAccessor;
import net.oauth.OAuthConsumer;
import net.oauth.OAuthMessage;
import net.oauth.OAuthServiceProvider;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.util.ParameterParser;
/**
* Strategy for using OAuth.
*/
public class OAuthStrategy implements AuthStrategy {
private State state = State.UNAUTHORIZED;
private enum State {
UNAUTHORIZED, // have not sent any requests
REQUEST_TOKEN, // have a request token
AUTHORIZED, // are authorized
ACCESS_TOKEN // have access token, ready to make calls
}
private String username;
private String consumerKey;
private String consumerSecret;
private String keyType;
private String reqUrl;
private String authzUrl;
private String accessUrl;
private String nonce;
private long timestamp;
private String requestToken = null;
private String accessToken = null;
private String tokenSecret = null;
/**
* Create OAuth authentcation strategy and negotiate with services to
* obtain access token to be used in subsequent calls.
*
* @param username Username to be used in authentication
* @param key Consumer key
* @param secret Consumer secret
* @param keyType Key type (e.g. "HMAC-SHA1")
* @param reqUrl URL of request token service
* @param authzUrl URL of authorize service
* @param accessUrl URL of acess token service
* @throws ProponoException on any sort of initialization error
*/
public OAuthStrategy(
String username, String key, String secret, String keyType,
String reqUrl, String authzUrl, String accessUrl) throws ProponoException {
this.username = username;
this.reqUrl = reqUrl;
this.authzUrl = authzUrl;
this.accessUrl = accessUrl;
this.consumerKey = key;
this.consumerSecret = secret;
this.keyType = keyType;
this.nonce = UUID.randomUUID().toString();
this.timestamp = (long)(new Date().getTime()/1000L);
init();
}
private void init() throws ProponoException {
callOAuthUri(reqUrl);
callOAuthUri(authzUrl);
callOAuthUri(accessUrl);
}
public void addAuthentication(HttpClient httpClient, HttpMethodBase method) throws ProponoException {
if (state != State.ACCESS_TOKEN) {
throw new ProponoException("ERROR: authentication strategy failed init");
}
// add OAuth name/values to request query string
// wish we didn't have to parse them apart first, ugh
List originalqlist = null;
if (method.getQueryString() != null) {
String qstring = method.getQueryString().trim();
qstring = qstring.startsWith("?") ? qstring.substring(1) : qstring;
originalqlist = new ParameterParser().parse(qstring, '&');
} else {
originalqlist = new ArrayList();
}
// put query string into hashmap form to please OAuth.net classes
Map params = new HashMap();
for (Iterator it = originalqlist.iterator(); it.hasNext();) {
NameValuePair pair = (NameValuePair)it.next();
params.put(pair.getName(), pair.getValue());
}
// add OAuth params to query string
params.put("xoauth_requestor_id", username);
params.put("oauth_consumer_key", consumerKey);
params.put("oauth_signature_method", keyType);
params.put("oauth_timestamp", Long.toString(timestamp));
params.put("oauth_nonce", nonce);
params.put("oauth_token", accessToken);
params.put("oauth_token_secret", tokenSecret);
// sign complete URI
String finalUri = null;
OAuthServiceProvider provider =
new OAuthServiceProvider(reqUrl, authzUrl, accessUrl);
OAuthConsumer consumer =
new OAuthConsumer(null, consumerKey, consumerSecret, provider);
OAuthAccessor accessor = new OAuthAccessor(consumer);
accessor.tokenSecret = tokenSecret;
OAuthMessage message;
try {
message = new OAuthMessage(
method.getName(), method.getURI().toString(), params.entrySet());
message.sign(accessor);
finalUri = OAuth.addParameters(message.URL, message.getParameters());
} catch (Exception ex) {
throw new ProponoException("ERROR: OAuth signing request", ex);
}
// pull query string off and put it back onto method
method.setQueryString(finalUri.substring(finalUri.lastIndexOf("?")));
}
private void callOAuthUri(String uri) throws ProponoException {
final HttpClient httpClient = new HttpClient();
final HttpMethodBase method;
final String content;
Map<String, String> params = new HashMap<String, String>();
if (params == null) {
params = new HashMap<String, String>();
}
params.put("oauth_version", "1.0");
if (username != null) {
params.put("xoauth_requestor_id", username);
}
params.put("oauth_consumer_key", consumerKey);
params.put("oauth_signature_method", keyType);
params.put("oauth_timestamp", Long.toString(timestamp));
params.put("oauth_nonce", nonce);
params.put("oauth_callback", "none");
OAuthServiceProvider provider =
new OAuthServiceProvider(reqUrl, authzUrl, accessUrl);
OAuthConsumer consumer =
new OAuthConsumer(null, consumerKey, consumerSecret, provider);
OAuthAccessor accessor = new OAuthAccessor(consumer);
if (state == State.UNAUTHORIZED) {
try {
OAuthMessage message = new OAuthMessage("GET", uri, params.entrySet());
message.sign(accessor);
String finalUri = OAuth.addParameters(message.URL, message.getParameters());
method = new GetMethod(finalUri);
httpClient.executeMethod(method);
content = method.getResponseBodyAsString();
} catch (Exception e) {
throw new ProponoException("ERROR fetching request token", e);
}
} else if (state == State.REQUEST_TOKEN) {
try {
params.put("oauth_token", requestToken);
params.put("oauth_token_secret", tokenSecret);
accessor.tokenSecret = tokenSecret;
OAuthMessage message = new OAuthMessage("POST", uri, params.entrySet());
message.sign(accessor);
String finalUri = OAuth.addParameters(message.URL, message.getParameters());
method = new PostMethod(finalUri);
httpClient.executeMethod(method);
content = method.getResponseBodyAsString();
} catch (Exception e) {
throw new ProponoException("ERROR fetching request token", e);
}
} else if (state == State.AUTHORIZED) {
try {
params.put("oauth_token", accessToken);
params.put("oauth_token_secret", tokenSecret);
accessor.tokenSecret = tokenSecret;
OAuthMessage message = new OAuthMessage("GET", uri, params.entrySet());
message.sign(accessor);
String finalUri = OAuth.addParameters(message.URL, message.getParameters());
method = new GetMethod(finalUri);
httpClient.executeMethod(method);
content = method.getResponseBodyAsString();
} catch (Exception e) {
throw new ProponoException("ERROR fetching request token", e);
}
} else {
method = null;
content = null;
return;
}
String token = null;
String secret = null;
if (content != null) {
String[] settings = content.split("&");
for (int i=0; i<settings.length; i++) {
String[] setting = settings[i].split("=");
if (setting.length > 1) {
if ("oauth_token".equals(setting[0])) {
token = setting[1];
} else if ("oauth_token_secret".equals(setting[0])) {
secret = setting[1];
}
}
}
}
switch (state) {
case UNAUTHORIZED:
if (token != null && secret != null) {
requestToken = token;
tokenSecret = secret;
state = State.REQUEST_TOKEN;
} else {
throw new ProponoException("ERROR: requestToken or tokenSecret is null");
}
break;
case REQUEST_TOKEN:
if (method.getStatusCode() == 200) {
state = State.AUTHORIZED;
} else {
throw new ProponoException("ERROR: authorization returned code: " + method.getStatusCode());
}
break;
case AUTHORIZED:
if (token != null && secret != null) {
accessToken = token;
tokenSecret = secret;
state = State.ACCESS_TOKEN;
} else {
throw new ProponoException("ERROR: accessToken or tokenSecret is null");
}
break;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View file

@ -0,0 +1,122 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. 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. For additional information regarding
* copyright in this work, please see the NOTICE file in the top level
* directory of this distribution.
*/
package com.sun.syndication.propono.atom.common;
import com.sun.syndication.propono.utils.ProponoException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.Namespace;
/**
* Models an Atom Publishing Protocol Service Document.
* Is able to read a Service document from a JDOM Document
* and to write Service document out as a JDOM Document.
*/
public class AtomService {
private List workspaces = new ArrayList();
/** Namespace for Atom Syndication Format */
public static Namespace ATOM_FORMAT =
Namespace.getNamespace("atom","http://www.w3.org/2005/Atom");
/** Namespace for Atom Publishing Protocol */
public static Namespace ATOM_PROTOCOL =
Namespace.getNamespace("app","http://www.w3.org/2007/app");
/**
* Create new and empty Atom service
*/
public AtomService() {
}
/**
* Add Workspace to service.
*/
public void addWorkspace(Workspace workspace) {
workspaces.add(workspace);
}
/**
* Get Workspaces available from service.
*/
public List getWorkspaces() {
return workspaces;
}
/**
* Set Workspaces of service.
*/
public void setWorkspaces(List workspaces) {
this.workspaces = workspaces;
}
/**
* Find workspace by title.
* @param title Match this title
* @return Matching Workspace or null if none found.
*/
public Workspace findWorkspace(String title) {
for (Iterator it = workspaces.iterator(); it.hasNext();) {
Workspace ws = (Workspace) it.next();
if (title.equals(ws.getTitle())) {
return ws;
}
}
return null;
}
/**
* Deserialize an Atom service XML document into an object
*/
public static AtomService documentToService(Document document) throws ProponoException {
AtomService service = new AtomService();
Element root = document.getRootElement();
List spaces = root.getChildren("workspace", ATOM_PROTOCOL);
Iterator iter = spaces.iterator();
while (iter.hasNext()) {
Element e = (Element) iter.next();
service.addWorkspace(Workspace.elementToWorkspace(e));
}
return service;
}
/**
* Serialize an AtomService object into an XML document
*/
public Document serviceToDocument() {
AtomService service = this;
Document doc = new Document();
Element root = new Element("service", ATOM_PROTOCOL);
doc.setRootElement(root);
Iterator iter = service.getWorkspaces().iterator();
while (iter.hasNext()) {
Workspace space = (Workspace) iter.next();
root.addContent(space.workspaceToElement());
}
return doc;
}
}

View file

@ -0,0 +1,155 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. 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. For additional information regarding
* copyright in this work, please see the NOTICE file in the top level
* directory of this distribution.
*/
package com.sun.syndication.propono.atom.common;
import com.sun.syndication.feed.atom.Category;
import com.sun.syndication.io.impl.Atom10Parser;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.jdom.Element;
/**
* Models an Atom protocol Categories element, which may contain ROME Atom
* {@link com.sun.syndication.feed.atom.Category} elements.
*/
public class Categories {
private List categories = new ArrayList(); // of Category objects
private String baseURI = null;
private Element categoriesElement = null;
private String href = null;
private String scheme = null;
private boolean fixed = false;
public Categories() {
}
/** Load select from XML element */
public Categories(Element e, String baseURI) {
this.categoriesElement = e;
this.baseURI = baseURI;
parseCategoriesElement(e);
}
/** Add category list of those specified */
public void addCategory(Category cat) {
categories.add(cat);
}
/**
* Iterate over Category objects
* @return List of ROME Atom {@link com.sun.syndication.feed.atom.Category}
*/
public List getCategories() {
return categories;
}
/** True if clients MUST use one of the categories specified */
public boolean isFixed() {
return fixed;
}
/** True if clients MUST use one of the categories specified */
public void setFixed(boolean fixed) {
this.fixed = fixed;
}
/** Category URI scheme to use for Categories without a scheme */
public String getScheme() {
return scheme;
}
/** Category URI scheme to use for Categories without a scheme */
public void setScheme(String scheme) {
this.scheme = scheme;
}
/** URI of out-of-line categories */
public String getHref() {
return href;
}
/** URI of out-of-line categories */
public void setHref(String href) {
this.href = href;
}
/** Get unresolved URI of the collection, or null if impossible to determine */
public String getHrefResolved() {
if (Atom10Parser.isAbsoluteURI(href)) {
return href;
} else if (baseURI != null && categoriesElement != null) {
return Atom10Parser.resolveURI(
baseURI, categoriesElement, href);
}
return null;
}
public Element categoriesToElement() {
Categories cats = this;
Element catsElem = new Element("categories", AtomService.ATOM_PROTOCOL);
catsElem.setAttribute("fixed", cats.isFixed() ? "yes" : "no", AtomService.ATOM_PROTOCOL);
if (cats.getScheme() != null) {
catsElem.setAttribute("scheme", cats.getScheme(), AtomService.ATOM_PROTOCOL);
}
if (cats.getHref() != null) {
catsElem.setAttribute("href", cats.getHref(), AtomService.ATOM_PROTOCOL);
} else {
// Loop to create <atom:category> elements
for (Iterator catIter = cats.getCategories().iterator(); catIter.hasNext();) {
Category cat = (Category) catIter.next();
Element catElem = new Element("category", AtomService.ATOM_FORMAT);
catElem.setAttribute("term", cat.getTerm(), AtomService.ATOM_FORMAT);
if (cat.getScheme() != null) { // optional
catElem.setAttribute("scheme", cat.getScheme(), AtomService.ATOM_FORMAT);
}
if (cat.getLabel() != null) { // optional
catElem.setAttribute("label", cat.getLabel(), AtomService.ATOM_FORMAT);
}
catsElem.addContent(catElem);
}
}
return catsElem;
}
protected void parseCategoriesElement(Element catsElem) {
if (catsElem.getAttribute("href", AtomService.ATOM_PROTOCOL) != null) {
setHref(catsElem.getAttribute("href", AtomService.ATOM_PROTOCOL).getValue());
}
if (catsElem.getAttribute("fixed", AtomService.ATOM_PROTOCOL) != null) {
if ("yes".equals(catsElem.getAttribute("fixed", AtomService.ATOM_PROTOCOL).getValue())) {
setFixed(true);
}
}
if (catsElem.getAttribute("scheme", AtomService.ATOM_PROTOCOL) != null) {
setScheme(catsElem.getAttribute("scheme", AtomService.ATOM_PROTOCOL).getValue());
}
// Loop to parse <atom:category> elemenents to Category objects
List catElems = catsElem.getChildren("category", AtomService.ATOM_FORMAT);
for (Iterator catIter = catElems.iterator(); catIter.hasNext();) {
Element catElem = (Element) catIter.next();
Category cat = new Category();
cat.setTerm(catElem.getAttributeValue("term", AtomService.ATOM_FORMAT));
cat.setLabel(catElem.getAttributeValue("label", AtomService.ATOM_FORMAT));
cat.setScheme(catElem.getAttributeValue("scheme", AtomService.ATOM_FORMAT));
addCategory(cat);
}
}
}

View file

@ -0,0 +1,252 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. 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. For additional information regarding
* copyright in this work, please see the NOTICE file in the top level
* directory of this distribution.
*/
package com.sun.syndication.propono.atom.common;
import com.sun.syndication.io.impl.Atom10Parser;
import com.sun.syndication.propono.utils.ProponoException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.jdom.Element;
/**
* Models an Atom workspace collection.
*/
public class Collection {
public static final String ENTRY_TYPE = "application/atom+xml;type=entry";
private Element collectionElement = null;
private String baseURI = null;
private String title = null;
private String titleType = null; // may be TEXT, HTML, XHTML
private List accepts = new ArrayList(); // of Strings
private String listTemplate = null;
private String href = null;
private List categories = new ArrayList(); // of Categories objects
/**
* Collection MUST have title and href.
* @param title Title for collection
* @param titleType Content type of title (null for plain text)
* @param href Collection URI.
*/
public Collection(String title, String titleType, String href) {
this.title = title;
this.titleType = titleType;
this.href = href;
}
/** Load self from XML element */
public Collection(Element e) throws ProponoException {
this.collectionElement = e;
this.parseCollectionElement(e);
}
/** Load self from XML element and base URI for resolving relative URIs */
public Collection(Element e, String baseURI) throws ProponoException {
this.collectionElement = e;
this.baseURI = baseURI;
this.parseCollectionElement(e);
}
/**
* List of content-type ranges accepted by collection.
*/
public List getAccepts() {
return accepts;
}
public void addAccept(String accept) {
this.accepts.add(accept);
}
public void setAccepts(List accepts) {
this.accepts = accepts;
}
/** The URI of the collection */
public String getHref() {
return href;
}
/**
* Set URI of collection
*/
public void setHref(String href) {
this.href = href;
}
/** Get resolved URI of the collection, or null if impossible to determine */
public String getHrefResolved() {
if (Atom10Parser.isAbsoluteURI(href)) {
return href;
} else if (baseURI != null && collectionElement != null) {
int lastslash = baseURI.lastIndexOf("/");
return Atom10Parser.resolveURI(baseURI.substring(0, lastslash), collectionElement, href);
}
return null;
}
/** Get resolved URI using collection's baseURI, or null if impossible to determine */
public String getHrefResolved(String relativeUri) {
if (Atom10Parser.isAbsoluteURI(relativeUri)) {
return relativeUri;
} else if (baseURI != null && collectionElement != null) {
int lastslash = baseURI.lastIndexOf("/");
return Atom10Parser.resolveURI(baseURI.substring(0, lastslash), collectionElement, relativeUri);
}
return null;
}
/** Must have human readable title */
public String getTitle() {
return title;
}
/**
* Set title of collection.
*/
public void setTitle(String title) {
this.title = title;
}
/**
* Type of title ("text", "html" or "xhtml")
*/
public String getTitleType() {
return titleType;
}
/**
* Type of title ("text", "html" or "xhtml")
*/
public void setTitleType(String titleType) {
this.titleType = titleType;
}
/** Workspace can have multiple Categories objects */
public void addCategories(Categories cats) {
categories.add(cats);
}
/**
* Get categories allowed by collection.
* @return Collection of {@link com.sun.syndication.propono.atom.common.Categories} objects.
*/
public List getCategories() {
return categories;
}
/**
* Returns true if contentType is accepted by collection.
*/
public boolean accepts(String ct) {
for (Iterator it = accepts.iterator(); it.hasNext();) {
String accept = (String)it.next();
if (accept != null && accept.trim().equals("*/*")) return true;
String entryType = "application/atom+xml";
boolean entry = entryType.equals(ct);
if (entry && null == accept) {
return true;
} else if (entry && "entry".equals(accept)) {
return true;
} else if (entry && entryType.equals(accept)) {
return true;
} else {
String[] rules = (String[])accepts.toArray(new String[accepts.size()]);
for (int i=0; i<rules.length; i++) {
String rule = rules[i].trim();
if (rule.equals(ct)) return true;
int slashstar = rule.indexOf("/*");
if (slashstar > 0) {
rule = rule.substring(0, slashstar + 1);
if (ct.startsWith(rule)) return true;
}
}
}
}
return false;
}
/**
* Serialize an AtomService.Collection into an XML element
*/
public Element collectionToElement() {
Collection collection = this;
Element element = new Element("collection", AtomService.ATOM_PROTOCOL);
element.setAttribute("href", collection.getHref());
Element titleElem = new Element("title", AtomService.ATOM_FORMAT);
titleElem.setText(collection.getTitle());
if (collection.getTitleType() != null && !collection.getTitleType().equals("TEXT")) {
titleElem.setAttribute("type", collection.getTitleType(), AtomService.ATOM_FORMAT);
}
element.addContent(titleElem);
// Loop to create <app:categories> elements
for (Iterator it = collection.getCategories().iterator(); it.hasNext();) {
Categories cats = (Categories)it.next();
element.addContent(cats.categoriesToElement());
}
for (Iterator it = collection.getAccepts().iterator(); it.hasNext();) {
String range = (String)it.next();
Element acceptElem = new Element("accept", AtomService.ATOM_PROTOCOL);
acceptElem.setText(range);
element.addContent(acceptElem);
}
return element;
}
/** Deserialize an Atom service collection XML element into an object */
public Collection elementToCollection(Element element) throws ProponoException {
return new Collection(element);
}
protected void parseCollectionElement(Element element) throws ProponoException {
setHref(element.getAttribute("href").getValue());
Element titleElem = element.getChild("title", AtomService.ATOM_FORMAT);
if (titleElem != null) {
setTitle(titleElem.getText());
if (titleElem.getAttribute("type", AtomService.ATOM_FORMAT) != null) {
setTitleType(titleElem.getAttribute("type", AtomService.ATOM_FORMAT).getValue());
}
}
List acceptElems = element.getChildren("accept", AtomService.ATOM_PROTOCOL);
if (acceptElems != null && acceptElems.size() > 0) {
for (Iterator it = acceptElems.iterator(); it.hasNext();) {
Element acceptElem = (Element)it.next();
addAccept(acceptElem.getTextTrim());
}
}
// Loop to parse <app:categories> element to Categories objects
List catsElems = element.getChildren("categories", AtomService.ATOM_PROTOCOL);
for (Iterator catsIter = catsElems.iterator(); catsIter.hasNext();) {
Element catsElem = (Element) catsIter.next();
Categories cats = new Categories(catsElem, baseURI);
addCategories(cats);
}
}
}

View file

@ -0,0 +1,147 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. 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. For additional information regarding
* copyright in this work, please see the NOTICE file in the top level
* directory of this distribution.
*/
package com.sun.syndication.propono.atom.common;
import com.sun.syndication.propono.utils.ProponoException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.jdom.Element;
/**
* Models an Atom workspace.
*/
public class Workspace {
private String title = null;
private String titleType = null; // may be TEXT, HTML, XHTML
private List collections = new ArrayList();
/**
* Collection MUST have title.
* @param title Title for collection
* @param titleType Content type of title (null for plain text)
*/
public Workspace(String title, String titleType) {
this.title = title;
this.titleType = titleType;
}
public Workspace(Element elem) throws ProponoException {
parseWorkspaceElement(elem);
}
/** Iterate over collections in workspace */
public List getCollections() {
return collections;
}
/** Add new collection to workspace */
public void addCollection(Collection col) {
collections.add(col);
}
/**
* DefaultWorkspace must have a human readable title
*/
public String getTitle() {
return title;
}
/**
* Set title of workspace.
*/
public void setTitle(String title) {
this.title = title;
}
/**
* Get title type ("text", "html", "xhtml" or MIME content-type)
*/
public String getTitleType() {
return titleType;
}
/**
* Set title type ("text", "html", "xhtml" or MIME content-type)
*/
public void setTitleType(String titleType) {
this.titleType = titleType;
}
/**
* Find collection by title and/or content-type.
* @param title Title or null to match all titles.
* @param contentType Content-type or null to match all content-types.
* @return First Collection that matches title and/or content-type.
*/
public Collection findCollection(String title, String contentType) {
for (Iterator it = collections.iterator(); it.hasNext();) {
Collection col = (Collection) it.next();
if (title != null && col.accepts(contentType)) {
return col;
} else if (col.accepts(contentType)) {
return col;
}
}
return null;
}
/** Deserialize a Atom workspace XML element into an object */
public static Workspace elementToWorkspace(Element element) throws ProponoException {
return new Workspace(element);
}
/**
* Serialize an AtomService.DefaultWorkspace object into an XML element
*/
public Element workspaceToElement() {
Workspace space = this;
Element element = new Element("workspace", AtomService.ATOM_PROTOCOL);
Element titleElem = new Element("title", AtomService.ATOM_FORMAT);
titleElem.setText(space.getTitle());
if (space.getTitleType() != null && !space.getTitleType().equals("TEXT")) {
titleElem.setAttribute("type", space.getTitleType(), AtomService.ATOM_FORMAT);
}
element.addContent(titleElem);
Iterator iter = space.getCollections().iterator();
while (iter.hasNext()) {
Collection col = (Collection) iter.next();
element.addContent(col.collectionToElement());
}
return element;
}
/** Deserialize a Atom workspace XML element into an object */
protected void parseWorkspaceElement(Element element) throws ProponoException {
Element titleElem = element.getChild("title", AtomService.ATOM_FORMAT);
setTitle(titleElem.getText());
if (titleElem.getAttribute("type", AtomService.ATOM_FORMAT) != null) {
setTitleType(titleElem.getAttribute("type", AtomService.ATOM_FORMAT).getValue());
}
List collections = element.getChildren("collection", AtomService.ATOM_PROTOCOL);
Iterator iter = collections.iterator();
while (iter.hasNext()) {
Element e = (Element) iter.next();
addCollection(new Collection(e));
}
}
}

View file

@ -0,0 +1,42 @@
/*
* Copyright 2007 Apache Software Foundation
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. 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. For additional information regarding
* copyright in this work, please see the NOTICE file in the top level
* directory of this distribution.
*/
package com.sun.syndication.propono.atom.common.rome;
import com.sun.syndication.feed.module.Module;
import java.util.Date;
/**
* ROME Extension Module to Atom protocol extensions to Atom format.
*/
public interface AppModule extends Module {
public static final String URI = "http://www.w3.org/2007/app";
/** True if entry is a draft */
public Boolean getDraft();
/** Set to true if entry is a draft */
public void setDraft(Boolean draft);
/** Time of last edit */
public Date getEdited();
/** Set time of last edit */
public void setEdited(Date edited);
}

View file

@ -0,0 +1,85 @@
/*
* Copyright 2007 Apache Software Foundation
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. 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. For additional information regarding
* copyright in this work, please see the NOTICE file in the top level
* directory of this distribution.
*/
package com.sun.syndication.propono.atom.common.rome;
import com.sun.syndication.io.impl.DateParser;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.jdom.Element;
import org.jdom.Namespace;
import com.sun.syndication.feed.module.Module;
import com.sun.syndication.io.ModuleGenerator;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.TimeZone;
/**
* Creates JDOM representation for APP Extension Module.
*/
public class AppModuleGenerator implements ModuleGenerator {
private static final Namespace APP_NS =
Namespace.getNamespace("app", AppModule.URI);
public String getNamespaceUri() {
return AppModule.URI;
}
private static final Set NAMESPACES;
static {
Set nss = new HashSet();
nss.add(APP_NS);
NAMESPACES = Collections.unmodifiableSet(nss);
}
/** Get namespaces associated with this module */
public Set getNamespaces() {
return NAMESPACES;
}
/** Generate JDOM element for module and add it to parent element */
public void generate(Module module, Element parent) {
AppModule m = (AppModule)module;
if (m.getDraft() != null) {
String draft = m.getDraft().booleanValue() ? "yes" : "no";
Element control = new Element("control", APP_NS);
control.addContent(generateSimpleElement("draft", draft));
parent.addContent(control);
}
if (m.getEdited() != null) {
Element edited = new Element("edited", APP_NS);
// Inclulde millis in date/time
SimpleDateFormat dateFormater = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
dateFormater.setTimeZone(TimeZone.getTimeZone("GMT"));
edited.addContent(dateFormater.format(m.getEdited()));
parent.addContent(edited);
}
}
private Element generateSimpleElement(String name, String value) {
Element element = new Element(name, APP_NS);
element.addContent(value);
return element;
}
}

View file

@ -0,0 +1,69 @@
/*
* Copyright 2007 Apache Software Foundation
* Copyright 2011 The ROME Teams
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. 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. For additional information regarding
* copyright in this work, please see the NOTICE file in the top level
* directory of this distribution.
*/
package com.sun.syndication.propono.atom.common.rome;
import com.sun.syndication.feed.CopyFrom;
import com.sun.syndication.feed.module.ModuleImpl;
import java.util.Date;
/**
* Bean representation of APP module.
*/
public class AppModuleImpl extends ModuleImpl implements AppModule {
private boolean draft = false;
private Date edited = null;
public AppModuleImpl() {
super(AppModule.class, AppModule.URI);
}
/** True if entry is draft */
public Boolean getDraft() {
return draft ? Boolean.TRUE : Boolean.FALSE;
}
/** Set to true if entry is draft */
public void setDraft(Boolean draft) {
this.draft = draft.booleanValue();
}
/** Time of last edit */
public Date getEdited() {
return edited;
}
/** Set time of last edit */
public void setEdited(Date edited) {
this.edited = edited;
}
/** Get interface class of module */
public Class getInterface() {
return AppModule.class;
}
/** Copy from other module */
public void copyFrom(CopyFrom obj) {
AppModule m = (AppModule)obj;
setDraft(m.getDraft());
setEdited(m.getEdited());
}
}

View file

@ -0,0 +1,66 @@
/*
* Copyright 2007 Apache Software Foundation
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. 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. For additional information regarding
* copyright in this work, please see the NOTICE file in the top level
* directory of this distribution.
*/
package com.sun.syndication.propono.atom.common.rome;
import com.sun.syndication.io.impl.DateParser;
import org.jdom.Element;
import org.jdom.Namespace;
import com.sun.syndication.feed.module.Module;
import com.sun.syndication.io.ModuleParser;
/**
* Parses APP module information from a JDOM element and into
* <code>AppModule</code> form.
*/
public class AppModuleParser implements ModuleParser {
/** Get URI of module namespace */
public String getNamespaceUri() {
return AppModule.URI;
}
/** Get namespace of module */
public Namespace getContentNamespace() {
return Namespace.getNamespace(AppModule.URI);
}
/** Parse JDOM element into module */
public Module parse(Element elem) {
boolean foundSomething = false;
AppModule m = new AppModuleImpl();
Element control = elem.getChild("control", getContentNamespace());
if (control != null) {
Element draftElem = control.getChild("draft", getContentNamespace());
if (draftElem != null) {
if ("yes".equals(draftElem.getText())) m.setDraft(Boolean.TRUE);
if ("no".equals(draftElem.getText())) m.setDraft(Boolean.FALSE);
}
}
Element edited = elem.getChild("edited", getContentNamespace());
if (edited != null) {
try {
m.setEdited(DateParser.parseW3CDateTime(edited.getTextTrim()));
} catch (Exception ignored) {}
}
return m;
}
}

View file

@ -0,0 +1,53 @@
/*
* Copyright 2007 Apache Software Foundation
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. 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. For additional information regarding
* copyright in this work, please see the NOTICE file in the top level
* directory of this distribution.
*/
package com.sun.syndication.propono.atom.server;
import javax.servlet.http.HttpServletResponse;
/**
* Exception thrown by {@link com.sun.syndication.propono.atom.server.AtomHandler}
* and extended by other Propono Atom exception classes.
*/
public class AtomException extends Exception {
/** Construct new exception */
public AtomException() {
super();
}
/** Construct new exception with message */
public AtomException(String msg) {
super(msg);
}
/** Contruct new exception with message and wrapping existing exception */
public AtomException(String msg, Throwable t) {
super(msg, t);
}
/** Construct new exception to wrap existing one. */
public AtomException(Throwable t) {
super(t);
}
/* Get HTTP status code associated with exception (HTTP 500 server error) */
/**
* Get HTTP status associated with exception.
*/
public int getStatus() {
return HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
}
}

View file

@ -0,0 +1,144 @@
/*
* Copyright 2007 Apache Software Foundation
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. 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. For additional information regarding
* copyright in this work, please see the NOTICE file in the top level
* directory of this distribution.
*/
package com.sun.syndication.propono.atom.server;
import com.sun.syndication.feed.atom.Entry;
import com.sun.syndication.feed.atom.Feed;
import com.sun.syndication.propono.atom.common.AtomService;
import com.sun.syndication.propono.atom.common.Categories;
/**
* Interface for handling single Atom protocol requests.
*
* <p>To create your own Atom protocol implementation you must implement this
* interface and create a concrete sub-class of
* {@link com.sun.syndication.propono.atom.server.AtomHandlerFactory}
* which is capable of instantiating it.</p>
*/
public interface AtomHandler
{
/**
* Get username of authenticated user. Return the username of the
* authenticated user
*/
public String getAuthenticatedUsername();
/**
* Return
* {@link com.sun.syndication.propono.atom.common.AtomService}
* object that contains the
* {@link com.sun.syndication.propono.atom.common.Workspace} objects
* available to the currently authenticated user and within those the
* {@link com.sun.syndication.propono.atom.common.Collection} avalaible.
*/
public AtomService getAtomService(AtomRequest req) throws AtomException;
/**
* Get categories, a list of Categories objects
*/
public Categories getCategories(AtomRequest req) throws AtomException;
/**
* Return collection or portion of collection specified by request.
* @param req Details of HTTP request
*/
public Feed getCollection(AtomRequest req) throws AtomException;
/**
* Store new entry in collection specified by request and return
* representation of entry as it is stored on server.
* @param req Details of HTTP request
* @return Location URL of new entry
*/
public Entry postEntry(AtomRequest req, Entry entry) throws AtomException;
/**
* Get entry specified by request.
* @param req Details of HTTP request
*/
public Entry getEntry(AtomRequest req) throws AtomException;
/**
* Get media resource specified by request.
* @param req Details of HTTP request
*/
public AtomMediaResource getMediaResource(AtomRequest req) throws AtomException;
/**
* Update entry specified by request and return new entry as represented
* on the server.
* @param req Details of HTTP request
*/
public void putEntry(AtomRequest req, Entry entry) throws AtomException;
/**
* Delete entry specified by request.
* @param req Details of HTTP request
*/
public void deleteEntry(AtomRequest req) throws AtomException;
/**
* Store media data in collection specified by request, create an Atom
* media-link entry to store metadata for the new media file and return
* that entry to the caller.
* @param req Details of HTTP request
* @param entry New entry initialzied with only title and content type
* @return Location URL of new media entry
*/
public Entry postMedia(AtomRequest req, Entry entry) throws AtomException;
/**
* Update the media file part of a media-link entry.
* @param req Details of HTTP request
*/
public void putMedia(AtomRequest req) throws AtomException;
/**
* Return true if specified request represents URI of a Service Document.
* @param req Details of HTTP request
*/
public boolean isAtomServiceURI(AtomRequest req);
/**
* Return true if specified request represents URI of a Categories Document.
* @param req Details of HTTP request
*/
public boolean isCategoriesURI(AtomRequest req);
/**
* Return true if specified request represents URI of a collection.
* @param req Details of HTTP request
*/
public boolean isCollectionURI(AtomRequest req);
/**
* Return true if specified request represents URI of an Atom entry.
* @param req Details of HTTP request
*/
public boolean isEntryURI(AtomRequest req);
/**
* Return true if specified patrequesthinfo represents media-edit URI.
* @param req Details of HTTP request
*/
public boolean isMediaEditURI(AtomRequest req);
}

View file

@ -0,0 +1,113 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.server;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Defines a factory that enables the
* {@link com.sun.syndication.propono.atom.server.AtomServlet} to obtain an
* {@link com.sun.syndication.propono.atom.server.AtomHandler} that handles an Atom request.
*
* <p>To create your own Atom protocol implementation you must sub-class this
* class with your own factory that is capable of creating instances of your
* {@link com.sun.syndication.propono.atom.server.AtomHandler} impementation.</p>
*/
public abstract class AtomHandlerFactory {
private static Log log =
LogFactory.getFactory().getInstance(AtomHandlerFactory.class);
private static final String DEFAULT_PROPERTY_NAME =
"com.sun.syndication.propono.atom.server.AtomHandlerFactory";
private static final String FALLBACK_IMPL_NAME =
"com.sun.syndication.propono.atom.server.impl.FileBasedAtomHandlerFactory";
/*
* <p>Protected constructor to prevent instantiation.
* Use {@link #newInstance()}.</p>
*/
protected AtomHandlerFactory() {
}
/**
* Obtain a new instance of a <code>AtomHandlerFactory</code>. This static
* method creates a new factory instance. This method uses the following
* ordered lookup procedure to determine the <code>AtomHandlerFactory</code>
* implementation class to load:
* <ul>
* <li>
* Use the <code>com.sun.syndication.propono.atom.server.AtomHandlerFactory</code>
* system property.
* </li>
* <li>
* Use the properties file "/propono.properties" in the classpath.
* This configuration file is in standard <code>java.util.Properties</code>
* format and contains the fully qualified name of the implementation
* class with the key being the system property defined above.
*
* The propono.properties file is read only once by Propono and it's
* values are then cached for future use. If the file does not exist
* when the first attempt is made to read from it, no further attempts
* are made to check for its existence. It is not possible to change
* the value of any property in propono.properties after it has been
* read for the first time.
* </li>
* <li>
* If not available, to determine the classname. The Services API will look
* for a classname in the file:
* <code>META-INF/services/com.sun.syndication.AtomHandlerFactory</code>
* in jars available to the runtime.
* </li>
* <li>
* Platform default <code>AtomHandlerFactory</code> instance.
* </li>
* </ul>
*
* Once an application has obtained a reference to a <code>AtomHandlerFactory</code>
* it can use the factory to configure and obtain parser instances.
*
* @return New instance of a <code>AtomHandlerFactory</code>
*
* @throws FactoryConfigurationError if the implementation is not available
* or cannot be instantiated.
*/
public static AtomHandlerFactory newInstance() {
try {
return (AtomHandlerFactory)
FactoryFinder.find(DEFAULT_PROPERTY_NAME, FALLBACK_IMPL_NAME);
} catch (FactoryFinder.ConfigurationError e) {
log.error("ERROR: finding factory", e);
throw new FactoryConfigurationError(e.getException(), e.getMessage());
}
}
/**
* Creates a new instance of a {@link com.sun.syndication.propono.atom.server.AtomHandler}
* using the currently configured parameters.
*
* @return A new instance of a AtomHandler.
*
* @throws AtomConfigurationException if a AtomHandler cannot be created
* which satisfies the configuration requested.
*/
public abstract AtomHandler newAtomHandler(
HttpServletRequest req, HttpServletResponse res);
}

View file

@ -0,0 +1,95 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.server;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Date;
import javax.activation.FileTypeMap;
import javax.activation.MimetypesFileTypeMap;
/**
* Represents a media link entry.
*/
public class AtomMediaResource {
private String contentType = null;
private long contentLength = 0;
private InputStream inputStream = null;
private Date lastModified = null;
private static FileTypeMap map = null;
static {
// TODO: figure out why PNG is missing from Java MIME types
map = FileTypeMap.getDefaultFileTypeMap();
if (map instanceof MimetypesFileTypeMap) {
try {
((MimetypesFileTypeMap)map).addMimeTypes("image/png png PNG");
} catch (Exception ignored) {}
}
}
public AtomMediaResource(File resource) throws FileNotFoundException {
contentType = map.getContentType(resource.getName());
contentLength = resource.length();
lastModified = new Date(resource.lastModified());
inputStream = new FileInputStream(resource);
}
public AtomMediaResource(String name, long length, Date lastModified, InputStream is)
throws FileNotFoundException {
this.contentType = map.getContentType(name);
this.contentLength = length;
this.lastModified = lastModified;
this.inputStream = is;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public long getContentLength() {
return contentLength;
}
public void setContentLength(long contentLength) {
this.contentLength = contentLength;
}
public InputStream getInputStream() {
return inputStream;
}
public void setInputStream(InputStream inputStream) {
this.inputStream = inputStream;
}
public Date getLastModified() {
return lastModified;
}
public void setLastModified(Date lastModified) {
this.lastModified = lastModified;
}
}

View file

@ -0,0 +1,49 @@
/*
* Copyright 2007 Apache Software Foundation
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. 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. For additional information regarding
* copyright in this work, please see the NOTICE file in the top level
* directory of this distribution.
*/
package com.sun.syndication.propono.atom.server;
import javax.servlet.http.HttpServletResponse;
/**
* Exception to be thrown by <code>AtomHandler</code> implementations in the
* case that a user is not authorized to access a resource.
*/
public class AtomNotAuthorizedException extends AtomException {
/** Construct new exception */
public AtomNotAuthorizedException() {
super();
}
/** Construct new exception with message */
public AtomNotAuthorizedException(String msg) {
super(msg);
}
/** Construct new exception with message and root cause */
public AtomNotAuthorizedException(String msg, Throwable t) {
super(msg, t);
}
/** Construct new exception to wrap root cause*/
public AtomNotAuthorizedException(Throwable t) {
super(t);
}
/** Get HTTP status code of exception (HTTP 403 unauthorized) */
public int getStatus() {
return HttpServletResponse.SC_UNAUTHORIZED;
}
}

View file

@ -0,0 +1,48 @@
/*
* Copyright 2007 Apache Software Foundation
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. 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. For additional information regarding
* copyright in this work, please see the NOTICE file in the top level
* directory of this distribution.
*/
package com.sun.syndication.propono.atom.server;
import javax.servlet.http.HttpServletResponse;
/**
* Exception thrown by AtomHandler in that case a resource is not found.
*/
public class AtomNotFoundException extends AtomException {
/** Construct new exception */
public AtomNotFoundException() {
super();
}
/** Construct new exception with message */
public AtomNotFoundException(String msg) {
super(msg);
}
/** Construct new exception with message and root cause */
public AtomNotFoundException(String msg, Throwable t) {
super(msg, t);
}
/** Construct new exception with root cause */
public AtomNotFoundException(Throwable t) {
super(t);
}
/** Get HTTP status code associated with exception (404 not found) */
public int getStatus() {
return HttpServletResponse.SC_NOT_FOUND;
}
}

View file

@ -0,0 +1,139 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. 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. For additional information regarding
* copyright in this work, please see the NOTICE file in the top level
* directory of this distribution.
*/
package com.sun.syndication.propono.atom.server;
import java.io.IOException;
import java.io.InputStream;
import java.security.Principal;
import java.util.Enumeration;
import java.util.Map;
/**
* Represents HTTP request to be processed by AtomHandler.
*/
public interface AtomRequest {
/**
* Returns any extra path information associated with the URL the client
* sent when it made this request.
*/
public String getPathInfo();
/**
* Returns the query string that is contained in the request URL after
* the path.
*/
public String getQueryString();
/**
* Returns the login of the user making this request, if the user has
* been authenticated, or null if the user has not been authenticated.
*/
public String getRemoteUser();
/**
* Returns a boolean indicating whether the authenticated user is included
* in the specified logical "role".
*/
public boolean isUserInRole(String arg0);
/**
* Returns a java.security.Principal object containing the name of the
* current authenticated user.
*/
public Principal getUserPrincipal();
/**
* Returns the part of this request's URL from the protocol name up to the
* query string in the first line of the HTTP request.
*/
public String getRequestURI();
/**
* Reconstructs the URL the client used to make the request.
*/
public StringBuffer getRequestURL();
/**
* Returns the length, in bytes, of the request body and made available by
* the input stream, or -1 if the length is not known.
*/
public int getContentLength();
/**
* Returns the MIME type of the body of the request, or null if the type
* is not known. */
public String getContentType();
/**
* Returns the value of a request parameter as a String, or null if the
* parameter does not exist.
*/
public String getParameter(String arg0);
/**
* Returns an Enumeration of String objects containing the names of the
* parameters contained in this request.
*/
public Enumeration getParameterNames();
/**
* Returns an array of String objects containing all of the values the
* given request parameter has, or null if the parameter does not exist.
*/
public String[] getParameterValues(String arg0);
/**
* Returns a java.util.Map of the parameters of this request.
*/
public Map getParameterMap();
/**
* Retrieves the body of the request as binary data using a
* ServletInputStream.
*/
public InputStream getInputStream() throws IOException;
/**
* Returns the value of the specified request header as a long value that
* represents a Date object. */
public long getDateHeader(String arg0);
/**
* Returns the value of the specified request header as a String.
*/
public String getHeader(String arg0);
/**
* Returns all the values of the specified request header as an Enumeration
* of String objects.
*/
public Enumeration getHeaders(String arg0);
/**
* Returns an enumeration of all the header names this request contains.
*/
public Enumeration getHeaderNames();
/**
* Returns the value of the specified request header as an int.
*/
public int getIntHeader(String arg0);
}

View file

@ -0,0 +1,114 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. 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. For additional information regarding
* copyright in this work, please see the NOTICE file in the top level
* directory of this distribution.
*/
package com.sun.syndication.propono.atom.server;
import java.io.IOException;
import java.io.InputStream;
import java.security.Principal;
import java.util.Enumeration;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
/**
* Default request implementation.
*/
public class AtomRequestImpl implements AtomRequest {
private HttpServletRequest wrapped = null;
public AtomRequestImpl(HttpServletRequest wrapped) {
this.wrapped = wrapped;
}
public String getPathInfo() {
return wrapped.getPathInfo() != null ? wrapped.getPathInfo() : "";
}
public String getQueryString() {
return wrapped.getQueryString();
}
public String getRemoteUser() {
return wrapped.getRemoteUser();
}
public boolean isUserInRole(String arg0) {
return wrapped.isUserInRole(arg0);
}
public Principal getUserPrincipal() {
return wrapped.getUserPrincipal();
}
public String getRequestURI() {
return wrapped.getRequestURI();
}
public StringBuffer getRequestURL() {
return wrapped.getRequestURL();
}
public int getContentLength() {
return wrapped.getContentLength();
}
public String getContentType() {
return wrapped.getContentType();
}
public String getParameter(String arg0) {
return wrapped.getParameter(arg0);
}
public Enumeration getParameterNames() {
return wrapped.getParameterNames();
}
public String[] getParameterValues(String arg0) {
return wrapped.getParameterValues(arg0);
}
public Map getParameterMap() {
return wrapped.getParameterMap();
}
public InputStream getInputStream() throws IOException {
return wrapped.getInputStream();
}
public long getDateHeader(String arg0) {
return wrapped.getDateHeader(arg0);
}
public String getHeader(String arg0) {
return wrapped.getHeader(arg0);
}
public Enumeration getHeaders(String arg0) {
return wrapped.getHeaders(arg0);
}
public Enumeration getHeaderNames() {
return wrapped.getHeaderNames();
}
public int getIntHeader(String arg0) {
return wrapped.getIntHeader(arg0);
}
}

View file

@ -0,0 +1,378 @@
/*
* Copyright 2007 Apache Software Foundation
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. 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. For additional information regarding
* copyright in this work, please see the NOTICE file in the top level
* directory of this distribution.
*/
package com.sun.syndication.propono.atom.server;
import com.sun.syndication.feed.atom.Content;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Writer;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdom.Document;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import com.sun.syndication.feed.atom.Entry;
import com.sun.syndication.feed.atom.Feed;
import com.sun.syndication.feed.atom.Link;
import com.sun.syndication.io.WireFeedOutput;
import com.sun.syndication.io.impl.Atom10Generator;
import com.sun.syndication.io.impl.Atom10Parser;
import com.sun.syndication.propono.atom.common.AtomService;
import com.sun.syndication.propono.atom.common.Categories;
import com.sun.syndication.propono.utils.Utilities;
import java.io.BufferedReader;
import java.util.Collections;
import java.util.Iterator;
import javax.servlet.ServletConfig;
/**
* Atom Servlet implements Atom protocol by calling an
* {@link com.sun.syndication.propono.atom.server.AtomHandler}
* implementation. This servlet takes care of parsing incoming XML into ROME
* Atom {@link com.sun.syndication.feed.atom.Entry} objects, passing those to the handler and serializing
* to the response the entries and feeds returned by the handler.
*/
public class AtomServlet extends HttpServlet {
/**
* Get feed type support by Servlet, "atom_1.0"
*/
public static final String FEED_TYPE = "atom_1.0";
private static String contextDirPath = null;
private static Log log =
LogFactory.getFactory().getInstance(AtomServlet.class);
static {
Atom10Parser.setResolveURIs(true);
}
//-----------------------------------------------------------------------------
/**
* Create an Atom request handler.
* TODO: make AtomRequestHandler implementation configurable.
*/
private AtomHandler createAtomRequestHandler(
HttpServletRequest request, HttpServletResponse response)
throws ServletException {
AtomHandlerFactory ahf = AtomHandlerFactory.newInstance();
return ahf.newAtomHandler(request, response);
}
//-----------------------------------------------------------------------------
/**
* Handles an Atom GET by calling handler and writing results to response.
*/
protected void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
log.debug("Entering");
AtomHandler handler = createAtomRequestHandler(req, res);
String userName = handler.getAuthenticatedUsername();
if (userName != null) {
AtomRequest areq = new AtomRequestImpl(req);
try {
if (handler.isAtomServiceURI(areq)) {
// return an Atom Service document
AtomService service = handler.getAtomService(areq);
Document doc = service.serviceToDocument();
res.setContentType("application/atomsvc+xml; charset=utf-8");
Writer writer = res.getWriter();
XMLOutputter outputter = new XMLOutputter();
outputter.setFormat(Format.getPrettyFormat());
outputter.output(doc, writer);
writer.close();
res.setStatus(HttpServletResponse.SC_OK);
}
else if (handler.isCategoriesURI(areq)) {
Categories cats = handler.getCategories(areq);
res.setContentType("application/xml");
Writer writer = res.getWriter();
Document catsDoc = new Document();
catsDoc.setRootElement(cats.categoriesToElement());
XMLOutputter outputter = new XMLOutputter();
outputter.output(catsDoc, writer);
writer.close();
res.setStatus(HttpServletResponse.SC_OK);
}
else if (handler.isCollectionURI(areq)) {
// return a collection
Feed col = handler.getCollection(areq);
col.setFeedType(FEED_TYPE);
WireFeedOutput wireFeedOutput = new WireFeedOutput();
Document feedDoc = wireFeedOutput.outputJDom(col);
res.setContentType("application/atom+xml; charset=utf-8");
Writer writer = res.getWriter();
XMLOutputter outputter = new XMLOutputter();
outputter.setFormat(Format.getPrettyFormat());
outputter.output(feedDoc, writer);
writer.close();
res.setStatus(HttpServletResponse.SC_OK);
}
else if (handler.isEntryURI(areq)) {
// return an entry
Entry entry = handler.getEntry(areq);
if (entry != null) {
res.setContentType("application/atom+xml; type=entry; charset=utf-8");
Writer writer = res.getWriter();
Atom10Generator.serializeEntry(entry, writer);
writer.close();
} else {
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
}
}
else if (handler.isMediaEditURI(areq)) {
AtomMediaResource entry = handler.getMediaResource(areq);
res.setContentType(entry.getContentType());
res.setContentLength((int)entry.getContentLength());
Utilities.copyInputToOutput(entry.getInputStream(), res.getOutputStream());
res.getOutputStream().flush();
res.getOutputStream().close();
}
else {
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
}
} catch (AtomException ae) {
res.sendError(ae.getStatus(), ae.getMessage());
log.debug("ERROR processing GET", ae);
} catch (Exception e) {
res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
log.debug("ERROR processing GET", e);
}
} else {
res.setHeader("WWW-Authenticate", "BASIC realm=\"AtomPub\"");
res.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
log.debug("Exiting");
}
//-----------------------------------------------------------------------------
/**
* Handles an Atom POST by calling handler to identify URI, reading/parsing
* data, calling handler and writing results to response.
*/
protected void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
log.debug("Entering");
AtomHandler handler = createAtomRequestHandler(req, res);
String userName = handler.getAuthenticatedUsername();
if (userName != null) {
AtomRequest areq = new AtomRequestImpl(req);
try {
if (handler.isCollectionURI(areq)) {
if (req.getContentType().startsWith("application/atom+xml")) {
// parse incoming entry
Entry entry = Atom10Parser.parseEntry(new BufferedReader(
new InputStreamReader(req.getInputStream(), "UTF-8")), null);
// call handler to post it
Entry newEntry = handler.postEntry(areq, entry);
// set Location and Content-Location headers
for (Iterator it = newEntry.getOtherLinks().iterator(); it.hasNext();) {
Link link = (Link) it.next();
if ("edit".equals(link.getRel())) {
res.addHeader("Location", link.getHrefResolved());
break;
}
}
for (Iterator it = newEntry.getAlternateLinks().iterator(); it.hasNext();) {
Link link = (Link) it.next();
if ("alternate".equals(link.getRel())) {
res.addHeader("Content-Location", link.getHrefResolved());
break;
}
}
// write entry back out to response
res.setStatus(HttpServletResponse.SC_CREATED);
res.setContentType("application/atom+xml; type=entry; charset=utf-8");
Writer writer = res.getWriter();
Atom10Generator.serializeEntry(newEntry, writer);
writer.close();
} else if (req.getContentType() != null) {
// get incoming title and slug from HTTP header
String title = areq.getHeader("Title");
// create new entry for resource, set title and type
Entry resource = new Entry();
resource.setTitle(title);
Content content = new Content();
content.setType(areq.getContentType());
resource.setContents(Collections.singletonList(content));
// hand input stream off to hander to post file
Entry newEntry = handler.postMedia(areq, resource);
// set Location and Content-Location headers
for (Iterator it = newEntry.getOtherLinks().iterator(); it.hasNext();) {
Link link = (Link) it.next();
if ("edit".equals(link.getRel())) {
res.addHeader("Location", link.getHrefResolved());
break;
}
}
for (Iterator it = newEntry.getAlternateLinks().iterator(); it.hasNext();) {
Link link = (Link) it.next();
if ("alternate".equals(link.getRel())) {
res.addHeader("Content-Location", link.getHrefResolved());
break;
}
}
res.setStatus(HttpServletResponse.SC_CREATED);
res.setContentType("application/atom+xml; type=entry; charset=utf-8");
Writer writer = res.getWriter();
Atom10Generator.serializeEntry(newEntry, writer);
writer.close();
} else {
res.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE,
"No content-type specified in request");
}
} else {
res.sendError(HttpServletResponse.SC_NOT_FOUND,
"Invalid collection specified in request");
}
} catch (AtomException ae) {
res.sendError(ae.getStatus(), ae.getMessage());
log.debug("ERROR processing POST", ae);
} catch (Exception e) {
res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
log.debug("ERROR processing POST", e);
}
} else {
res.setHeader("WWW-Authenticate", "BASIC realm=\"AtomPub\"");
res.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
log.debug("Exiting");
}
//-----------------------------------------------------------------------------
/**
* Handles an Atom PUT by calling handler to identify URI, reading/parsing
* data, calling handler and writing results to response.
*/
protected void doPut(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
log.debug("Entering");
AtomHandler handler = createAtomRequestHandler(req, res);
String userName = handler.getAuthenticatedUsername();
if (userName != null) {
AtomRequest areq = new AtomRequestImpl(req);
try {
if (handler.isEntryURI(areq)) {
// parse incoming entry
Entry unsavedEntry = Atom10Parser.parseEntry(new BufferedReader(
new InputStreamReader(req.getInputStream(), "UTF-8")), null);
// call handler to put entry
handler.putEntry(areq, unsavedEntry);
res.setStatus(HttpServletResponse.SC_OK);
} else if (handler.isMediaEditURI(areq)) {
// hand input stream to handler
handler.putMedia(areq);
res.setStatus(HttpServletResponse.SC_OK);
} else {
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
}
} catch (AtomException ae) {
res.sendError(ae.getStatus(), ae.getMessage());
log.debug("ERROR processing PUT", ae);
} catch (Exception e) {
res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
log.debug("ERROR processing PUT", e);
}
} else {
res.setHeader("WWW-Authenticate", "BASIC realm=\"AtomPub\"");
// Wanted to use sendError() here but Tomcat sends 403 forbidden
// when I do that, so sticking with setStatus() for time being.
res.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}
log.debug("Exiting");
}
//-----------------------------------------------------------------------------
/**
* Handle Atom DELETE by calling appropriate handler.
*/
protected void doDelete(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
log.debug("Entering");
AtomHandler handler = createAtomRequestHandler(req, res);
String userName = handler.getAuthenticatedUsername();
if (userName != null) {
AtomRequest areq = new AtomRequestImpl(req);
try {
if (handler.isEntryURI(areq)) {
handler.deleteEntry(areq);
res.setStatus(HttpServletResponse.SC_OK);
}
else {
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
}
} catch (AtomException ae) {
res.sendError(ae.getStatus(), ae.getMessage());
log.debug("ERROR processing DELETE", ae);
} catch (Exception e) {
res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
log.debug("ERROR processing DELETE", e);
}
} else {
res.setHeader("WWW-Authenticate", "BASIC realm=\"AtomPub\"");
// Wanted to use sendError() here but Tomcat sends 403 forbidden
// when I do that, so sticking with setStatus() for time being.
res.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}
log.debug("Exiting");
}
/**
* Initialize servlet.
*/
public void init( ServletConfig config ) throws ServletException {
super.init( config );
contextDirPath = getServletContext().getRealPath("/");
}
/**
* Get absolute path to Servlet context directory.
*/
public static String getContextDirPath() {
return contextDirPath;
}
}

View file

@ -0,0 +1,106 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.server;
/**
* Thrown when a problem with configuration with the
* {@link com.sun.syndication.propono.atom.server.AtomHandlerFactory} exists.
* This error will typically be thrown when the class of a parser factory
* specified in the system properties cannot be found or instantiated.
*/
public class FactoryConfigurationError extends Error {
/**
* <code>Exception</code> that represents the error.
*/
private Exception exception;
/**
* Create a new <code>FactoryConfigurationError</code> with no
* detail mesage.
*/
public FactoryConfigurationError() {
super();
this.exception = null;
}
/**
* Create a new <code>FactoryConfigurationError</code> with
* the <code>String </code> specified as an error message.
*
* @param msg The error message for the exception.
*/
public FactoryConfigurationError(String msg) {
super(msg);
this.exception = null;
}
/**
* Create a new <code>FactoryConfigurationError</code> with a
* given <code>Exception</code> base cause of the error.
*
* @param e The exception to be encapsulated in a
* FactoryConfigurationError.
*/
public FactoryConfigurationError(Exception e) {
super(e.toString());
this.exception = e;
}
/**
* Create a new <code>FactoryConfigurationError</code> with the
* given <code>Exception</code> base cause and detail message.
*
* @param e The exception to be encapsulated in a
* FactoryConfigurationError
* @param msg The detail message.
*/
public FactoryConfigurationError(Exception e, String msg) {
super(msg);
this.exception = e;
}
/**
* Return the message (if any) for this error . If there is no
* message for the exception and there is an encapsulated
* exception then the message of that exception, if it exists will be
* returned. Else the name of the encapsulated exception will be
* returned.
*
* @return The error message.
*/
public String getMessage() {
String message = super.getMessage();
if (message == null && exception != null) {
return exception.getMessage();
}
return message;
}
/**
* Return the actual exception (if any) that caused this exception to
* be raised.
*
* @return The encapsulated exception, or null if there is none.
*/
public Exception getException() {
return exception;
}
}

View file

@ -0,0 +1,280 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.server;
import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
/**
* Find {@link com.sun.syndication.propono.atom.server.AtomHandlerFactory} based on properties files.
*/
class FactoryFinder {
private static boolean debug = false;
static Properties cacheProps= new Properties();
static SecuritySupport ss = new SecuritySupport() ;
static boolean firstTime = true;
private static void dPrint(String msg) {
if (debug) {
System.err.println("Propono: " + msg);
}
}
/**
* Create an instance of a class using the specified ClassLoader and
* optionally fall back to the current ClassLoader if not found.
*
* @param className Name of the concrete class corresponding to the
* service provider
*
* @param cl ClassLoader to use to load the class, null means to use
* the bootstrap ClassLoader
*
* @param doFallback true if the current ClassLoader should be tried as
* a fallback if the class is not found using cl
*/
private static Object newInstance(
String className, ClassLoader cl, boolean doFallback)
throws ConfigurationError {
try {
Class providerClass;
if (cl == null) {
// If classloader is null Use the bootstrap ClassLoader.
// Thus Class.forName(String) will use the current
// ClassLoader which will be the bootstrap ClassLoader.
providerClass = Class.forName(className);
} else {
try {
providerClass = cl.loadClass(className);
} catch (ClassNotFoundException x) {
if (doFallback) {
// Fall back to current classloader
cl = FactoryFinder.class.getClassLoader();
providerClass = cl.loadClass(className);
} else {
throw x;
}
}
}
Object instance = providerClass.newInstance();
dPrint("created new instance of " + providerClass +
" using ClassLoader: " + cl);
return instance;
} catch (ClassNotFoundException x) {
throw new ConfigurationError(
"Provider " + className + " not found", x);
} catch (Exception x) {
throw new ConfigurationError(
"Provider " + className + " could not be instantiated: " + x, x);
}
}
/**
* Finds the implementation Class object in the specified order. Main
* entry point.
* @return Class object of factory, never null
*
* @param factoryId Name of the factory to find, same as
* a property name
* @param fallbackClassName Implementation class name, if nothing else
* is found. Use null to mean no fallback.
*
* Package private so this code can be shared.
*/
static Object find(String factoryId, String fallbackClassName)
throws ConfigurationError {
// Figure out which ClassLoader to use for loading the provider
// class. If there is a Context ClassLoader then use it.
ClassLoader classLoader = ss.getContextClassLoader();
if (classLoader == null) {
// if we have no Context ClassLoader
// so use the current ClassLoader
classLoader = FactoryFinder.class.getClassLoader();
}
dPrint("find factoryId =" + factoryId);
// Use the system property first
try {
String systemProp = ss.getSystemProperty(factoryId);
if( systemProp!=null) {
dPrint("found system property, value=" + systemProp);
return newInstance(systemProp, classLoader, true );
}
} catch (SecurityException se) {
//if first option fails due to any reason we should try next option in the
//look up algorithm.
}
// try to read from /propono.properties
try {
String javah = ss.getSystemProperty("java.home");
String configFile = "/propono.properties";
String factoryClassName = null;
if(firstTime){
synchronized(cacheProps){
if (firstTime) {
try {
InputStream is = FactoryFinder.class.getResourceAsStream(configFile);
firstTime = false;
if (is != null) {
dPrint("Read properties file: " + configFile);
cacheProps.load(is);
}
} catch (Exception intentionallyIgnored) {}
}
}
}
factoryClassName = cacheProps.getProperty(factoryId);
if(factoryClassName != null){
dPrint("found in $java.home/propono.properties, value=" + factoryClassName);
return newInstance(factoryClassName, classLoader, true);
}
} catch(Exception ex) {
if( debug ) ex.printStackTrace();
}
// Try Jar Service Provider Mechanism
Object provider = findJarServiceProvider(factoryId);
if (provider != null) {
return provider;
}
if (fallbackClassName == null) {
throw new ConfigurationError(
"Provider for " + factoryId + " cannot be found", null);
}
dPrint("loaded from fallback value: " + fallbackClassName);
return newInstance(fallbackClassName, classLoader, true);
}
/*
* Try to find provider using Jar Service Provider Mechanism
*
* @return instance of provider class if found or null
*/
private static Object findJarServiceProvider(String factoryId)
throws ConfigurationError {
String serviceId = "META-INF/services/" + factoryId;
InputStream is = null;
// First try the Context ClassLoader
ClassLoader cl = ss.getContextClassLoader();
if (cl != null) {
is = ss.getResourceAsStream(cl, serviceId);
// If no provider found then try the current ClassLoader
if (is == null) {
cl = FactoryFinder.class.getClassLoader();
is = ss.getResourceAsStream(cl, serviceId);
}
} else {
// No Context ClassLoader, try the current
// ClassLoader
cl = FactoryFinder.class.getClassLoader();
is = ss.getResourceAsStream(cl, serviceId);
}
if (is == null) {
// No provider found
return null;
}
dPrint("found jar resource=" + serviceId +
" using ClassLoader: " + cl);
// Read the service provider name in UTF-8 as specified in
// the jar spec. Unfortunately this fails in Microsoft
// VJ++, which does not implement the UTF-8
// encoding. Theoretically, we should simply let it fail in
// that case, since the JVM is obviously broken if it
// doesn't support such a basic standard. But since there
// are still some users attempting to use VJ++ for
// development, we have dropped in a fallback which makes a
// second attempt using the platform's default encoding. In
// VJ++ this is apparently ASCII, which is a subset of
// UTF-8... and since the strings we'll be reading here are
// also primarily limited to the 7-bit ASCII range (at
// least, in English versions), this should work well
// enough to keep us on the air until we're ready to
// officially decommit from VJ++. [Edited comment from
// jkesselm]
BufferedReader rd;
try {
rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
} catch (java.io.UnsupportedEncodingException e) {
rd = new BufferedReader(new InputStreamReader(is));
}
String factoryClassName = null;
try {
// XXX Does not handle all possible input as specified by the
// Jar Service Provider specification
factoryClassName = rd.readLine();
rd.close();
} catch (IOException x) {
// No provider found
return null;
}
if (factoryClassName != null &&
! "".equals(factoryClassName)) {
dPrint("found in resource, value="
+ factoryClassName);
// Note: here we do not want to fall back to the current
// ClassLoader because we want to avoid the case where the
// resource file was found using one ClassLoader and the
// provider class was instantiated using a different one.
return newInstance(factoryClassName, cl, false);
}
// No provider found
return null;
}
static class ConfigurationError extends Error {
private Exception exception;
/**
* Construct a new instance with the specified detail string and
* exception.
*/
ConfigurationError(String msg, Exception x) {
super(msg);
this.exception = x;
}
Exception getException() {
return exception;
}
}
}

View file

@ -0,0 +1,90 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.server;
import java.security.*;
import java.net.*;
import java.io.*;
import java.util.*;
/**
* This class is duplicated for each subpackage, it is package private and
* therefore is not exposed as part of the public API.
*/
class SecuritySupport {
ClassLoader getContextClassLoader() {
return (ClassLoader)
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
ClassLoader cl = null;
try {
cl = Thread.currentThread().getContextClassLoader();
} catch (SecurityException ex) { }
return cl;
}
});
}
String getSystemProperty(final String propName) {
return (String)
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return System.getProperty(propName);
}
});
}
FileInputStream getFileInputStream(final File file)
throws FileNotFoundException {
try {
return (FileInputStream)
AccessController.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws FileNotFoundException {
return new FileInputStream(file);
}
});
} catch (PrivilegedActionException e) {
throw (FileNotFoundException)e.getException();
}
}
InputStream getResourceAsStream(final ClassLoader cl,
final String name) {
return (InputStream)
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
InputStream ris;
if (cl == null) {
ris = ClassLoader.getSystemResourceAsStream(name);
} else {
ris = cl.getResourceAsStream(name);
}
return ris;
}
});
}
boolean doesFileExist(final File f) {
return ((Boolean)
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return new Boolean(f.exists());
}
})).booleanValue();
}
}

View file

@ -0,0 +1,443 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.server.impl;
import com.sun.syndication.propono.atom.server.AtomMediaResource;
import org.apache.commons.codec.binary.Base64;
import com.sun.syndication.propono.atom.server.AtomHandler;
import com.sun.syndication.propono.atom.server.AtomException;
import com.sun.syndication.propono.atom.server.AtomServlet;
import com.sun.syndication.feed.atom.Entry;
import com.sun.syndication.feed.atom.Feed;
import com.sun.syndication.propono.atom.common.AtomService;
import com.sun.syndication.propono.atom.common.Categories;
import com.sun.syndication.propono.atom.server.AtomRequest;
import java.io.File;
import java.util.StringTokenizer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils;
/**
* File-based {@link com.sun.syndication.propono.atom.server.AtomHandler}
* implementation that stores entries and media-entries to disk. Implemented
* using {@link com.sun.syndication.propono.atom.server.impl.FileBasedAtomService}.
*/
public class FileBasedAtomHandler implements AtomHandler {
private static Log log =
LogFactory.getFactory().getInstance(FileBasedAtomHandler.class);
private static String fileStoreDir = null;
private String userName = null;
private String atomProtocolURL = null;
private String contextURI = null;
private String uploadurl = null;
private FileBasedAtomService service = null;
/**
* Construct handler to handle one request.
* @param req Request to be handled.
*/
public FileBasedAtomHandler( HttpServletRequest req ) {
this(req, AtomServlet.getContextDirPath());
}
/**
* Contruct handler for one request, using specified file storage directory.
* @param req Request to be handled.
* @param uploaddir File storage upload dir.
*/
public FileBasedAtomHandler(HttpServletRequest req, String uploaddir) {
log.debug("ctor");
userName = authenticateBASIC(req);
atomProtocolURL = req.getScheme() + "://" + req.getServerName() + ":"
+ req.getServerPort() + req.getContextPath() + req.getServletPath();
contextURI = req.getScheme() + "://" + req.getServerName() + ":"
+ req.getServerPort() + req.getContextPath();
try {
service = new FileBasedAtomService(userName, uploaddir,
contextURI, req.getContextPath(), req.getServletPath());
} catch (Throwable t) {
throw new RuntimeException("ERROR creating FileBasedAtomService", t);
}
}
/**
* Method used for validating user. Developers can overwrite this method
* and use credentials stored in Database or LDAP to confirm if the user is
* allowed to access this service.
* @param login user submitted login id
* @param password user submitted password
*/
public boolean validateUser(String login, String password) {
return true;
}
/**
* Get username of authenticated user
* @return User name.
*/
public String getAuthenticatedUsername() {
// For now return userName as the login id entered for authorization
return userName;
}
/**
* Get base URI of Atom protocol implementation.
* @return Base URI of Atom protocol implemenation.
*/
public String getAtomProtocolURL( ) {
if ( atomProtocolURL == null ) {
return "app";
} else {
return atomProtocolURL;
}
}
/**
* Return introspection document
* @throws com.sun.syndication.propono.atom.server.AtomException Unexpected exception.
* @return AtomService object with workspaces and collections.
*/
public AtomService getAtomService(AtomRequest areq) throws AtomException {
return service;
}
/**
* Returns null because we use in-line categories.
* @throws com.sun.syndication.propono.atom.server.AtomException Unexpected exception.
* @return Categories object
*/
public Categories getCategories(AtomRequest areq) throws AtomException {
log.debug("getCollection");
String[] pathInfo = StringUtils.split(areq.getPathInfo(),"/");
String handle = pathInfo[0];
String collection = pathInfo[1];
FileBasedCollection col = service.findCollectionByHandle(handle, collection);
return (Categories)col.getCategories(true).get(0);
}
/**
* Get collection specified by pathinfo.
* @param areq Details of HTTP request
* @return ROME feed representing collection.
* @throws com.sun.syndication.propono.atom.server.AtomException Invalid collection or other exception.
*/
public Feed getCollection(AtomRequest areq) throws AtomException {
log.debug("getCollection");
String[] pathInfo = StringUtils.split(areq.getPathInfo(),"/");
String handle = pathInfo[0];
String collection = pathInfo[1];
FileBasedCollection col = service.findCollectionByHandle(handle, collection);
return col.getFeedDocument();
}
/**
* Create a new entry specified by pathInfo and posted entry. We save the
* submitted Atom entry verbatim, but we do set the id and reset the update
* time.
*
* @param entry Entry to be added to collection.
* @param areq Details of HTTP request
* @throws com.sun.syndication.propono.atom.server.AtomException On invalid collection or other error.
* @return Entry as represented on server.
*/
public Entry postEntry(AtomRequest areq, Entry entry) throws AtomException {
log.debug("postEntry");
String[] pathInfo = StringUtils.split(areq.getPathInfo(),"/");
String handle = pathInfo[0];
String collection = pathInfo[1];
FileBasedCollection col = service.findCollectionByHandle(handle, collection);
try {
return col.addEntry(entry);
} catch (Exception fe) {
fe.printStackTrace();
throw new AtomException( fe );
}
}
/**
* Get entry specified by pathInfo.
* @param areq Details of HTTP request
* @throws com.sun.syndication.propono.atom.server.AtomException On invalid pathinfo or other error.
* @return ROME Entry object.
*/
public Entry getEntry(AtomRequest areq) throws AtomException {
log.debug("getEntry");
String[] pathInfo = StringUtils.split(areq.getPathInfo(),"/");
String handle = pathInfo[0];
String collection = pathInfo[1];
String fileName = pathInfo[2];
FileBasedCollection col = service.findCollectionByHandle(handle, collection);
try {
return col.getEntry(fileName);
} catch (Exception re) {
if (re instanceof AtomException) throw (AtomException)re;
throw new AtomException("ERROR: getting entry", re);
}
}
/**
* Update entry specified by pathInfo and posted entry.
*
* @param entry
* @param areq Details of HTTP request
* @throws com.sun.syndication.propono.atom.server.AtomException
*/
public void putEntry(AtomRequest areq, Entry entry) throws AtomException {
log.debug("putEntry");
String[] pathInfo = StringUtils.split(areq.getPathInfo(),"/");
String handle = pathInfo[0];
String collection = pathInfo[1];
String fileName = pathInfo[2];
FileBasedCollection col = service.findCollectionByHandle(handle, collection);
try {
col.updateEntry(entry, fileName);
} catch ( Exception fe ) {
throw new AtomException( fe );
}
}
/**
* Delete entry specified by pathInfo.
* @param areq Details of HTTP request
*/
public void deleteEntry(AtomRequest areq) throws AtomException {
log.debug("deleteEntry");
String[] pathInfo = StringUtils.split(areq.getPathInfo(),"/");
String handle = pathInfo[0];
String collection = pathInfo[1];
String fileName = pathInfo[2];
FileBasedCollection col = service.findCollectionByHandle(handle, collection);
try {
col.deleteEntry(fileName);
} catch (Exception e) {
String msg = "ERROR in atom.deleteResource";
log.error(msg,e);
throw new AtomException(msg);
}
}
/**
* Store media data in collection specified by pathInfo, create an Atom
* media-link entry to store metadata for the new media file and return
* that entry to the caller.
* @param areq Details of HTTP request
* @param entry New entry initialzied with only title and content type
* @return Location URL of new media entry
*/
public Entry postMedia(AtomRequest areq, Entry entry) throws AtomException {
// get incoming slug from HTTP header
String slug = areq.getHeader("Slug");
if (log.isDebugEnabled()) {
log.debug("postMedia - title: "+entry.getTitle()+" slug:"+slug);
}
try {
File tempFile = null;
String[] pathInfo = StringUtils.split(areq.getPathInfo(),"/");
String handle = pathInfo[0];
String collection = pathInfo[1];
FileBasedCollection col = service.findCollectionByHandle(handle, collection);
try {
col.addMediaEntry(entry, slug, areq.getInputStream());
} catch (Exception e) {
e.printStackTrace();
String msg = "ERROR reading posted file";
log.error(msg,e);
throw new AtomException(msg, e);
} finally {
if (tempFile != null) tempFile.delete();
}
} catch (Exception re) {
throw new AtomException("ERROR: posting media");
}
return entry;
}
/**
* Update the media file part of a media-link entry.
* @param areq Details of HTTP request
* Assuming pathInfo of form /user-name/resource/name
*/
public void putMedia(AtomRequest areq) throws AtomException {
log.debug("putMedia");
String[] pathInfo = StringUtils.split(areq.getPathInfo(),"/");
String handle = pathInfo[0];
String collection = pathInfo[1];
String fileName = pathInfo[3];
FileBasedCollection col = service.findCollectionByHandle(handle, collection);
try {
col.updateMediaEntry(fileName, areq.getContentType(), areq.getInputStream());
} catch (Exception re) {
throw new AtomException("ERROR: posting media");
}
}
public AtomMediaResource getMediaResource(AtomRequest areq) throws AtomException {
log.debug("putMedia");
String[] pathInfo = StringUtils.split(areq.getPathInfo(),"/");
String handle = pathInfo[0];
String collection = pathInfo[1];
String fileName = pathInfo[3];
FileBasedCollection col = service.findCollectionByHandle(handle, collection);
try {
return col.getMediaResource(fileName);
} catch (Exception re) {
throw new AtomException("ERROR: posting media");
}
}
/**
* Return true if specified pathinfo represents URI of service doc.
*/
public boolean isAtomServiceURI(AtomRequest areq) {
String[] pathInfo = StringUtils.split(areq.getPathInfo(),"/");
if (pathInfo.length==0) return true;
return false;
}
/**
* Return true if specified pathinfo represents URI of category doc.
*/
public boolean isCategoriesURI(AtomRequest areq) {
log.debug("isCategoriesDocumentURI");
String[] pathInfo = StringUtils.split(areq.getPathInfo(),"/");
if (pathInfo.length == 3 && "categories".equals(pathInfo[2])) {
return true;
}
return false;
}
/**
* Return true if specified pathinfo represents URI of a collection.
*/
public boolean isCollectionURI(AtomRequest areq) {
log.debug("isCollectionURI");
// workspace/collection-plural
// if length is 2 and points to a valid collection then YES
String[] pathInfo = StringUtils.split(areq.getPathInfo(),"/");
if (pathInfo.length == 2) {
String handle = pathInfo[0];
String collection = pathInfo[1];
if (service.findCollectionByHandle(handle, collection) != null) {
return true;
}
}
return false;
}
/**
* Return true if specified pathinfo represents URI of an Atom entry.
*/
public boolean isEntryURI(AtomRequest areq) {
log.debug("isEntryURI");
// workspace/collection-singular/fsid
// if length is 3 and points to a valid collection then YES
String[] pathInfo = StringUtils.split(areq.getPathInfo(),"/");
if (pathInfo.length == 3) {
String handle = pathInfo[0];
String collection = pathInfo[1];
if (service.findCollectionByHandle(handle, collection) != null) {
return true;
}
}
return false;
}
/**
* Return true if specified pathinfo represents media-edit URI.
*/
public boolean isMediaEditURI(AtomRequest areq) {
log.debug("isMediaEditURI");
// workspace/collection-singular/fsid/media/fsid
// if length is 4, points to a valid collection and fsid is mentioned twice then YES
String[] pathInfo = StringUtils.split(areq.getPathInfo(),"/");
if (pathInfo.length == 4) {
String handle = pathInfo[0];
String collection = pathInfo[1];
String media = pathInfo[2];
String fsid = pathInfo[3];
if (service.findCollectionByHandle(handle, collection) != null && media.equals("media")) {
return true;
}
}
return false;
}
/**
* BASIC authentication.
*/
public String authenticateBASIC(HttpServletRequest request) {
log.debug("authenticateBASIC");
boolean valid = false;
String userID = null;
String password = null;
try {
String authHeader = request.getHeader("Authorization");
if (authHeader != null) {
StringTokenizer st = new StringTokenizer(authHeader);
if (st.hasMoreTokens()) {
String basic = st.nextToken();
if (basic.equalsIgnoreCase("Basic")) {
String credentials = st.nextToken();
String userPass = new String(Base64.decodeBase64(credentials.getBytes()));
int p = userPass.indexOf(":");
if (p != -1) {
userID = userPass.substring(0, p);
password = userPass.substring(p+1);
// Validate the User.
valid = validateUser( userID, password );
}
}
}
}
} catch (Exception e) {
log.debug(e);
}
if (valid) {
//For now assume userID as userName
return userID;
}
return null;
}
}

View file

@ -0,0 +1,37 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.server.impl;
import com.sun.syndication.propono.atom.server.AtomHandlerFactory;
import com.sun.syndication.propono.atom.server.AtomHandler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Extends {@link com.sun.syndication.propono.atom.server.AtomHandlerFactory} to create and return
* {@link com.sun.syndication.propono.atom.server.impl.FileBasedAtomHandler}.
*/
public class FileBasedAtomHandlerFactory extends AtomHandlerFactory {
/**
* Create new AtomHandler.
*/
public AtomHandler newAtomHandler(
HttpServletRequest req, HttpServletResponse res ) {
return new FileBasedAtomHandler(req);
}
}

View file

@ -0,0 +1,188 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.server.impl;
import com.sun.syndication.propono.atom.common.AtomService;
import com.sun.syndication.propono.utils.Utilities;
import java.io.InputStream;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
/**
* File based Atom service.
* Supports one workspace per user.
* Collections in workspace are defined in /propono.properties, for example:
*
* <pre>
* # Define list of collections to be offered
* propono.atomserver.filebased.collections=entries,gifimages
*
* # Defines 'entries' collection, accepts entries
* propono.atomserver.filebased.collection.entries.title=Entries
* propono.atomserver.filebased.collection.entries.singular=entry
* propono.atomserver.filebased.collection.entries.plural=entries
* propono.atomserver.filebased.collection.entries.accept=application/atom+xml;type=entry
* propono.atomserver.filebased.collection.entries.categories=general,category1,category2
*
* # Defines 'gifimages' collection, accepts only GIF files
* propono.atomserver.filebased.collection.gifimages.title=GIF Images
* propono.atomserver.filebased.collection.gifimages.singular=gif
* propono.atomserver.filebased.collection.gifimages.plural=gifs
* propono.atomserver.filebased.collection.gifimages.accept=image/gif
* propono.atomserver.filebased.collection.gifimages.categories=general,category1,category2
* </pre>
*
* If no such properties are found, then service will fall back to two
* collections: 'entries' for Atom entries and 'resources' for any content-type.
*
*
* <p><b>URI structure used for accessing collections and entries</b></p>
*
* <p>Collection feed (URI allows GET to get collection, POST to add to it)<br/>
* <code>[servlet-context-uri]/app/[workspace-handle]/[collection-plural] </code>
* </p>
*
* <p>Collection entry (URI allows GET, PUT and DELETE)<br/>
* <code>[servlet-context-uri]/app/[workspace-handle]/[collection-singular]/[entryid] </code>
* </p>
*
* <p>Collection entry media (URI allows GET, PUT and DELETE)<br/>
* <code>[servlet-context-uri]/app/[workspace-handle]/[collection-singular]/media/[entryid]</code>
* </p>
*
* <p>Categories URI if not using inline categories (URI allows GET)<br/>
* <code>[servlet-context-uri]/app/[workspace-handle]/[collection-plural]/categories</code>
* </p>
*
*
* <p><b>Directory structure used to store collections and entries</b></p>
*
* <p>Collection feed (kept constantly up to date)<br/>
* <code>[servlet-context-dir]/[workspace-handle]/[collection-plural]/feed.xml</code>
* </p>
*
* <p>Collection entry (individual entries also stored as entry.xml files)<br/>
* <code>[servlet-context-dir]/[workspace-handle]/[collection-plural]/id/entry.xml</code>
* </p>
*
* <p>Collection entry media (media file stored under entry directory)<br/>
* <code>[servlet-context-dir]/[workspace-handle]/[collection-plural]/id/media/id</code>
* </p>
*/
public class FileBasedAtomService extends AtomService {
private Map workspaceMap = new TreeMap();
private Map collectionMap = new TreeMap();
private static Properties cacheProps = new Properties();
private boolean firstTime = true;
/**
* Creates a new instance of FileBasedAtomService.
*/
public FileBasedAtomService(
String userName, String baseDir, String contextURI, String contextPath, String servletPath) throws Exception {
String workspaceHandle = userName;
// One workspace per user
FileBasedWorkspace workspace = new FileBasedWorkspace(workspaceHandle, baseDir);
workspaceMap.put(userName, workspace);
if (firstTime) {
synchronized(cacheProps) {
InputStream is = getClass().getResourceAsStream("/propono.properties");
if (is != null) cacheProps.load(is);
firstTime = false;
}
}
// can't find propono.properties, so use system props instead
if (cacheProps == null) cacheProps = System.getProperties();
String relativeURIsString = cacheProps.getProperty(
"propono.atomserver.filebased.relativeURIs");
boolean relativeURIs = "true".equals(relativeURIsString);
String inlineCategoriesString = cacheProps.getProperty(
"propono.atomserver.filebased.inlineCategories");
boolean inlineCategories = "true".equals(inlineCategoriesString);
String colnames = cacheProps.getProperty("propono.atomserver.filebased.collections");
if (colnames != null) {
// collections specified in propono.properties, use those
String[] colarray = Utilities.stringToStringArray(colnames,",");
for (int i=0; i<colarray.length; i++) {
String prefix = "propono.atomserver.filebased.collection." + colarray[i] + ".";
String collectionTitle = cacheProps.getProperty(prefix + "title");
String collectionSingular = cacheProps.getProperty(prefix + "singular");
String collectionPlural = cacheProps.getProperty(prefix + "plural");
String collectionAccept = cacheProps.getProperty(prefix + "accept");
String catNamesString = cacheProps.getProperty(prefix + "categories");
String[] catNames = Utilities.stringToStringArray(catNamesString, ",");
FileBasedCollection entries = new FileBasedCollection(
collectionTitle, workspaceHandle,
collectionPlural, collectionSingular, collectionAccept,
inlineCategories, catNames,
relativeURIs, contextURI, contextPath, servletPath, baseDir);
workspace.addCollection(entries);
// want to be able to look up collection by singular and plural names
collectionMap.put(workspaceHandle + "|" + collectionSingular, entries);
collectionMap.put(workspaceHandle + "|" + collectionPlural, entries);
}
} else {
// Fallback to two collections. One collection for accepting entries
// and other collection for other ( resources/uploaded images etc.)
String[] catNames = new String[] {"general", "category1", "category2"};
FileBasedCollection entries = new FileBasedCollection(
"Entries", workspaceHandle,
"entries", "entry", "application/atom+xml;type=entry",
inlineCategories, catNames,
relativeURIs, contextURI, contextPath, servletPath, baseDir);
workspace.addCollection(entries);
// want to be able to look up collection by singular and plural names
collectionMap.put(workspaceHandle + "|entry", entries);
collectionMap.put(workspaceHandle + "|entries", entries);
FileBasedCollection resources = new FileBasedCollection(
"Resources", workspaceHandle,
"resources", "resource", "*/*",
inlineCategories, catNames,
relativeURIs, contextURI, contextPath, servletPath, baseDir);
// want to be able to look up collection by singular and plural names
workspace.addCollection(resources);
collectionMap.put(workspaceHandle + "|resource", resources);
collectionMap.put(workspaceHandle + "|resources", resources);
}
getWorkspaces().add(workspace);
}
/**
* Find workspace by handle, returns null of not found.
*/
FileBasedWorkspace findWorkspaceByHandle(String handle) {
return (FileBasedWorkspace)workspaceMap.get(handle);
}
FileBasedCollection findCollectionByHandle(String handle, String collection) {
return (FileBasedCollection)collectionMap.get(handle+"|"+collection);
}
}

View file

@ -0,0 +1,837 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.server.impl;
import java.util.Iterator;
import org.jdom.Document;
import org.jdom.output.XMLOutputter;
import com.sun.syndication.feed.WireFeed;
import com.sun.syndication.feed.atom.Category;
import com.sun.syndication.feed.atom.Content;
import com.sun.syndication.feed.atom.Entry;
import com.sun.syndication.feed.atom.Feed;
import com.sun.syndication.feed.atom.Link;
import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.WireFeedInput;
import com.sun.syndication.io.WireFeedOutput;
import com.sun.syndication.io.impl.Atom10Generator;
import com.sun.syndication.io.impl.Atom10Parser;
import com.sun.syndication.propono.atom.common.Categories;
import com.sun.syndication.propono.atom.common.Collection;
import com.sun.syndication.propono.atom.common.rome.AppModule;
import com.sun.syndication.propono.atom.common.rome.AppModuleImpl;
import com.sun.syndication.propono.atom.server.AtomException;
import com.sun.syndication.propono.atom.server.AtomMediaResource;
import com.sun.syndication.propono.atom.server.AtomNotFoundException;
import com.sun.syndication.propono.utils.Utilities;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;
import javax.activation.FileTypeMap;
import javax.activation.MimetypesFileTypeMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* File based Atom collection implementation. This is the heart of the
* file-based Atom service implementation. It provides methods for adding,
* getting updating and deleting Atom entries and media entries.
*/
public class FileBasedCollection extends Collection {
private static Log log =
LogFactory.getFactory().getInstance(FileBasedCollection.class);
private String handle = null;
private String singular = null;
private String collection = null;
private boolean inlineCats = false;
private String[] catNames = null;
private boolean relativeURIs = false;
private String contextURI = null;
private String contextPath = null;
private String servletPath = null;
private String baseDir = null;
private static final String FEED_TYPE = "atom_1.0";
/**
* Construct by providing title (plain text, no HTML), a workspace handle,
* a plural collection name (e.g. entries), a singular collection name
* (e.g. entry), the base directory for file storage, the content-type
* range accepted by the collection and the root Atom protocol URI for the
* service.
* @param title Title of collection (plain text, no HTML)
* @param handle Workspace handle
* @param collection Collection handle, plural
* @param singular Collection handle, singular
* @param accept Content type range accepted by collection
* @param inlineCats True for inline categories
* @param catNames Category names for this workspace
* @param baseDir Base directory for file storage
* @param relativeURIs True for relative URIs
* @param contextURI Absolute URI of context that hosts APP service
* @param contextPath Context path of APP service (e.g. "/sample-atomserver")
* @param servletPath Servlet path of APP service (e.g. "/app")
*/
public FileBasedCollection(
String title,
String handle,
String collection,
String singular,
String accept,
boolean inlineCats,
String[] catNames,
boolean relativeURIs,
String contextURI,
String contextPath,
String servletPath,
String baseDir) {
super(title, "text",
relativeURIs
? servletPath.substring(1) + "/" + handle + "/" + collection
: contextURI + servletPath + "/" + handle + "/" + collection);
this.handle = handle;
this.collection = collection;
this.singular = singular;
this.inlineCats = inlineCats;
this.catNames = catNames;
this.baseDir = baseDir;
this.relativeURIs = relativeURIs;
this.contextURI = contextURI;
this.contextPath = contextPath;
this.servletPath = servletPath;
addAccept(accept);
}
/**
* Get feed document representing collection.
* @throws com.sun.syndication.propono.atom.server.AtomException On error retrieving feed file.
* @return Atom Feed representing collection.
*/
public Feed getFeedDocument() throws AtomException {
InputStream in = null;
synchronized(FileStore.getFileStore()) {
in = FileStore.getFileStore().getFileInputStream(getFeedPath());
if (in == null) {
in = createDefaultFeedDocument(contextURI + servletPath + "/" + handle + "/" + collection);
}
}
try {
WireFeedInput input = new WireFeedInput();
WireFeed wireFeed = input.build(new InputStreamReader(in, "UTF-8"));
return (Feed)wireFeed;
} catch (Exception ex) {
throw new AtomException(ex);
}
}
/**
* Get list of one Categories object containing categories allowed by collection.
* @param inline True if Categories object should contain collection of
* in-line Categories objects or false if it should set the
* Href for out-of-line categories.
*/
public List getCategories(boolean inline) {
Categories cats = new Categories();
cats.setFixed(true);
cats.setScheme(contextURI + "/" + handle + "/" + singular);
if (inline) {
for (int i=0; i<catNames.length; i++) {
Category cat = new Category();
cat.setTerm(catNames[i]);
cats.addCategory(cat);
}
} else {
cats.setHref(getCategoriesURI());
}
return Collections.singletonList(cats);
}
/**
* Get list of one Categories object containing categories allowed by collection,
* returns in-line categories if collection set to use in-line categories.
*/
public List getCategories() {
return getCategories(inlineCats);
}
/**
* Add entry to collection.
* @param entry Entry to be added to collection. Entry will be saved to disk in a
* directory under the collection's directory and the path will follow the
* pattern [collection-plural]/[entryid]/entry.xml. The entry will be added
* to the collection's feed in [collection-plural]/feed.xml.
* @throws java.lang.Exception On error.
* @return Entry as it exists on the server.
*/
public Entry addEntry(Entry entry) throws Exception {
synchronized (FileStore.getFileStore()) {
Feed f = getFeedDocument();
String fsid = FileStore.getFileStore().getNextId();
updateTimestamps(entry);
// Save entry to file
String entryPath = getEntryPath(fsid);
OutputStream os = FileStore.getFileStore().getFileOutputStream(entryPath);
updateEntryAppLinks(entry, fsid, true);
Atom10Generator.serializeEntry(entry, new OutputStreamWriter(os, "UTF-8"));
os.flush();
os.close();
// Update feed file
updateEntryAppLinks(entry, fsid, false);
updateFeedDocumentWithNewEntry(f, entry);
return entry;
}
}
/**
* Add media entry to collection. Accepts a media file to be added to collection.
* The file will be saved to disk in a directory under the collection's directory
* and the path will follow the pattern <code>[collection-plural]/[entryid]/media/[entryid]</code>.
* An Atom entry will be created to store metadata for the entry and it will exist
* at the path <code>[collection-plural]/[entryid]/entry.xml</code>.
* The entry will be added to the collection's feed in [collection-plural]/feed.xml.
* @param entry Entry object
* @param slug String to be used in file-name
* @param is Source of media data
* @throws java.lang.Exception On Error
* @return Location URI of entry
*/
public String addMediaEntry(Entry entry, String slug, InputStream is) throws Exception {
synchronized (FileStore.getFileStore()) {
// Save media file temp file
Content content = (Content)entry.getContents().get(0);
if (entry.getTitle() == null) {
entry.setTitle(slug);
}
String fileName = createFileName((slug != null) ? slug : entry.getTitle(), content.getType());
File tempFile = File.createTempFile(fileName, "tmp");
FileOutputStream fos = new FileOutputStream(tempFile);
Utilities.copyInputToOutput(is, fos);
fos.close();
// Save media file
FileInputStream fis = new FileInputStream(tempFile);
saveMediaFile(fileName, content.getType(), tempFile.length(), fis);
fis.close();
File resourceFile = new File(getEntryMediaPath(fileName));
// Create media-link entry
updateTimestamps(entry);
// Save media-link entry
String entryPath = getEntryPath(fileName);
OutputStream os = FileStore.getFileStore().getFileOutputStream(entryPath);
updateMediaEntryAppLinks(entry, resourceFile.getName(), true);
Atom10Generator.serializeEntry(entry, new OutputStreamWriter(os, "UTF-8"));
os.flush();
os.close();
// Update feed with new entry
Feed f = getFeedDocument();
updateMediaEntryAppLinks(entry, resourceFile.getName(), false);
updateFeedDocumentWithNewEntry(f, entry);
return getEntryEditURI(fileName, false, true);
}
}
/**
* Get an entry from the collection.
* @param fsid Internal ID of entry to be returned
* @throws java.lang.Exception On error
* @return Entry specified by fileName/ID
*/
public Entry getEntry(String fsid) throws Exception {
if (fsid.endsWith(".media-link")) {
fsid = fsid.substring(0, fsid.length() - ".media-link".length());
}
String entryPath = getEntryPath(fsid);
checkExistence(entryPath);
InputStream in = FileStore.getFileStore().getFileInputStream(entryPath);
final Entry entry;
String filePath = getEntryMediaPath(fsid);
File resource = new File(fsid);
if (resource.exists()) {
entry = loadAtomResourceEntry(in, resource);
updateMediaEntryAppLinks(entry, fsid, true);
} else {
entry = loadAtomEntry(in);
updateEntryAppLinks(entry, fsid, true);
}
return entry;
}
/**
* Get media resource wrapping a file.
*/
public AtomMediaResource getMediaResource(String fileName) throws Exception {
String filePath = getEntryMediaPath(fileName);
File resource = new File(filePath);
return new AtomMediaResource(resource);
}
/**
* Update an entry in the collection.
* @param entry Updated entry to be stored
* @param fsid Internal ID of entry
* @throws java.lang.Exception On error
*/
public void updateEntry(Entry entry, String fsid) throws Exception {
synchronized (FileStore.getFileStore()) {
Feed f = getFeedDocument();
if (fsid.endsWith(".media-link")) {
fsid = fsid.substring(0, fsid.length() - ".media-link".length());
}
updateTimestamps(entry);
updateEntryAppLinks(entry, fsid, false);
updateFeedDocumentWithExistingEntry(f, entry);
String entryPath = getEntryPath(fsid);
OutputStream os = FileStore.getFileStore().getFileOutputStream(entryPath);
updateEntryAppLinks(entry, fsid, true);
Atom10Generator.serializeEntry(entry, new OutputStreamWriter(os, "UTF-8"));
os.flush();
os.close();
}
}
/**
* Update media associated with a media-link entry.
* @param fileName Internal ID of entry being updated
* @param contentType Content type of data
* @param is Source of updated data
* @throws java.lang.Exception On error
* @return Updated Entry as it exists on server
*/
public Entry updateMediaEntry(String fileName, String contentType, InputStream is) throws Exception {
synchronized (FileStore.getFileStore()) {
File tempFile = File.createTempFile(fileName, "tmp");
FileOutputStream fos = new FileOutputStream(tempFile);
Utilities.copyInputToOutput(is, fos);
fos.close();
// Update media file
FileInputStream fis = new FileInputStream(tempFile);
saveMediaFile(fileName, contentType, tempFile.length(), fis);
fis.close();
File resourceFile = new File(getEntryMediaPath(fileName));
// Load media-link entry to return
String entryPath = getEntryPath(fileName);
InputStream in = FileStore.getFileStore().getFileInputStream(entryPath);
Entry atomEntry = loadAtomResourceEntry(in, resourceFile);
updateTimestamps(atomEntry);
updateMediaEntryAppLinks(atomEntry, fileName, false);
// Update feed with new entry
Feed f = getFeedDocument();
updateFeedDocumentWithExistingEntry(f, atomEntry);
// Save updated media-link entry
OutputStream os = FileStore.getFileStore().getFileOutputStream(entryPath);
updateMediaEntryAppLinks(atomEntry, fileName, true);
Atom10Generator.serializeEntry(atomEntry, new OutputStreamWriter(os, "UTF-8"));
os.flush();
os.close();
return atomEntry;
}
}
/**
* Delete an entry and any associated media file.
* @param fsid Internal ID of entry
* @throws java.lang.Exception On error
*/
public void deleteEntry(String fsid) throws Exception {
synchronized (FileStore.getFileStore()) {
// Remove entry from Feed
Feed feed = getFeedDocument();
updateFeedDocumentRemovingEntry(feed, fsid);
String entryFilePath = this.getEntryPath(fsid);
FileStore.getFileStore().deleteFile(entryFilePath);
String entryMediaPath = this.getEntryMediaPath(fsid);
if (entryMediaPath != null) {
FileStore.getFileStore().deleteFile(entryMediaPath);
}
String entryDirPath = getEntryDirPath(fsid);
FileStore.getFileStore().deleteDirectory(entryDirPath);
try {Thread.sleep(500L);}catch(Exception ignored){}
}
}
private void updateFeedDocumentWithNewEntry(Feed f, Entry e) throws AtomException {
boolean inserted = false;
for (int i=0; i<f.getEntries().size(); i++) {
Entry entry = (Entry)f.getEntries().get(i);
AppModule mod = (AppModule)entry.getModule(AppModule.URI);
AppModule newMod = (AppModule)e.getModule(AppModule.URI);
if (newMod.getEdited().before(mod.getEdited())) {
f.getEntries().add(i, e);
inserted = true;
break;
}
}
if (!inserted) {
f.getEntries().add(0, e);
}
updateFeedDocument(f);
}
private void updateFeedDocumentRemovingEntry(Feed f, String id) throws AtomException {
Entry e = findEntry("urn:uuid:" + id, f);
f.getEntries().remove(e);
updateFeedDocument(f);
}
private void updateFeedDocumentWithExistingEntry(Feed f, Entry e) throws AtomException {
Entry old = findEntry(e.getId(), f);
f.getEntries().remove(old);
boolean inserted = false;
for (int i=0; i<f.getEntries().size(); i++) {
Entry entry = (Entry)f.getEntries().get(i);
AppModule entryAppModule = (AppModule)entry.getModule(AppModule.URI);
AppModule eAppModule = (AppModule)entry.getModule(AppModule.URI);
if (eAppModule.getEdited().before(entryAppModule.getEdited())) {
f.getEntries().add(i, e);
inserted = true;
break;
}
}
if (!inserted) {
f.getEntries().add(0, e);
}
updateFeedDocument(f);
}
private Entry findEntry(String id, Feed f) {
List l = f.getEntries();
for (Iterator it = l.iterator(); it.hasNext();) {
Entry e = (Entry)it.next();
if (id.equals(e.getId()))
return e;
}
return null;
}
private void updateFeedDocument(Feed f) throws AtomException{
try {
synchronized(FileStore.getFileStore()) {
WireFeedOutput wireFeedOutput = new WireFeedOutput();
Document feedDoc = wireFeedOutput.outputJDom( f );
XMLOutputter outputter = new XMLOutputter();
//outputter.setFormat(Format.getPrettyFormat());
OutputStream fos = FileStore.getFileStore().getFileOutputStream(getFeedPath());
outputter.output(feedDoc, new OutputStreamWriter(fos, "UTF-8"));
}
} catch (FeedException fex) {
throw new AtomException(fex);
}catch (IOException ex) {
throw new AtomException(ex);
}
}
private InputStream createDefaultFeedDocument(String uri) throws AtomException {
Feed f = new Feed();
f.setTitle("Feed");
f.setId(uri);
f.setFeedType( FEED_TYPE);
Link selfLink = new Link();
selfLink.setRel("self");
selfLink.setHref(uri);
f.getOtherLinks().add(selfLink);
try {
WireFeedOutput wireFeedOutput = new WireFeedOutput();
Document feedDoc = wireFeedOutput.outputJDom( f );
XMLOutputter outputter = new XMLOutputter();
//outputter.setFormat(Format.getCompactFormat());
OutputStream fos = FileStore.getFileStore().getFileOutputStream(getFeedPath());
outputter.output(feedDoc, new OutputStreamWriter(fos, "UTF-8"));
} catch (FeedException ex) {
throw new AtomException(ex);
} catch (IOException ex) {
throw new AtomException(ex);
} catch ( Exception e ) {
e.printStackTrace();
}
return FileStore.getFileStore().getFileInputStream(getFeedPath());
}
private Entry loadAtomResourceEntry(InputStream in, File file) {
try {
Entry entry = Atom10Parser.parseEntry(
new BufferedReader(new InputStreamReader(in)), null);
updateMediaEntryAppLinks(entry, file.getName(), true);
return entry;
} catch ( Exception e ) {
e.printStackTrace();
return null;
}
}
private void updateEntryAppLinks(Entry entry, String fsid, boolean singleEntry) {
entry.setId("urn:uuid:" + fsid);
// Look for existing alt links and the alt link
Link altLink = null;
List altLinks = entry.getAlternateLinks();
if (altLinks != null) {
for (Iterator it = altLinks.iterator(); it.hasNext();) {
Link link = (Link)it.next();
if (link.getRel() == null || "alternate".equals(link.getRel())) {
altLink = link;
break;
}
}
} else {
// No alt links found, so add them now
altLinks = new ArrayList();
entry.setAlternateLinks(altLinks);
}
// The alt link not found, so add it now
if (altLink == null) {
altLink = new Link();
altLinks.add(altLink);
}
// Set correct value for the alt link
altLink.setRel("alternate");
altLink.setHref(getEntryViewURI(fsid));
// Look for existing other links and the edit link
Link editLink = null;
List otherLinks = entry.getOtherLinks();
if (otherLinks != null) {
for (Iterator it = otherLinks.iterator(); it.hasNext();) {
Link link = (Link)it.next();
if ("edit".equals(link.getRel())) {
editLink = link;
break;
}
}
} else {
// No other links found, so add them now
otherLinks = new ArrayList();
entry.setOtherLinks(otherLinks);
}
// The edit link not found, so add it now
if (editLink == null) {
editLink = new Link();
otherLinks.add(editLink);
}
// Set correct value for the edit link
editLink.setRel("edit");
editLink.setHref(getEntryEditURI(fsid, relativeURIs, singleEntry));
}
private void updateMediaEntryAppLinks(Entry entry, String fileName, boolean singleEntry) {
// TODO: figure out why PNG is missing from Java MIME types
FileTypeMap map = FileTypeMap.getDefaultFileTypeMap();
if (map instanceof MimetypesFileTypeMap) {
try {
((MimetypesFileTypeMap)map).addMimeTypes("image/png png PNG");
} catch (Exception ignored) {}
}
String contentType = map.getContentType(fileName);
entry.setId(getEntryMediaViewURI(fileName));
entry.setTitle(fileName);
entry.setUpdated(new Date());
List otherlinks = new ArrayList();
entry.setOtherLinks(otherlinks);
Link editlink = new Link();
editlink.setRel("edit");
editlink.setHref(getEntryEditURI(fileName, relativeURIs, singleEntry));
otherlinks.add(editlink);
Link editMedialink = new Link();
editMedialink.setRel("edit-media");
editMedialink.setHref(getEntryMediaEditURI(fileName, relativeURIs, singleEntry));
otherlinks.add(editMedialink);
Content content = (Content)entry.getContents().get(0);
content.setSrc(getEntryMediaViewURI(fileName));
List contents = new ArrayList();
contents.add(content);
entry.setContents(contents);
}
/**
* Create a Rome Atom entry based on a Roller entry.
* Content is escaped.
* Link is stored as rel=alternate link.
*/
private Entry loadAtomEntry(InputStream in) {
try {
return Atom10Parser.parseEntry(
new BufferedReader(new InputStreamReader(in, "UTF-8")), null);
} catch ( Exception e ) {
e.printStackTrace();
return null;
}
}
/**
* Update existing or add new app:edited.
*/
private void updateTimestamps(Entry entry) {
// We're not differenting between an update and an edit (yet)
entry.setUpdated(new Date());
AppModule appModule = (AppModule)entry.getModule(AppModule.URI);
if (appModule == null) {
appModule = new AppModuleImpl();
List modules = entry.getModules()==null ? new ArrayList() : entry.getModules();
modules.add(appModule);
entry.setModules(modules);
}
appModule.setEdited(entry.getUpdated());
}
/**
* Save file to website's resource directory.
* @param handle Weblog handle to save to
* @param name Name of file to save
* @param size Size of file to be saved
* @param is Read file from input stream
*/
private void saveMediaFile(
String name, String contentType, long size, InputStream is) throws AtomException {
byte[] buffer = new byte[8192];
int bytesRead = 0;
File dirPath = new File(getEntryMediaPath(name));
if (!dirPath.getParentFile().exists()) {
dirPath.getParentFile().mkdirs();
}
OutputStream bos = null;
try {
bos = new FileOutputStream(dirPath.getAbsolutePath());
while ((bytesRead = is.read(buffer, 0, 8192)) != -1) {
bos.write(buffer, 0, bytesRead);
}
} catch (Exception e) {
throw new AtomException("ERROR uploading file", e);
} finally {
try {
bos.flush();
bos.close();
} catch (Exception ignored) {}
}
}
/**
* Creates a file name for a file based on a weblog handle, title string and a
* content-type.
*
* @param handle Weblog handle
* @param title Title to be used as basis for file name (or null)
* @param contentType Content type of file (must not be null)
*
* If a title is specified, the method will apply the same create-anchor
* logic we use for weblog entries to create a file name based on the title.
*
* If title is null, the base file name will be the weblog handle plus a
* YYYYMMDDHHSS timestamp.
*
* The extension will be formed by using the part of content type that
* comes after he slash.
*
* For example:
* weblog.handle = "daveblog"
* title = "Port Antonio"
* content-type = "image/jpg"
* Would result in port_antonio.jpg
*
* Another example:
* weblog.handle = "daveblog"
* title = null
* content-type = "image/jpg"
* Might result in daveblog-200608201034.jpg
*/
private String createFileName(String title, String contentType) {
if (handle == null) throw new IllegalArgumentException("weblog handle cannot be null");
if (contentType == null) throw new IllegalArgumentException("contentType cannot be null");
String fileName = null;
SimpleDateFormat sdf = new SimpleDateFormat();
sdf.applyPattern("yyyyMMddHHssSSS");
// Determine the extension based on the contentType. This is a hack.
// The info we need to map from contentType to file extension is in
// JRE/lib/content-type.properties, but Java Activation doesn't provide
// a way to do a reverse mapping or to get at the data.
String[] typeTokens = contentType.split("/");
String ext = typeTokens[1];
if (title != null && !title.trim().equals("")) {
// We've got a title, so use it to build file name
String base = Utilities.replaceNonAlphanumeric(title, ' ');
StringTokenizer toker = new StringTokenizer(base);
String tmp = null;
int count = 0;
while (toker.hasMoreTokens() && count < 5) {
String s = toker.nextToken();
s = s.toLowerCase();
tmp = (tmp == null) ? s : tmp + "_" + s;
count++;
}
fileName = tmp + "-" + sdf.format(new Date()) + "." + ext;
} else {
// No title or text, so instead we'll use the item's date
// in YYYYMMDD format to form the file name
fileName = handle + "-" + sdf.format(new Date()) + "." + ext;
}
return fileName;
}
//------------------------------------------------------------ URI methods
private String getEntryEditURI(String fsid, boolean relative, boolean singleEntry) {
String entryURI = null;
if (relative) {
if (singleEntry) {
entryURI = fsid;
} else {
entryURI = singular + "/" + fsid;
}
} else {
entryURI = contextURI + servletPath + "/" + handle + "/" + singular + "/" + fsid;
}
return entryURI;
}
private String getEntryViewURI(String fsid) {
return contextURI + "/" + handle + "/" + collection + "/" + fsid + "/entry.xml";
}
private String getEntryMediaEditURI(String fsid, boolean relative, boolean singleEntry) {
String entryURI = null;
if (relative) {
if (singleEntry) {
entryURI = "media/" + fsid;
} else {
entryURI = singular + "/media/" + fsid;
}
} else {
entryURI = contextURI + servletPath + "/" + handle + "/" + singular + "/media/" + fsid;
}
return entryURI;
}
private String getEntryMediaViewURI(String fsid) {
return contextURI + "/" + handle + "/" + collection + "/" + fsid + "/media/" + fsid;
}
private String getCategoriesURI() {
if (relativeURIs) {
return contextURI + servletPath + "/" + handle + "/" + singular + "/categories";
} else {
return servletPath + "/" + handle + "/" + singular + "/categories";
}
}
//------------------------------------------------------- File path methods
private String getBaseDir() {
return baseDir;
}
private String getFeedPath() {
return getBaseDir() + handle
+ File.separator + collection + File.separator+ "feed.xml";
}
private String getEntryDirPath(String id) {
return getBaseDir() + handle
+ File.separator + collection + File.separator + id;
}
private String getEntryPath(String id) {
return getEntryDirPath(id) + File.separator + "entry.xml";
}
private String getEntryMediaPath(String id) {
return getEntryDirPath(id) + File.separator + "media" + File.separator + id;
}
private static void checkExistence(String path) throws AtomNotFoundException{
if (!FileStore.getFileStore().exists(path)) {
throw new AtomNotFoundException("Entry does not exist");
}
}
}

View file

@ -0,0 +1,34 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.server.impl;
import com.sun.syndication.propono.atom.common.Workspace;
/**
* File based Atom service Workspace.
*/
public class FileBasedWorkspace extends Workspace {
private String baseDir = null;
private String handle = null;
/** Creates a new instance of FileBasedWorkspace */
public FileBasedWorkspace(String handle, String baseDir) {
super(handle, "text");
this.handle = handle;
this.baseDir = baseDir;
}
}

View file

@ -0,0 +1,116 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.server.impl;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Class which helps in handling File persistence related operations.
*/
class FileStore {
private static Log log =
LogFactory.getFactory().getInstance(FileStore.class);
private static final FileStore fileStore = new FileStore();
public String getNextId() {
//return UUID.randomUUID().toString(); // requires JDK 1.5
return RandomStringUtils.randomAlphanumeric(20);
}
public boolean exists(String path) {
File f = new File(path);
return f.exists();
}
public InputStream getFileInputStream(String path) {
log.debug("getFileContents path: " + path);
try {
return new BufferedInputStream(new FileInputStream(path));
} catch (FileNotFoundException e) {
log.debug(" File not found: " + path);
return null;
}
}
public OutputStream getFileOutputStream(String path) {
log.debug("getFileOutputStream path: " + path);
try {
File f = new File(path);
f.getParentFile().mkdirs();
return new BufferedOutputStream(new FileOutputStream(f));
} catch (FileNotFoundException e) {
log.debug(" File not found: " + path);
return null;
}
}
public void createOrUpdateFile(String path, InputStream content) throws FileNotFoundException, IOException {
log.debug("createOrUpdateFile path: " + path);
File f = new File(path);
f.mkdirs();
FileOutputStream out = new FileOutputStream(f);
byte[] buffer = new byte[2048];
int read;
while ((read = content.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
}
public void deleteFile(String path) {
log.debug("deleteFile path: " + path);
File f = new File(path);
if (!f.delete()) {
log.debug(" Failed to delete: " + f.getAbsolutePath());
}
}
public static FileStore getFileStore() {
return fileStore;
}
public boolean deleteDirectory(String path) {
return deleteDirectory(new File(path));
}
public boolean deleteDirectory(File path) {
log.debug("deleteDirectory path: " + path);
if( path.exists() ) {
File[] files = path.listFiles();
for(int i=0; i<files.length; i++) {
if(files[i].isDirectory()) {
deleteDirectory(files[i]);
} else {
files[i].delete();
}
}
}
return( path.delete() );
}
}

View file

@ -0,0 +1,193 @@
/*
* Copyright 2007 Dave Johnson (Blogapps project)
*
* Licensed 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 com.sun.syndication.propono.blogclient;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* Base implementation of a blog entry.
*/
public abstract class BaseBlogEntry implements BlogEntry {
protected String id = null;
protected Person author = null;
protected Content content = null;
protected String title = null;
protected String permalink = null;
protected String summary = null;
protected Date modificationDate = null;
protected Date publicationDate = null;
protected List categories = new ArrayList();
protected boolean draft = false;
private Blog blog = null;
/**
* Contruct abstract blog entry.
*/
public BaseBlogEntry(Blog blog) {
this.blog = blog;
}
/**
* {@inheritDoc}
*/
public String getId() {
return id;
}
/**
* {@inheritDoc}
*/
public String getPermalink() {
return permalink;
}
void setPermalink(String permalink) {
this.permalink = permalink;
}
/**
* {@inheritDoc}
*/
public Person getAuthor() {
return author;
}
/**
* {@inheritDoc}
*/
public void setAuthor(Person author) {
this.author = author;
}
/**
* {@inheritDoc}
*/
public Content getContent() {
return content;
}
/**
* {@inheritDoc}
*/
public void setContent(Content content) {
this.content = content;
}
/**
* {@inheritDoc}
*/
public boolean getDraft() {
return draft;
}
/**
* {@inheritDoc}
*/
public void setDraft(boolean draft) {
this.draft = draft;
}
/**
* {@inheritDoc}
*/
public Date getPublicationDate() {
return publicationDate;
}
/**
* {@inheritDoc}
*/
public void setPublicationDate(Date pubDate) {
this.publicationDate = pubDate;
}
/**
* {@inheritDoc}
*/
public Date getModificationDate() {
return modificationDate;
}
/**
* {@inheritDoc}
*/
public void setModificationDate(Date date) {
modificationDate = date;
}
/**
* {@inheritDoc}
*/
public String getTitle() {
return title;
}
/**
* {@inheritDoc}
*/
public void setTitle(String title) {
this.title = title;
}
/**
* {@inheritDoc}
*/
public String getSummary() {
return summary;
}
/**
* {@inheritDoc}
*/
public void setSummary(String summary) {
this.summary = summary;
}
/**
* {@inheritDoc}
*/
public List getCategories() {
return categories;
}
/**
* {@inheritDoc}
*/
public void setCategories(List categories) {
this.categories = categories;
}
/**
* {@inheritDoc}
*/
public Blog getBlog() {
return blog;
}
void setBlog(Blog blog) {
this.blog = blog;
}
/**
* String representation, returns id.
*/
public String toString() {
return id;
}
}

View file

@ -0,0 +1,213 @@
/*
* Copyright 2007 Dave Johnson (Blogapps project)
*
* Licensed 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 com.sun.syndication.propono.blogclient;
import java.util.List;
import java.util.Iterator;
/**
* <p>Represents a blog, which has collections of entries and resources.
* You can access the collections using the getCollections() and
* getCollection(String name) methods, which return Blog.Collection objects,
* which you can use to create, retrieve update or delete entries within
* a collection.</p>
*/
public interface Blog {
/**
* Token can be used to fetch this blog again from getBlog() method.
* @return Blog object specified by token.
*/
public String getToken();
/**
* Name of this blog.
* @return Display name of this blog.
*/
public String getName();
/**
* Get a single BlogEntry (or BlogResource) by token.
* @param token Token from blog entry's getToken() method.
* @throws com.sun.syndication.propono.blogclient.BlogClientException On error fetching the blog entry.
* @return Blog entry specified by token.
*/
public BlogEntry getEntry(String token) throws BlogClientException;
/**
* Gets listing of entry and resource collections available in the blog,
* including the primary collections.
* @throws BlogClientException On error fetching collections.
* @return List of Blog.Collection objects.
*/
public List getCollections() throws BlogClientException;
/**
* Get collection by token.
* @param token Token from a collection's getToken() method.
* @throws BlogClientException On error fetching collection.
* @return Blog.Collection object.
*/
public Collection getCollection(String token) throws BlogClientException;
/**
* Represents an entry or resource collection on a blog server.
*/
public interface Collection {
/**
* Get blog that contains this collection.
* @return Blog that contains this collection.
*/
public Blog getBlog();
/**
* Title of collection.
* @return Title of collecton.
*/
public String getTitle();
/**
* Token that can be used to fetch collection.
* @return Token that can be used to fetch collection.
*/
public String getToken();
/**
* Content-types accepted by collection.
* @return Comma-separated list of content-types accepted.
*/
public List getAccepts();
/**
* Determines if collection will accept a content-type.
* @param contentType Content-type to be considered.
* @return True of content type will be accepted, false otherwise.
*/
public boolean accepts(String contentType);
/**
* Return categories allowed by colletion.
* @throws BlogClientException On error fetching categories.
* @return List of BlogEntry.Category objects for this collection.
*/
public List getCategories() throws BlogClientException;
/**
* Create but do not save new entry in collection.
* To save entry, call its save() method.
* @throws BlogClientException On error creating entry.
* @return New BlogEntry object.
*/
public BlogEntry newEntry() throws BlogClientException;
/**
* Create but do not save new resource in collection.
* To save resource, call its save() method.
* @param name Name of new resource.
* @param contentType MIME content-type of new resource.
* @param bytes Data for new resource.
* @throws BlogClientException On error creating entry.
* @return New BlogResource object,
*/
public BlogResource newResource(String name, String contentType, byte[] bytes) throws BlogClientException;
/**
* Get iterator over entries/resources in this collection.
* @return List of BlogEntry objects, some may be BlogResources.
* @throws BlogClientException On error fetching entries/resources.
*/
public Iterator getEntries() throws BlogClientException;
/**
* Save or update a BlogEntry in this collection by adding it to this
* collection and then calling it's entry.save() method.
* @param entry BlogEntry to be saved.
* @throws BlogClientException On error saving entry.
* @return URI of entry.
*/
public String saveEntry(BlogEntry entry) throws BlogClientException;
/**
* Save or update resource in this collection
* @param resource BlogResource to be saved.
* @throws BlogClientException On error saving resource.
* @return URI of resource.
*/
public String saveResource(BlogResource resource) throws BlogClientException;
}
// Deprecated primary collection methods, instead use collections directly.
/**
* Get iterator over entries in primary entries collection (the first
* collection that accepts entries). Note that entries may be partial,
* so don't try to update and save them: to update and entry, first fetch
* it with getEntry(), change fields, then call entry.save();
* @return To iterate over all entries in collection.
* @throws BlogClientException On failure or if there is no primary entries collection.
*
* @deprecated Instead use collections directly.
*/
public Iterator getEntries() throws BlogClientException;
/**
* Get entries in primary resources collection (the first
* collection that accepts anything other than entries).
* @throws BlogClientException On failure or if there is no primary resources collection.
* @return To iterate over all resojrces in collection.
*
* @deprecated Instead use collections directly.
*/
public Iterator getResources() throws BlogClientException;
/**
* Create but do not save it to server new BlogEntry in primary entries collection
* (the first collection found that accepts entries). To save the entry to the
* server to a collection, use the entry's save() method.
* @throws BlogClientException On error or if there is no primary entries collection.
* @return Unsaved BlogEntry in primary entries collection.
*
* @deprecated Instead use collections directly.
*/
public BlogEntry newEntry() throws BlogClientException;
/**
* Create but do not save it to server new BlogResource in primary resources collection
* (the first collection found that accepts resources). To save the resource to the
* server to a collection, use the resource's save() method.
* @param name Name of resource to be saved.
* @param type MIME content type of resource data.
* @param bytes Bytes of resource data.
* @throws BlogClientException On error or if there is no primary respurces collection.
* @return Unsaved BlogEntry in primary resources collection.
*
* @deprecated Instead use collections directly.
*/
public BlogResource newResource(String name, String type, byte[] bytes)
throws BlogClientException;
/**
* Returns list of available BlogEntry.Category in primary entries collection.
* @throws BlogClientException On error or if there is no primary entries collection.
* @return List of BlogEntry.Category objects.
*
* @deprecated Instead use collections directly.
*/
public List getCategories() throws BlogClientException;
}

View file

@ -0,0 +1,40 @@
/*
* Copyright 2007 Dave Johnson (Blogapps project)
*
* Licensed 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 com.sun.syndication.propono.blogclient;
/**
* Represents a Blog Client exception, the library throws these instead of
* implementation specific exceptions.
*/
public class BlogClientException extends Exception {
/**
* Construct a new exception
* @param msg Text message that explains exception
*/
public BlogClientException(String msg) {
super(msg);
}
/**
* Construct a new exception which wraps a throwable.
* @param msg Text message that explains exception
* @param t Throwable to be wrapped by exception
*/
public BlogClientException(String msg, Throwable t) {
super(msg, t);
}
}

View file

@ -0,0 +1,34 @@
/*
* Copyright 2007 Dave Johnson (Blogapps project)
*
* Licensed 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 com.sun.syndication.propono.blogclient;
import java.util.List;
/**
* A BlogConnection is a single-user connection to a blog server where the user
* has access to multiple blogs, which are each represented by a Blog interface.
*/
public interface BlogConnection {
/** Returns collection of blogs available from this connection */
public abstract List getBlogs();
/** Get blog by token */
public abstract Blog getBlog(String token);
/** Set appkey (optional, needed by some blog servers) */
public void setAppkey(String appkey);
}

View file

@ -0,0 +1,80 @@
/*
* Copyright 2007 Dave Johnson (Blogapps project)
*
* Licensed 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 com.sun.syndication.propono.blogclient;
import java.lang.reflect.Constructor;
/**
* Entry point to the Blogapps blog client library.
*/
public class BlogConnectionFactory {
// BlogConnection implementations must:
// 1) implement BlogConnection
// 2) privide contructor that accepts three strings args: url, username and password.
// TODO: make implementations configurable
private static String ATOMPROTOCOL_IMPL_CLASS =
"com.sun.syndication.propono.blogclient.atomprotocol.AtomConnection";
private static String METAWEBLOG_IMPL_CLASS =
"com.sun.syndication.propono.blogclient.metaweblog.MetaWeblogConnection";
/**
* Create a connection to a blog server.
* @param type Connection type, must be "atom" or "metaweblog"
* @param url End-point URL to connect to
* @param username Username for login to blog server
* @param password Password for login to blog server
*/
public static BlogConnection getBlogConnection(
String type, String url, String username, String password)
throws BlogClientException {
BlogConnection blogConnection = null;
if (type == null || type.equals("metaweblog")) {
blogConnection = createBlogConnection(
METAWEBLOG_IMPL_CLASS, url, username, password);
} else if (type.equals("atom")) {
blogConnection = createBlogConnection(
ATOMPROTOCOL_IMPL_CLASS, url, username, password);
} else {
throw new BlogClientException("Type must be 'atom' or 'metaweblog'");
}
return blogConnection;
}
private static BlogConnection createBlogConnection(
String className, String url, String username, String password)
throws BlogClientException {
Class conClass;
try {
conClass = Class.forName(className);
} catch (ClassNotFoundException ex) {
throw new BlogClientException(
"BlogConnection impl. class not found: "+className, ex);
}
Class[] args = new Class[] {String.class, String.class, String.class};
Constructor ctor;
try {
ctor = conClass.getConstructor(args);
return (BlogConnection)
ctor.newInstance(new Object[] {url, username, password});
} catch (Throwable t) {
throw new BlogClientException(
"ERROR instantiating BlogConnection impl.", t);
}
}
}

View file

@ -0,0 +1,231 @@
/*
* Copyright 2007 Dave Johnson (Blogapps project)
*
* Licensed 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 com.sun.syndication.propono.blogclient;
import java.util.Date;
import java.util.List;
import java.io.InputStream;
/**
* Represents a single blog entry.
*/
public interface BlogEntry {
/** Get token, which can be used to fetch the blog entry */
public String getToken();
/**
* Save this entry to it's collection. If this is a new entry and does not
* have a collection yet, then save() will save it to the primary collection.
*/
public void save() throws BlogClientException;
/** Delete this entry from blog server */
public void delete() throws BlogClientException;
/** Permanent link to this entry (assigned by server) */
public String getPermalink();
/** Blog is associated with a blog */
public Blog getBlog();
/** Get categories, a list of BlogEntry.Category objects */
public List getCategories();
/** Set categories, a list of BlogEntry.Category objects */
public void setCategories(List categories);
/** Get globally unique ID of this blog entry */
public String getId();
/** Get title of this blog entry */
public String getTitle();
/** Set title of this blog entry */
public void setTitle(String title);
/** Get summary of this blog entry */
public String getSummary();
/** Set summary of this blog entry */
public void setSummary(String summary);
/** Get content of this blog entry */
public Content getContent();
/** Set content of this blog entry */
public void setContent(Content content);
/** Get draft status of this entry */
public boolean getDraft();
/** Set draft status of this entry */
public void setDraft(boolean draft);
/** Get author of this entry */
public Person getAuthor();
/** Set author of this entry */
public void setAuthor(Person author);
/** Set publish date of this entry */
public Date getPublicationDate();
/** Get publish date of this entry */
public void setPublicationDate(Date date);
/** Get update date of this entry */
public Date getModificationDate();
/** Set update date of this entry */
public void setModificationDate(Date date);
/** Represents blog entry content */
public class Content {
String type = "html";
String value = null;
String src = null;
/** Construct content */
public Content() {}
/** Construct content with value (and type="html") */
public Content(String value) {
this.value = value;
}
/** Get value of content if in-line */
public String getValue() {
return value;
}
/** Set value of content if in-line */
public void setValue(String value) {
this.value = value;
}
/**
* Get type of content, either "text", "html", "xhtml" or a MIME content-type.
* Defaults to HTML.
*/
public String getType() {
return type;
}
/**
* Set type of content, either "text", "html", "xhtml" or a MIME content-type.
* Defaults to HTML.
*/
public void setType(String type) {
this.type = type;
}
/** Get URI of content if out-of-line */
public String getSrc() {
return src;
}
/** Set URI of content if out-of-line */
public void setSrc(String src) {
this.src = src;
}
}
/** Represents a blog author or contributor */
public class Person {
String name;
String email;
String url;
/** Get person's email */
public String getEmail() {
return email;
}
/** Set person's email */
public void setEmail(String email) {
this.email = email;
}
/** Get person's name */
public String getName() {
return name;
}
/** Set person's name */
public void setName(String name) {
this.name = name;
}
/** Get person's URL */
public String getUrl() {
return url;
}
/** Set person's URL */
public void setUrl(String url) {
this.url = url;
}
/** Returns person's name */
public String toString() {
return name;
}
}
/** Represents a weblog category */
public class Category {
String id;
String name;
String url;
/**
* Create new Catetory
*/
public Category() {}
/**
* Create new category with name.
*/
public Category(String id) {
this.id = id;
this.name = id;
}
/**
* Determines if categories are equal based on id.
*/
public boolean equals(Object obj) {
Category other = (Category)obj;
if (obj == null) return false;
if (getId() != null && other.getId() != null
&& getId().equals(other.getId())) return true;
return false;
}
/** Get category id */
public String getId() {
return id;
}
/** Set category id */
public void setId(String id) {
this.id = id;
}
/** Get category display name */
public String getName() {
return name;
}
/** Set category display name */
public void setName(String name) {
this.name = name;
}
/** Get URL of category domain */
public String getUrl() {
return url;
}
/** Set URL of category domain */
public void setUrl(String url) {
this.url = url;
}
/** Return category's name or id for display */
public String toString() {
return name!=null ? name : id;
}
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright 2007 Dave Johnson (Blogapps project)
*
* Licensed 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 com.sun.syndication.propono.blogclient;
import java.io.InputStream;
/**
* Represents a file that has been uploaded to a blog.
* <p />
* Resources are modeled as a type of BlogEntry, but be aware: not all servers
* can save resource metadata (i.e. title, category, author, etc.). MetaWeblog
* based servers can't save metadata at all and Atom protocol servers are not
* required to preserve uploaded file metadata.
*/
public interface BlogResource extends BlogEntry {
/** Get resource name (name is required) */
public String getName();
/** Get resource as stream, using content.src as URL */
public InputStream getAsStream() throws BlogClientException;
/** Update resource by immediately uploading new bytes to server */
public void update(byte[] newBytes) throws BlogClientException;
}

View file

@ -0,0 +1,206 @@
/*
* Copyright 2007 Dave Johnson (Blogapps project)
*
* Licensed 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 com.sun.syndication.propono.blogclient.atomprotocol;
import com.sun.syndication.propono.utils.ProponoException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.sun.syndication.propono.blogclient.Blog;
import com.sun.syndication.propono.blogclient.BlogClientException;
import com.sun.syndication.propono.blogclient.BlogEntry;
import com.sun.syndication.propono.blogclient.BlogResource;
import com.sun.syndication.propono.atom.client.ClientAtomService;
import com.sun.syndication.propono.atom.client.ClientCollection;
import com.sun.syndication.propono.atom.client.ClientEntry;
import com.sun.syndication.propono.atom.client.ClientMediaEntry;
import com.sun.syndication.propono.atom.client.ClientWorkspace;
import java.util.Map;
import java.util.TreeMap;
/**
* Atom protocol implementation of the BlogClient Blog interface.
*/
public class AtomBlog implements Blog {
static final Log logger = LogFactory.getLog(AtomBlog.class);
private HttpClient httpClient = null;
private String name = null;
private ClientAtomService service;
private ClientWorkspace workspace = null;
private AtomCollection entriesCollection = null;
private AtomCollection resourcesCollection = null;
private Map collections = new TreeMap();
/**
* Create AtomBlog using specified HTTPClient, user account and workspace,
* called by AtomConnection. Fetches Atom Service document and creates
* an AtomCollection object for each collection found. The first entry
* collection is considered the primary entry collection. And the first
* resource collection is considered the primary resource collection.
*/
AtomBlog(ClientAtomService service, ClientWorkspace workspace) {
this.setService(service);
this.setWorkspace(workspace);
this.name = workspace.getTitle();
Iterator members = workspace.getCollections().iterator();
while (members.hasNext()) {
ClientCollection col = (ClientCollection) members.next();
if (col.accepts("entry") && entriesCollection == null) {
// first entry collection is primary entry collection
entriesCollection = new AtomCollection(this, col);
}
else if (!col.accepts("entry") && resourcesCollection == null) {
// first non-entry collection is primary resource collection
resourcesCollection = new AtomCollection(this, col);
}
collections.put(col.getHrefResolved(), new AtomCollection(this, col));
}
}
/**
* {@inheritDoc}
*/
public String getName() { return name; }
/**
* String display of blog, returns name.
*/
public String toString() { return getName(); }
/**
* {@inheritDoc}
*/
public String getToken() { return entriesCollection.getToken(); }
/**
* {@inheritDoc}
*/
public BlogEntry newEntry() throws BlogClientException {
if (entriesCollection == null) throw new BlogClientException("No entry collection");
return entriesCollection.newEntry();
}
/**
* {@inheritDoc}
*/
public BlogEntry getEntry(String token) throws BlogClientException {
ClientEntry clientEntry = null;
AtomEntry atomEntry = null;
try {
clientEntry = getService().getEntry(token);
} catch (ProponoException ex) {
throw new BlogClientException("ERROR: fetching entry", ex);
}
if (clientEntry != null && clientEntry instanceof ClientMediaEntry) {
return new AtomResource(this, (ClientMediaEntry)clientEntry);
} else if (clientEntry != null && clientEntry instanceof ClientEntry) {
return new AtomEntry(this, clientEntry);
} else {
throw new BlogClientException("ERROR: unknown object type returned");
}
}
/**
* {@inheritDoc}
*/
public Iterator getEntries() throws BlogClientException {
if (entriesCollection == null) throw new BlogClientException("No primary entry collection");
return new AtomEntryIterator(entriesCollection);
}
/**
* {@inheritDoc}
*/
public Iterator getResources() throws BlogClientException {
if (resourcesCollection == null) throw new BlogClientException("No primary entry collection");
return new AtomEntryIterator(resourcesCollection);
}
String saveEntry(BlogEntry entry) throws BlogClientException {
if (entriesCollection == null) throw new BlogClientException("No primary entry collection");
return entriesCollection.saveEntry(entry);
}
void deleteEntry(BlogEntry entry) throws BlogClientException {
if (entriesCollection == null) throw new BlogClientException("No primary entry collection");
entriesCollection.deleteEntry(entry);
}
/**
* {@inheritDoc}
*/
public List getCategories() throws BlogClientException {
if (entriesCollection == null) throw new BlogClientException("No primary entry collection");
return entriesCollection.getCategories();
}
/**
* {@inheritDoc}
*/
public BlogResource newResource(
String name, String contentType, byte[] bytes) throws BlogClientException {
if (resourcesCollection == null) {
throw new BlogClientException("No resource collection");
}
return resourcesCollection.newResource(name, contentType, bytes);
}
String saveResource(BlogResource res) throws BlogClientException {
if (resourcesCollection == null) throw new BlogClientException("No primary resource collection");
return resourcesCollection.saveResource(res);
}
void deleteResource(BlogResource resource) throws BlogClientException {
deleteEntry((BlogEntry)resource);
}
/**
* {@inheritDoc}
*/
public List getCollections() throws BlogClientException {
return new ArrayList(collections.values());
}
/**
* {@inheritDoc}
*/
public Blog.Collection getCollection(String token) throws BlogClientException {
return (Blog.Collection)collections.get(token);
}
ClientAtomService getService() {
return service;
}
void setService(ClientAtomService service) {
this.service = service;
}
ClientWorkspace getWorkspace() {
return workspace;
}
void setWorkspace(ClientWorkspace workspace) {
this.workspace = workspace;
}
}

View file

@ -0,0 +1,165 @@
/*
* Copyright 2007 Dave Johnson (Blogapps project)
*
* Licensed 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 com.sun.syndication.propono.blogclient.atomprotocol;
import com.sun.syndication.feed.atom.Category;
import com.sun.syndication.propono.atom.client.ClientAtomService;
import com.sun.syndication.propono.atom.common.Categories;
import com.sun.syndication.propono.atom.client.ClientCollection;
import com.sun.syndication.propono.atom.client.ClientEntry;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.sun.syndication.propono.blogclient.Blog;
import com.sun.syndication.propono.blogclient.BlogClientException;
import com.sun.syndication.propono.blogclient.BlogEntry;
import com.sun.syndication.propono.blogclient.BlogResource;
/**
* Atom protocol implementation of BlogClient Blog.Collection.
*/
public class AtomCollection implements Blog.Collection {
static final Log logger = LogFactory.getLog(AtomCollection.class);
private Blog blog = null;
private List categories = new ArrayList();
private ClientCollection clientCollection = null;
AtomCollection(AtomBlog blog, ClientCollection col) {
this.blog = blog;
this.clientCollection = col;
for (Iterator catsIter = col.getCategories().iterator(); catsIter.hasNext();) {
Categories cats = (Categories)catsIter.next();
for (Iterator catIter = cats.getCategories().iterator(); catIter.hasNext();) {
Category cat = (Category)catIter.next();
BlogEntry.Category blogCat = new BlogEntry.Category(cat.getTerm());
blogCat.setName(cat.getLabel());
blogCat.setUrl(cat.getScheme());
getCategories().add(blogCat);
}
}
}
/**
* {@inheritDoc}
*/
public String getTitle() {
return getClientCollection().getTitle();
}
/**
* {@inheritDoc}
*/
public String getToken() {
return getClientCollection().getHrefResolved();
}
/**
* {@inheritDoc}
*/
public List getAccepts() {
return getClientCollection().getAccepts();
}
/**
* {@inheritDoc}
*/
public boolean accepts(String ct) {
return getClientCollection().accepts(ct);
}
/**
* {@inheritDoc}
*/
public Iterator getEntries() throws BlogClientException {
return new AtomEntryIterator(this);
}
/**
* {@inheritDoc}
*/
public BlogEntry newEntry() throws BlogClientException {
AtomBlog atomBlog = (AtomBlog)getBlog();
BlogEntry entry = new AtomEntry(atomBlog, this);
return entry;
}
/**
* {@inheritDoc}
*/
public BlogResource newResource(String name, String contentType, byte[] bytes) throws BlogClientException {
return new AtomResource(this, name, contentType, bytes);
}
/**
* {@inheritDoc}
*/
public String saveResource(BlogResource res) throws BlogClientException {
((AtomResource)res).setCollection(this);
res.save();
return res.getContent().getSrc();
}
/**
* {@inheritDoc}
*/
public String saveEntry(BlogEntry entry) throws BlogClientException {
((AtomEntry)entry).setCollection(this);
entry.save();
return entry.getPermalink();
}
void deleteEntry(BlogEntry entry) throws BlogClientException {
try {
ClientAtomService service = ((AtomBlog)getBlog()).getService();
ClientEntry clientEntry = service.getEntry(entry.getToken());
clientEntry.remove();
} catch (Exception e) {
throw new BlogClientException("ERROR deleting entry", e);
}
}
/**
* {@inheritDoc}
*/
public Blog getBlog() {
return blog;
}
void setBlog(AtomBlog blog) {
this.blog = blog;
}
/**
* {@inheritDoc}
*/
public List getCategories() {
return categories;
}
void setCategories(List categories) {
this.categories = categories;
}
ClientCollection getClientCollection() {
return clientCollection;
}
}

View file

@ -0,0 +1,92 @@
/*
* Copyright 2007 Dave Johnson (Blogapps project)
*
* Licensed 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 com.sun.syndication.propono.blogclient.atomprotocol;
import com.sun.syndication.propono.atom.client.AtomClientFactory;
import com.sun.syndication.propono.atom.client.BasicAuthStrategy;
import com.sun.syndication.propono.atom.client.ClientAtomService;
import com.sun.syndication.propono.atom.client.ClientWorkspace;
import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdom.Document;
import com.sun.syndication.propono.blogclient.BlogConnection;
import com.sun.syndication.propono.blogclient.Blog;
import com.sun.syndication.propono.blogclient.BlogClientException;
/**
* Atom protocol of BlogConnection. Connects to Atom server, creates AtomBlog
* object for each Atom workspace found and within each blog a collection for each
* Atom collection found.
*/
public class AtomConnection implements BlogConnection {
private static Log logger = LogFactory.getLog(AtomConnection.class);
private HttpClient httpClient = null;
private Map blogs = new HashMap();
/**
* Create Atom blog client instance for specified URL and user account.
* @param uri End-point URL of Atom service
* @param username Username of account
* @param password Password of account
*/
public AtomConnection(String uri, String username, String password)
throws BlogClientException {
Document doc = null;
try {
ClientAtomService service = (ClientAtomService)
AtomClientFactory.getAtomService(uri, new BasicAuthStrategy(username, password));
Iterator iter = service.getWorkspaces().iterator();
int count = 0;
while (iter.hasNext()) {
ClientWorkspace workspace = (ClientWorkspace)iter.next();
Blog blog = new AtomBlog(service, workspace);
blogs.put(blog.getToken(), blog);
}
} catch (Throwable t) {
throw new BlogClientException("Error connecting to blog server", t);
}
}
/**
* {@inheritDoc}
*/
public List getBlogs() {
return new ArrayList(blogs.values());
}
/**
* {@inheritDoc}
*/
public Blog getBlog(String token) {
return (AtomBlog)blogs.get(token);
}
/**
* {@inheritDoc}
*/
public void setAppkey(String appkey) {
}
}

View file

@ -0,0 +1,240 @@
/*
* Copyright 2007 Dave Johnson (Blogapps project)
*
* Licensed 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 com.sun.syndication.propono.blogclient.atomprotocol;
import com.sun.syndication.propono.utils.ProponoException;
import com.sun.syndication.propono.atom.common.rome.AppModule;
import com.sun.syndication.propono.atom.common.rome.AppModuleImpl;
import com.sun.syndication.propono.blogclient.BlogClientException;
import com.sun.syndication.propono.blogclient.BlogEntry;
import com.sun.syndication.propono.blogclient.BaseBlogEntry;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import com.sun.syndication.feed.atom.Entry;
import com.sun.syndication.feed.atom.Link;
import com.sun.syndication.propono.atom.client.ClientEntry;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.sun.syndication.propono.blogclient.BlogEntry.Person;
/**
* Atom protocol implementation of BlogEntry.
*/
public class AtomEntry extends BaseBlogEntry implements BlogEntry {
static final Log logger = LogFactory.getLog(AtomCollection.class);
String editURI = null;
AtomCollection collection = null;
AtomEntry(AtomBlog blog, AtomCollection collection) throws BlogClientException {
super(blog);
this.collection = collection;
}
AtomEntry(AtomCollection collection, ClientEntry entry) throws BlogClientException {
this((AtomBlog)collection.getBlog(), collection);
//clientEntry = entry;
copyFromRomeEntry(entry);
}
AtomEntry(AtomBlog blog, ClientEntry entry) throws BlogClientException {
super(blog);
//clientEntry = entry;
copyFromRomeEntry(entry);
}
/**
* {@inheritDoc}
*/
public String getToken() {
return editURI;
}
AtomCollection getCollection() {
return collection;
}
void setCollection(AtomCollection collection) {
this.collection = collection;
}
/**
* True if entry's token's are equal.
*/
public boolean equals(Object o) {
if (o instanceof AtomEntry) {
AtomEntry other = (AtomEntry)o;
if (other.getToken() != null && getToken() != null) {
return other.getToken().equals(getToken());
}
}
return false;
}
/**
* {@inheritDoc}
*/
public void save() throws BlogClientException {
boolean create = (getToken() == null);
if (create && getCollection() == null) {
throw new BlogClientException("Cannot save entry, no collection");
} else if (create) {
try {
ClientEntry clientEntry = collection.getClientCollection().createEntry();
copyToRomeEntry(clientEntry);
collection.getClientCollection().addEntry(clientEntry);
copyFromRomeEntry(clientEntry);
} catch (ProponoException ex) {
throw new BlogClientException("Error saving entry", ex);
}
} else {
try {
ClientEntry clientEntry = ((AtomBlog)getBlog()).getService().getEntry(getToken());
copyToRomeEntry(clientEntry);
clientEntry.update();
copyFromRomeEntry(clientEntry);
} catch (ProponoException ex) {
throw new BlogClientException("Error updating entry", ex);
}
}
}
/**
* {@inheritDoc}
*/
public void delete() throws BlogClientException {
if (getToken() == null) {
throw new BlogClientException("Cannot delete unsaved entry");
}
try {
ClientEntry clientEntry = ((AtomBlog)getBlog()).getService().getEntry(editURI);
clientEntry.remove();
} catch (ProponoException ex) {
throw new BlogClientException("Error removing entry", ex);
}
}
void copyFromRomeEntry(ClientEntry entry) {
id = entry.getId();
title = entry.getTitle();
editURI = entry.getEditURI();
List altlinks = entry.getAlternateLinks();
if (altlinks != null) {
for (Iterator iter = altlinks.iterator(); iter.hasNext();) {
Link link = (Link)iter.next();
if ("alternate".equals(link.getRel()) || link.getRel()==null) {
permalink = link.getHrefResolved();
break;
}
}
}
List contents = entry.getContents();
com.sun.syndication.feed.atom.Content romeContent = null;
if (contents != null && contents.size() > 0) {
romeContent = (com.sun.syndication.feed.atom.Content)contents.get(0);
}
if (romeContent != null) {
content = new BlogEntry.Content(romeContent.getValue());
content.setType(romeContent.getType());
content.setSrc(romeContent.getSrc());
}
if (entry.getCategories() != null) {
List cats = new ArrayList();
List romeCats = entry.getCategories();
for (Iterator iter=romeCats.iterator(); iter.hasNext();) {
com.sun.syndication.feed.atom.Category romeCat =
(com.sun.syndication.feed.atom.Category)iter.next();
BlogEntry.Category cat = new BlogEntry.Category();
cat.setId(romeCat.getTerm());
cat.setUrl(romeCat.getScheme());
cat.setName(romeCat.getLabel());
cats.add(cat);
}
categories = cats;
}
List authors = entry.getAuthors();
if (authors!=null && authors.size() > 0) {
com.sun.syndication.feed.atom.Person romeAuthor =
(com.sun.syndication.feed.atom.Person)authors.get(0);
if (romeAuthor != null) {
author = new Person();
author.setName(romeAuthor.getName());
author.setEmail(romeAuthor.getEmail());
author.setUrl(romeAuthor.getUrl());
}
}
publicationDate = entry.getPublished();
modificationDate = entry.getModified();
AppModule control = (AppModule)entry.getModule(AppModule.URI);
if (control != null && control.getDraft() != null) {
draft = control.getDraft().booleanValue();
} else {
draft = false;
}
}
Entry copyToRomeEntry(ClientEntry entry) {
if (id != null) {
entry.setId(id);
}
entry.setTitle(title);
if (author != null) {
com.sun.syndication.feed.atom.Person person =
new com.sun.syndication.feed.atom.Person();
person.setName(author.getName());
person.setEmail(author.getEmail());
person.setUrl(author.getUrl());
List authors = new ArrayList();
authors.add(person);
entry.setAuthors(authors);
}
if (content != null) {
com.sun.syndication.feed.atom.Content romeContent =
new com.sun.syndication.feed.atom.Content();
romeContent.setValue(content.getValue());
romeContent.setType(content.getType());
List contents = new ArrayList();
contents.add(romeContent);
entry.setContents(contents);
}
if (categories != null) {
List romeCats = new ArrayList();
for (Iterator iter=categories.iterator(); iter.hasNext();) {
BlogEntry.Category cat = (BlogEntry.Category)iter.next();
com.sun.syndication.feed.atom.Category romeCategory =
new com.sun.syndication.feed.atom.Category();
romeCategory.setTerm(cat.getId());
romeCategory.setScheme(cat.getUrl());
romeCategory.setLabel(cat.getName());
romeCats.add(romeCategory);
}
entry.setCategories(romeCats);
}
entry.setPublished((publicationDate == null) ? new Date() : publicationDate);
entry.setModified((modificationDate == null) ? new Date() : modificationDate);
List modules = new ArrayList();
AppModule control = new AppModuleImpl();
control.setDraft(new Boolean(draft));
modules.add(control);
entry.setModules(modules);
return entry;
}
}

View file

@ -0,0 +1,72 @@
/*
* Copyright 2007 Dave Johnson (Blogapps project)
*
* Licensed 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 com.sun.syndication.propono.blogclient.atomprotocol;
import com.sun.syndication.propono.atom.client.ClientEntry;
import com.sun.syndication.propono.atom.client.ClientMediaEntry;
import java.util.Iterator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.sun.syndication.propono.blogclient.BlogClientException;
/**
* Atom protocol implementation of BlogClient entry iterator.
*/
public class AtomEntryIterator implements Iterator {
static final Log logger = LogFactory.getLog(AtomEntryIterator.class);
private Iterator iterator = null;
private AtomCollection collection = null;
AtomEntryIterator(AtomCollection collection) throws BlogClientException {
try {
this.collection = collection;
iterator = collection.getClientCollection().getEntries();
} catch (Exception e) {
throw new BlogClientException("ERROR fetching collection", e);
}
}
/**
* True if more entries are available.
*/
public boolean hasNext() {
return iterator.hasNext();
}
/**
* Get next entry.
*/
public Object next() {
try {
ClientEntry entry = (ClientEntry)iterator.next();
if (entry instanceof ClientMediaEntry) {
return new AtomResource(collection, (ClientMediaEntry)entry);
} else {
return new AtomEntry(collection, entry);
}
} catch (Exception e) {
logger.error("ERROR fetching entry", e);
}
return null;
}
/**
* Remove is not supported.
*/
public void remove() {
// optional method, not implemented
}
}

View file

@ -0,0 +1,134 @@
/*
* Copyright 2007 Dave Johnson (Blogapps project)
*
* Licensed 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 com.sun.syndication.propono.blogclient.atomprotocol;
import java.io.InputStream;
import com.sun.syndication.propono.blogclient.BlogClientException;
import com.sun.syndication.propono.blogclient.BlogEntry;
import com.sun.syndication.propono.blogclient.BlogResource;
import com.sun.syndication.feed.atom.Link;
import com.sun.syndication.propono.atom.client.ClientAtomService;
import com.sun.syndication.propono.atom.client.ClientCollection;
import com.sun.syndication.propono.atom.client.ClientEntry;
import com.sun.syndication.propono.atom.client.ClientMediaEntry;
import java.util.Iterator;
import java.util.List;
/**
* Atom protocol implementation of BlogResource.
*/
public class AtomResource extends AtomEntry implements BlogResource {
private AtomCollection collection;
private byte[] bytes;
AtomResource(AtomCollection collection, String name, String contentType, byte[] bytes)
throws BlogClientException {
super((AtomBlog)collection.getBlog(), collection);
this.collection = collection;
this.bytes = bytes;
BlogEntry.Content rcontent = new BlogEntry.Content();
rcontent.setType(contentType);
setContent(rcontent);
}
AtomResource(AtomCollection collection, ClientMediaEntry entry)
throws BlogClientException {
super(collection, entry);
}
AtomResource(AtomBlog blog, ClientMediaEntry entry) throws BlogClientException {
super(blog, entry);
}
/**
* {@inheritDoc}
*/
public String getName() {
return getTitle();
}
byte[] getBytes() {
return bytes;
}
/**
* {@inheritDoc}
*/
public InputStream getAsStream() throws BlogClientException {
try {
return null; //((ClientMediaEntry)clientEntry).getAsStream();
} catch (Exception e) {
throw new BlogClientException("Error creating entry", e);
}
}
/**
* {@inheritDoc}
*/
public void save() throws BlogClientException {
try {
if (getToken() == null) {
ClientAtomService clientService = ((AtomBlog)getBlog()).getService();
ClientCollection clientCollection = collection.getClientCollection();
ClientMediaEntry clientEntry =
new ClientMediaEntry(clientService, clientCollection, getTitle(),
"", getContent().getType(), getBytes());
copyToRomeEntry(clientEntry);
collection.getClientCollection().addEntry(clientEntry);
this.editURI = clientEntry.getEditURI();
} else {
ClientAtomService clientService = ((AtomBlog)getBlog()).getService();
ClientMediaEntry clientEntry = (ClientMediaEntry)clientService.getEntry(editURI);
clientEntry.update();
}
} catch (Exception e) {
throw new BlogClientException("Error creating entry", e);
}
}
/**
* {@inheritDoc}
*/
public void update(byte[] newBytes) throws BlogClientException {
try {
//((ClientMediaEntry)clientEntry).setBytes(newBytes);
//clientEntry.update();
} catch (Exception e) {
throw new BlogClientException("Error creating entry", e);
}
}
void copyFromRomeEntry(ClientEntry entry) {
super.copyFromRomeEntry(entry);
List links = entry.getOtherLinks();
if (links != null) {
for (Iterator iter = links.iterator(); iter.hasNext();) {
Link link = (Link)iter.next();
if ("edit-media".equals(link.getRel())) {
id = link.getHrefResolved();
break;
}
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View file

@ -0,0 +1,436 @@
/*
* Copyright 2007 Dave Johnson (Blogapps project)
*
* Licensed 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 com.sun.syndication.propono.blogclient.metaweblog;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Iterator;
import com.sun.syndication.propono.blogclient.BlogEntry;
import com.sun.syndication.propono.blogclient.Blog;
import com.sun.syndication.propono.blogclient.BlogClientException;
import com.sun.syndication.propono.blogclient.BlogResource;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
/**
* Blog implementation that uses a mix of Blogger and MetaWeblog API methods.
*/
public class MetaWeblogBlog implements Blog {
private String blogid;
private String name;
private URL url;
private String userName;
private String password;
private String appkey = "dummy";
private Map collections;
private XmlRpcClient xmlRpcClient = null;
/**
* {@inheritDoc}
*/
public String getName() { return name; }
/**
* {@inheritDoc}
*/
public String getToken() { return blogid; }
/**
* String representation of blog, returns the name.
*/
public String toString() { return getName(); }
private XmlRpcClient getXmlRpcClient() {
if (xmlRpcClient == null) {
XmlRpcClientConfigImpl xmlrpcConfig = new XmlRpcClientConfigImpl();
xmlrpcConfig.setServerURL(url);
xmlRpcClient = new XmlRpcClient();
xmlRpcClient.setConfig(xmlrpcConfig);
}
return xmlRpcClient;
}
MetaWeblogBlog(String blogid, String name,
URL url, String userName, String password) {
this.blogid = blogid;
this.name = name;
this.url = url;
this.userName = userName;
this.password = password;
this.collections = new TreeMap();
collections.put("entries",
new MetaWeblogBlogCollection(this, "entries", "Entries", "entry"));
collections.put("resources",
new MetaWeblogBlogCollection(this, "resources", "Resources", "*"));
}
MetaWeblogBlog(String blogId, String name,
URL url, String userName, String password, String appkey) {
this(blogId, name, url, userName, password);
this.appkey = appkey;
}
/**
* {@inheritDoc}
*/
public BlogEntry newEntry() {
return new MetaWeblogEntry(this, new HashMap());
}
String saveEntry(BlogEntry entry) throws BlogClientException {
Blog.Collection col = (Blog.Collection)collections.get("entries");
return col.saveEntry(entry);
}
/**
* {@inheritDoc}
*/
public BlogEntry getEntry(String id) throws BlogClientException {
try {
Map result = (Map)
getXmlRpcClient().execute("metaWeblog.getPost", new Object[] {id, userName, password});
return new MetaWeblogEntry(this, result);
} catch (Exception e) {
throw new BlogClientException("ERROR: XML-RPC error getting entry", e);
}
}
void deleteEntry(String id) throws BlogClientException {
try {
getXmlRpcClient().execute("blogger.deletePost",
new Object[] {appkey, id, userName, password, Boolean.FALSE});
} catch (Exception e) {
throw new BlogClientException("ERROR: XML-RPC error getting entry", e);
}
}
/**
* {@inheritDoc}
*/
public Iterator getEntries() throws BlogClientException {
return new EntryIterator();
}
/**
* {@inheritDoc}
*/
public BlogResource newResource(String name, String contentType, byte[] bytes) throws BlogClientException {
return new MetaWeblogResource(this, name, contentType, bytes);
}
String saveResource(MetaWeblogResource resource) throws BlogClientException {
Blog.Collection col = (Blog.Collection)collections.get("resources");
return col.saveResource(resource);
}
BlogResource getResource(String token) throws BlogClientException {
return null;
}
/**
* {@inheritDoc}
*/
public Iterator getResources() throws BlogClientException {
return new NoOpIterator();
}
void deleteResource(BlogResource resource) throws BlogClientException {
// no-op
}
/**
* {@inheritDoc}
*/
public List getCategories() throws BlogClientException {
ArrayList ret = new ArrayList();
try {
Object result =
getXmlRpcClient().execute ("metaWeblog.getCategories",
new Object[] {blogid, userName, password});
if (result != null && result instanceof HashMap) {
// Standard MetaWeblog API style: struct of struts
Map catsmap = (Map)result;
Iterator keys = catsmap.keySet().iterator();
while (keys.hasNext()) {
String key = (String)keys.next();
Map catmap = (Map)catsmap.get(key);
BlogEntry.Category category = new BlogEntry.Category(key);
category.setName((String)catmap.get("description"));
// catmap.get("htmlUrl");
// catmap.get("rssUrl");
ret.add(category);
}
} else if (result != null && result instanceof Object[]) {
// Wordpress style: array of structs
Object[] resultArray = (Object[])result;
for (int i=0; i<resultArray.length; i++) {
Map catmap = (Map)resultArray[i];
String categoryId = (String)catmap.get("categoryId");
String categoryName = (String)catmap.get("categoryName");
BlogEntry.Category category = new BlogEntry.Category(categoryId);
category.setName(categoryName);
ret.add(category);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return ret;
}
private HashMap createPostStructure(BlogEntry entry) {
return ((MetaWeblogEntry)entry).toPostStructure();
}
/**
* {@inheritDoc}
*/
public List getCollections() throws BlogClientException {
return new ArrayList(collections.values());
}
/**
* {@inheritDoc}
*/
public Blog.Collection getCollection(String token) throws BlogClientException {
return (Blog.Collection)collections.get(token);
}
//-------------------------------------------------------------------------
/** MetaWeblog API impplementation of Blog.Collection */
public class MetaWeblogBlogCollection implements Blog.Collection {
private String accept = null;
private String title = null;
private String token = null;
private Blog blog = null;
/**
* @param token Identifier for collection, unique within blog
* @param title Title of collection
* @param accept Content types accepted, either "entry" or "*"
*/
public MetaWeblogBlogCollection(Blog blog, String token, String title, String accept) {
this.blog = blog;
this.accept = accept;
this.title = title;
this.token = token;
}
/**
* {@inheritDoc}
*/
public String getTitle() {
return title;
}
/**
* {@inheritDoc}
*/
public String getToken() {
return token;
}
/**
* {@inheritDoc}
*/
public List getAccepts() {
return Collections.singletonList(accept);
}
/**
* {@inheritDoc}
*/
public BlogResource newResource(String name, String contentType, byte[] bytes) throws BlogClientException {
return blog.newResource(name, contentType, bytes);
}
/**
* {@inheritDoc}
*/
public BlogEntry newEntry() throws BlogClientException {
return blog.newEntry();
}
/**
* {@inheritDoc}
*/
public boolean accepts(String ct) {
if (accept.equals("*")) {
// everything accepted
return true;
} else if (accept.equals("entry") && ct.equals("application/metaweblog+xml")) {
// entries only accepted and "application/metaweblog+xml" means entry
return true;
}
return false;
}
/**
* {@inheritDoc}
*/
public Iterator getEntries() throws BlogClientException {
Iterator ret = null;
if (accept.equals("entry")) {
ret = MetaWeblogBlog.this.getEntries();
} else {
ret = MetaWeblogBlog.this.getResources();
}
return ret;
}
/**
* {@inheritDoc}
*/
public String saveEntry(BlogEntry entry) throws BlogClientException {
String ret = entry.getId();
if (entry.getId() == null) {
try {
ret = (String)getXmlRpcClient().execute("metaWeblog.newPost",
new Object[] {blogid, userName, password, createPostStructure(entry), new Boolean(!entry.getDraft()) });
} catch (Exception e) {
throw new BlogClientException("ERROR: XML-RPC error saving new entry", e);
}
} else {
try {
getXmlRpcClient().execute("metaWeblog.editPost",
new Object[] {entry.getId(),userName,password,createPostStructure(entry),new Boolean(!entry.getDraft())});
} catch (Exception e) {
throw new BlogClientException("ERROR: XML-RPC error updating entry", e);
}
}
return ret;
}
/**
* {@inheritDoc}
*/
public String saveResource(BlogResource res) throws BlogClientException {
MetaWeblogResource resource = (MetaWeblogResource)res;
try {
HashMap resmap = new HashMap();
resmap.put("name", resource.getName());
resmap.put("type", resource.getContent().getType());
resmap.put("bits", resource.getBytes());
Map result = (Map)
getXmlRpcClient().execute("metaWeblog.newMediaObject",
new Object[] {blogid, userName, password, resmap});
String url = (String)result.get("url");
res.getContent().setSrc(url);
return url;
} catch (Exception e) {
throw new BlogClientException("ERROR: loading or uploading file", e);
}
}
/**
* {@inheritDoc}
*/
public List getCategories() throws BlogClientException {
return MetaWeblogBlog.this.getCategories();
}
/**
* {@inheritDoc}
*/
public Blog getBlog() {
return blog;
}
}
//-------------------------------------------------------------------------
/**
* Iterates over MetaWeblog API entries.
*/
public class EntryIterator implements Iterator {
private int pos = 0;
private boolean eod = false;
private static final int BUFSIZE = 30;
private List results = null;
/**
* Iterator for looping over MetaWeblog API entries.
*/
public EntryIterator() throws BlogClientException {
getNextEntries();
}
/**
* Returns true if more entries are avialable.
*/
public boolean hasNext() {
if (pos == results.size() && !eod) {
try { getNextEntries(); } catch (Exception ignored) {}
}
return (pos < results.size());
}
/**
* Get next entry.
*/
public Object next() {
Map entryHash = (Map)results.get(pos++);
return new MetaWeblogEntry(MetaWeblogBlog.this, entryHash);
}
/**
* Remove is not implemented.
*/
public void remove() {
}
private void getNextEntries() throws BlogClientException {
int requestSize = pos + BUFSIZE;
try {
Object[] resultsArray = (Object[])
getXmlRpcClient().execute("metaWeblog.getRecentPosts",
new Object[] {blogid, userName, password, new Integer(requestSize)} );
results = Arrays.asList(resultsArray);
} catch (Exception e) {
throw new BlogClientException("ERROR: XML-RPC error getting entry", e);
}
if (results.size() < requestSize) eod = true;
}
}
//-------------------------------------------------------------------------
/**
* No-op iterator.
*/
public class NoOpIterator implements Iterator {
/**
* No-op
*/
public boolean hasNext() {
return false;
}
/**
* No-op
*/
public Object next() {
return null;
}
/**
* No-op
*/
public void remove() {}
}
}

View file

@ -0,0 +1,105 @@
/*
* Copyright 2007 Dave Johnson (Blogapps project)
*
* Licensed 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 com.sun.syndication.propono.blogclient.metaweblog;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.io.IOException;
import com.sun.syndication.propono.blogclient.BlogConnection;
import com.sun.syndication.propono.blogclient.Blog;
import com.sun.syndication.propono.blogclient.BlogClientException;
import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
/**
* BlogClient implementation that uses a mix of Blogger and MetaWeblog API methods.
*/
public class MetaWeblogConnection implements BlogConnection {
private URL url = null;
private String userName = null;
private String password = null;
private String appkey = "null";
private Map blogs = null;
private XmlRpcClient xmlRpcClient = null;
public MetaWeblogConnection(String url, String userName, String password)
throws BlogClientException {
this.userName = userName;
this.password = password;
try {
this.url = new URL(url);
blogs = createBlogMap();
} catch (Throwable t) {
throw new BlogClientException("ERROR connecting to server", t);
}
}
private XmlRpcClient getXmlRpcClient() {
if (xmlRpcClient == null) {
XmlRpcClientConfigImpl xmlrpcConfig = new XmlRpcClientConfigImpl();
xmlrpcConfig.setServerURL(url);
xmlRpcClient = new XmlRpcClient();
xmlRpcClient.setConfig(xmlrpcConfig);
}
return xmlRpcClient;
}
/**
* {@inheritDoc}
*/
public List getBlogs() {
return new ArrayList(blogs.values());
}
/**
* {@inheritDoc}
*/
private Map createBlogMap() throws XmlRpcException, IOException {
Map blogMap = new HashMap();
Object[] results = (Object[])getXmlRpcClient().execute("blogger.getUsersBlogs",
new Object[] {appkey, userName, password});
for (int i = 0; i < results.length; i++) {
Map blog = (Map)results[i];
String blogid = (String)blog.get("blogid");
String name = (String)blog.get("blogName");
blogMap.put(blogid, new MetaWeblogBlog(blogid, name, url, userName, password));
}
return blogMap;
}
/**
* {@inheritDoc}
*/
public Blog getBlog(String token) {
return (Blog)blogs.get(token);
}
/**
* {@inheritDoc}
*/
public void setAppkey(String appkey) {
this.appkey = appkey;
}
}

View file

@ -0,0 +1,122 @@
/*
* Copyright 2007 Dave Johnson (Blogapps project)
*
* Licensed 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 com.sun.syndication.propono.blogclient.metaweblog;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import com.sun.syndication.propono.blogclient.BlogClientException;
import com.sun.syndication.propono.blogclient.BaseBlogEntry;
import com.sun.syndication.propono.blogclient.BlogEntry;
import java.util.Map;
/**
* MetaWeblog API implementation of an entry.
*/
public class MetaWeblogEntry extends BaseBlogEntry {
MetaWeblogEntry(MetaWeblogBlog blog, Map entryMap) {
super(blog);
id = (String)entryMap.get("postid");
content = new Content((String)entryMap.get("description"));
// let's pretend MetaWeblog API has a content-type
content.setType("application/metaweblog+xml");
// no way to tell if entry is draft or not
draft = false;
title = (String)entryMap.get("title");
publicationDate = (Date)entryMap.get("dateCreated");
permalink = (String)entryMap.get("permaLink");
// AlexisMP: fix to get the author value populated.
author.setName( (String)entryMap.get("userid") );
author.setEmail( (String)entryMap.get("author") );
categories = new ArrayList();
Object[] catArray = (Object[])entryMap.get("categories");
if (catArray != null) {
for (int i=0; i<catArray.length; i++) {
Category cat = new Category((String)catArray[i]);
categories.add(cat);
}
}
}
/**
* {@inheritDoc}
*/
public String getToken() {
return id;
}
/**
* True if tokens are equal
*/
public boolean equals(Object o) {
if (o instanceof MetaWeblogEntry) {
MetaWeblogEntry other = (MetaWeblogEntry)o;
if (other.id != null && id != null) {
return other.id.equals(id);
}
}
return false;
}
/**
* {@inheritDoc}
*/
public void save() throws BlogClientException {
id = ((MetaWeblogBlog)getBlog()).saveEntry(this);
}
/**
* {@inheritDoc}
*/
public void delete() throws BlogClientException {
((MetaWeblogBlog)getBlog()).deleteEntry(id);
}
HashMap toPostStructure() {
HashMap struct = new HashMap();
if (getTitle() != null) {
struct.put("title", getTitle());
}
if (getContent() != null && getContent().getValue() != null) {
struct.put("description", getContent().getValue());
}
if (getCategories() != null && getCategories().size() > 0) {
List catArray = new ArrayList();
List cats = getCategories();
for (int i=0; i<cats.size(); i++) {
BlogEntry.Category cat = (BlogEntry.Category)cats.get(i);
catArray.add(cat.getName());
}
struct.put("categories", catArray);
}
if (getPublicationDate() != null) {
struct.put("dateCreated", getPublicationDate());
}
if (getId() != null) {
struct.put("postid", getId());
}
return struct;
}
}

View file

@ -0,0 +1,112 @@
/*
* Copyright 2007 Dave Johnson (Blogapps project)
*
* Licensed 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 com.sun.syndication.propono.blogclient.metaweblog;
import com.sun.syndication.propono.blogclient.BlogClientException;
import java.io.InputStream;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import com.sun.syndication.propono.blogclient.BlogResource;
import java.util.HashMap;
/**
* MetaWeblog API implementation of an resource entry.
*/
public class MetaWeblogResource extends MetaWeblogEntry implements BlogResource {
private MetaWeblogBlog blog;
private String name;
private String contentType;
private byte[] bytes;
MetaWeblogResource(MetaWeblogBlog blog,
String name, String contentType, byte[] bytes) {
super(blog, new HashMap());
this.blog = blog;
this.name = name;
this.contentType = contentType;
this.bytes = bytes;
this.content = new Content();
this.content.setType(contentType);
}
/**
* {@inheritDoc}
*/
public String getName() {
return name;
}
/**
* {@inheritDoc}
*/
public String getToken() {
return null;
}
/**
* Get content-type of associated media resource.
*/
public String getContentType() {
return contentType;
}
/**
* Get media resource as input stream.
*/
public InputStream getAsStream() throws BlogClientException {
HttpClient httpClient = new HttpClient();
GetMethod method = new GetMethod(permalink);
try {
httpClient.executeMethod(method);
} catch (Exception e) {
throw new BlogClientException("ERROR: error reading file", e);
}
if (method.getStatusCode() != 200) {
throw new BlogClientException("ERROR HTTP status=" + method.getStatusCode());
}
try {
return method.getResponseBodyAsStream();
} catch (Exception e) {
throw new BlogClientException("ERROR: error reading file", e);
}
}
/**
* {@inheritDoc}
*/
public void save() throws BlogClientException {
blog.saveResource(this);
}
/**
* {@inheritDoc}
*/
public void update(byte[] bytes) throws BlogClientException {
this.bytes = bytes;
save();
}
/**
* Get resource data as byte array.
*/
public byte[] getBytes() {
return bytes;
}
/**
* Not supported by MetaWeblog API
*/
public void delete() throws BlogClientException {
}
}

View file

@ -0,0 +1,153 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.utils;
import java.io.PrintStream;
import java.io.PrintWriter;
/**
* Base Propono exception class.
*/
public class ProponoException extends Exception {
private Throwable mRootCause = null;
private String longMessage = null;
/**
* Construct emtpy exception object.
*/
public ProponoException() {
super();
}
/**
* Construct ProponoException with message string.
* @param s Error message string.
*/
public ProponoException(String s) {
super(s);
}
/**
* Construct ProponoException with message string.
* @param s Error message string.
*/
public ProponoException(String s, String longMessage) {
super(s);
this.longMessage = longMessage;
}
/**
* Construct ProponoException, wrapping existing throwable.
* @param s Error message
* @param t Existing connection to wrap.
*/
public ProponoException(String s, Throwable t) {
super(s);
mRootCause = t;
}
/**
* Construct ProponoException, wrapping existing throwable.
* @param s Error message
* @param t Existing connection to wrap.
*/
public ProponoException(String s, String longMessge, Throwable t) {
super(s);
mRootCause = t;
this.longMessage = longMessage;
}
/**
* Construct ProponoException, wrapping existing throwable.
* @param t Existing exception to be wrapped.
*/
public ProponoException(Throwable t) {
mRootCause = t;
}
/**
* Get root cause object, or null if none.
* @return Root cause or null if none.
*/
public Throwable getRootCause() {
return mRootCause;
}
/**
* Get root cause message.
* @return Root cause message.
*/
public String getRootCauseMessage() {
String rcmessage = null;
if (getRootCause()!=null) {
if (getRootCause().getCause()!=null) {
rcmessage = getRootCause().getCause().getMessage();
}
rcmessage = (rcmessage == null) ? getRootCause().getMessage() : rcmessage;
rcmessage = (rcmessage == null) ? super.getMessage() : rcmessage;
rcmessage = (rcmessage == null) ? "NONE" : rcmessage;
}
return rcmessage;
}
/**
* Print stack trace for exception and for root cause exception if htere is one.
* @see java.lang.Throwable#printStackTrace()
*/
public void printStackTrace() {
super.printStackTrace();
if (mRootCause != null) {
System.out.println("--- ROOT CAUSE ---");
mRootCause.printStackTrace();
}
}
/**
* Print stack trace for exception and for root cause exception if htere is one.
* @param s Stream to print to.
*/
public void printStackTrace(PrintStream s) {
super.printStackTrace(s);
if (mRootCause != null) {
s.println("--- ROOT CAUSE ---");
mRootCause.printStackTrace(s);
}
}
/**
* Print stack trace for exception and for root cause exception if htere is one.
* @param s Writer to write to.
*/
public void printStackTrace(PrintWriter s) {
super.printStackTrace(s);
if (null != mRootCause) {
s.println("--- ROOT CAUSE ---");
mRootCause.printStackTrace(s);
}
}
}

View file

@ -0,0 +1,268 @@
/*
* Copyright 2007 Dave Johnson (Blogapps project)
*
* Licensed 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 com.sun.syndication.propono.utils;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.regex.Pattern;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.Namespace;
import org.jdom.Parent;
/**
* Utilities for file I/O and string manipulation.
*/
public class Utilities {
private static final String LS = System.getProperty("line.separator");
/**
* Returns the contents of the file in a byte array (from JavaAlmanac).
*/
public static byte[] getBytesFromFile(File file) throws IOException {
InputStream is = new FileInputStream(file);
// Get the size of the file
long length = file.length();
// You cannot create an array using a long type.
// It needs to be an int type.
// Before converting to an int type, check
// to ensure that file is not larger than Integer.MAX_VALUE.
if (length > Integer.MAX_VALUE) {
// File is too large
}
// Create the byte array to hold the data
byte[] bytes = new byte[(int)length];
// Read in the bytes
int offset = 0;
int numRead = 0;
while (offset < bytes.length
&& (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
offset += numRead;
}
// Ensure all the bytes have been read in
if (offset < bytes.length) {
throw new IOException("Could not completely read file "+file.getName());
}
// Close the input stream and return bytes
is.close();
return bytes;
}
/**
* Read input from stream and into string.
*/
public static String streamToString(InputStream is) throws IOException {
StringBuffer sb = new StringBuffer();
BufferedReader in = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = in.readLine()) != null) {
sb.append(line);
sb.append(LS);
}
return sb.toString();
}
/**
* Copy input stream to output stream using 8K buffer.
*/
public static void copyInputToOutput(
InputStream input,
OutputStream output)
throws IOException {
BufferedInputStream in = new BufferedInputStream(input);
BufferedOutputStream out = new BufferedOutputStream(output);
byte buffer[] = new byte[8192];
for (int count = 0; count != -1;) {
count = in.read(buffer, 0, 8192);
if (count != -1)
out.write(buffer, 0, count);
}
try {
in.close();
out.close();
} catch (IOException ex) {
throw new IOException("Closing file streams, " + ex.getMessage());
}
}
/**
* Replaces occurences of non-alphanumeric characters with a supplied char.
*/
public static String replaceNonAlphanumeric(String str, char subst) {
StringBuffer ret = new StringBuffer(str.length());
char[] testChars = str.toCharArray();
for (int i = 0; i < testChars.length; i++) {
if (Character.isLetterOrDigit(testChars[i])) {
ret.append(testChars[i]);
} else {
ret.append( subst );
}
}
return ret.toString();
}
/**
* Convert string to string array.
*/
public static String[] stringToStringArray(String instr, String delim)
throws NoSuchElementException, NumberFormatException {
StringTokenizer toker = new StringTokenizer(instr, delim);
String stringArray[] = new String[toker.countTokens()];
int i = 0;
while (toker.hasMoreTokens()) {
stringArray[i++] = toker.nextToken();
}
return stringArray;
}
/**
* Convert string array to string.
*/
public static String stringArrayToString(String[] stringArray, String delim) {
String ret = "";
for (int i = 0; i < stringArray.length; i++) {
if (ret.length() > 0)
ret = ret + delim + stringArray[i];
else
ret = stringArray[i];
}
return ret;
}
static Pattern absoluteURIPattern = Pattern.compile("^[a-z0-9]*:.*$");
private static boolean isAbsoluteURI(String uri) {
return absoluteURIPattern.matcher(uri).find();
}
private static boolean isRelativeURI(String uri) {
return !isAbsoluteURI(uri);
}
/**
* }
* Resolve URI based considering xml:base and baseURI.
* @param baseURI Base URI of feed
* @param parent Parent from which to consider xml:base
* @param url URL to be resolved
*/
private static String resolveURI(String baseURI, Parent parent, String url) {
if (isRelativeURI(url)) {
url = (!".".equals(url) && !"./".equals(url)) ? url : "";
// Relative URI with parent
if (parent != null && parent instanceof Element) {
// Do we have an xml:base?
String xmlbase = ((Element)parent).getAttributeValue(
"base", Namespace.XML_NAMESPACE);
if (xmlbase != null && xmlbase.trim().length() > 0) {
if (isAbsoluteURI(xmlbase)) {
// Absolute xml:base, so form URI right now
if (url.startsWith("/")) {
// Host relative URI
int slashslash = xmlbase.indexOf("//");
int nextslash = xmlbase.indexOf("/", slashslash + 2);
if (nextslash != -1) xmlbase = xmlbase.substring(0, nextslash);
return formURI(xmlbase, url);
}
if (!xmlbase.endsWith("/")) {
// Base URI is filename, strip it off
xmlbase = xmlbase.substring(0, xmlbase.lastIndexOf("/"));
}
return formURI(xmlbase, url);
} else {
// Relative xml:base, so walk up tree
return resolveURI(baseURI, parent.getParent(),
stripTrailingSlash(xmlbase) + "/"+ stripStartingSlash(url));
}
}
// No xml:base so walk up tree
return resolveURI(baseURI, parent.getParent(), url);
// Relative URI with no parent (i.e. top of tree), so form URI right now
} else if (parent == null || parent instanceof Document) {
return formURI(baseURI, url);
}
}
return url;
}
/**
* Form URI by combining base with append portion and giving
* special consideration to append portions that begin with ".."
* @param base Base of URI, may end with trailing slash
* @param append String to append, may begin with slash or ".."
*/
private static String formURI(String base, String append) {
base = stripTrailingSlash(base);
append = stripStartingSlash(append);
if (append.startsWith("..")) {
String ret = null;
String[] parts = append.split("/");
for (int i=0; i<parts.length; i++) {
if ("..".equals(parts[i])) {
int last = base.lastIndexOf("/");
if (last != -1) {
base = base.substring(0, last);
append = append.substring(3, append.length());
}
else break;
}
}
}
return base + "/" + append;
}
/**
* Strip starting slash from beginning of string.
*/
private static String stripStartingSlash(String s) {
if (s != null && s.startsWith("/")) {
s = s.substring(1, s.length());
}
return s;
}
/**
* Strip trailing slash from end of string.
*/
private static String stripTrailingSlash(String s) {
if (s != null && s.endsWith("/")) {
s = s.substring(0, s.length() - 1);
}
return s;
}
}

View file

@ -0,0 +1 @@
rome.propono.version=1.0

View file

@ -0,0 +1,7 @@
# Configures Propono APP extension module
atom_1.0.item.ModuleParser.classes=\
com.sun.syndication.propono.atom.common.rome.AppModuleParser
atom_1.0.item.ModuleGenerator.classes=\
com.sun.syndication.propono.atom.common.rome.AppModuleGenerator

View file

@ -0,0 +1,452 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.client;
import com.sun.syndication.feed.atom.Category;
import com.sun.syndication.feed.atom.Content;
import com.sun.syndication.propono.utils.ProponoException;
import com.sun.syndication.propono.atom.common.Categories;
import com.sun.syndication.propono.atom.common.Collection;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Simple APP test designed to run against a live Atom server.
*/
public class AtomClientTest extends TestCase {
private static Log log =
LogFactory.getFactory().getInstance(AtomClientTest.class);
private static ClientAtomService service = null;
// Basic Auth example
private static String endpoint = "http://localhost:8080/sample-atomserver/app";
private static String username = "admin";
private static String password = "admin";
static {
try {
service = AtomClientFactory.getAtomService(endpoint,
new BasicAuthStrategy(username, password));
} catch (Exception e) {
log.error("ERROR creating service", e);
}
}
/*
// Roller OAuth example
private static String endpoint = "http://macsnoopdave:8080/roller-services/app";
private static String consumerKey = "55132608a2fb68816bcd3d1caeafc933";
private static String consumerSecret = "bb420783-fdea-4270-ab83-36445c18c307";
private static String requestUri = "http://macsnoopdave:8080/roller-services/oauth/requestToken";
private static String authorizeUri = "http://macsnoopdave:8080/roller-services/oauth/authorize?userId=roller&oauth_callback=none";
private static String accessUri = "http://macsnoopdave:8080/roller-services/oauth/accessToken";
private static String username = "roller";
private static String password = "n/a";
static {
try {
service = AtomClientFactory.getAtomService(endpoint,
new OAuthStrategy(
username, consumerKey, consumerSecret, "HMAC-SHA1",
requestUri, authorizeUri, accessUri));
} catch (Exception e) {
log.error("ERROR creating service", e);
}
}
*/
// GData Blogger API
/*
private static String endpoint = "http://www.blogger.com/feeds/default/blogs?alt=atom-service";
private static String email = "EMAIL";
private static String password = "PASSWORD";
private static String serviceName = "blogger";
static {
try {
service = AtomClientFactory.getAtomService(endpoint,
new GDataAuthStrategy(email, password, serviceName));
} catch (Exception e) {
log.error("ERROR creating service", e);
}
}
*/
private int maxPagingEntries = 10;
public AtomClientTest(String testName) {
super(testName);
}
public String getEndpoint() {
return endpoint;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
protected void setUp() throws Exception {
}
protected void tearDown() throws Exception {
}
public static Test suite() {
TestSuite suite = new TestSuite(AtomClientTest.class);
return suite;
}
/**
* Tests that server has introspection doc with at least one workspace.
*/
public void testGetAtomService() throws Exception {
assertNotNull(service);
assertTrue(service.getWorkspaces().size() > 0);
for (Iterator it = service.getWorkspaces().iterator(); it.hasNext();) {
ClientWorkspace space = (ClientWorkspace) it.next();
assertNotNull(space.getTitle());
log.debug("Workspace: " + space.getTitle());
for (Iterator colit = space.getCollections().iterator(); colit.hasNext();) {
ClientCollection col = (ClientCollection) colit.next();
log.debug(" Collection: " + col.getTitle() + " Accepts: " + col.getAccepts());
log.debug(" href: " + col.getHrefResolved());
assertNotNull(col.getTitle());
}
}
}
/**
* Tests that entries can be posted and removed in all collections that
* accept entries. Fails if no collections found that accept entries.
*/
public void testSimpleEntryPostAndRemove() throws Exception {
assertNotNull(service);
assertTrue(service.getWorkspaces().size() > 0);
int count = 0;
for (Iterator it = service.getWorkspaces().iterator(); it.hasNext();) {
ClientWorkspace space = (ClientWorkspace) it.next();
assertNotNull(space.getTitle());
for (Iterator colit = space.getCollections().iterator(); colit.hasNext();) {
ClientCollection col = (ClientCollection) colit.next();
if (col.accepts(Collection.ENTRY_TYPE)) {
// we found a collection that accepts entries, so post one
ClientEntry m1 = col.createEntry();
m1.setTitle("Test post");
Content c = new Content();
c.setValue("This is a test post");
c.setType("html");
m1.setContent(c);
col.addEntry(m1);
// entry should now exist on server
ClientEntry m2 = col.getEntry(m1.getEditURI());
assertNotNull(m2);
// remove entry
m2.remove();
// fetching entry now should result in exception
boolean failed = false;
try {
col.getEntry(m1.getEditURI());
} catch (ProponoException e) {
failed = true;
}
assertTrue(failed);
count++;
}
}
}
assertTrue(count > 0);
}
/**
* Tests that entries can be posted, updated and removed in all collections that
* accept entries. Fails if no collections found that accept entries.
*/
public void testSimpleEntryPostUpdateAndRemove() throws Exception {
assertNotNull(service);
assertTrue(service.getWorkspaces().size() > 0);
int count = 0;
for (Iterator it = service.getWorkspaces().iterator(); it.hasNext();) {
ClientWorkspace space = (ClientWorkspace) it.next();
assertNotNull(space.getTitle());
for (Iterator colit = space.getCollections().iterator(); colit.hasNext();) {
ClientCollection col = (ClientCollection) colit.next();
if (col.accepts(Collection.ENTRY_TYPE)) {
// we found a collection that accepts entries, so post one
ClientEntry m1 = col.createEntry();
m1.setTitle(col.getTitle() + ": Test post");
Content c = new Content();
c.setValue("This is a test post");
c.setType("html");
m1.setContent(c);
col.addEntry(m1);
// entry should now exist on server
ClientEntry m2 = (ClientEntry)col.getEntry(m1.getEditURI());
assertNotNull(m2);
m2.setTitle(col.getTitle() + ": Updated title");
m2.update();
// entry should now be updated on server
ClientEntry m3 = (ClientEntry)col.getEntry(m1.getEditURI());
assertEquals(col.getTitle() + ": Updated title", m3.getTitle());
// remove entry
m3.remove();
// fetching entry now should result in exception
boolean failed = false;
try {
col.getEntry(m1.getEditURI());
} catch (ProponoException e) {
failed = true;
}
assertTrue(failed);
count++;
}
}
}
assertTrue(count > 0);
}
public void testFindWorkspace() throws Exception {
assertNotNull(service);
ClientWorkspace ws = (ClientWorkspace)service.findWorkspace("adminblog");
if (ws != null) {
ClientCollection col = (ClientCollection)ws.findCollection(null, "entry");
ClientEntry entry = col.createEntry();
entry.setTitle("NPE on submitting order query");
entry.setContent("This is a <b>bad</b> one!", Content.HTML);
col.addEntry(entry);
// entry should now exist on server
ClientEntry saved = (ClientEntry)col.getEntry(entry.getEditURI());
assertNotNull(saved);
// remove entry
saved.remove();
// fetching entry now should result in exception
boolean failed = false;
try {
col.getEntry(saved.getEditURI());
} catch (ProponoException e) {
failed = true;
}
assertTrue(failed);
}
}
/**
* Test posting an entry to every available collection with a fixed and
* an unfixed category if server support allows, then cleanup.
*/
public void testEntryPostWithCategories() throws Exception {
assertNotNull(service);
assertTrue(service.getWorkspaces().size() > 0);
int count = 0;
for (Iterator it = service.getWorkspaces().iterator(); it.hasNext();) {
ClientWorkspace space = (ClientWorkspace) it.next();
assertNotNull(space.getTitle());
for (Iterator colit = space.getCollections().iterator(); colit.hasNext();) {
ClientCollection col = (ClientCollection) colit.next();
if (col.accepts(Collection.ENTRY_TYPE)) {
// we found a collection that accepts GIF, so post one
ClientEntry m1 = col.createEntry();
m1.setTitle("Test post");
Content c = new Content();
c.setValue("This is a test post");
c.setType("html");
m1.setContent(c);
// if possible, pick one fixed an un unfixed category
Category fixedCat = null;
Category unfixedCat = null;
List entryCats = new ArrayList();
for (int i=0; i<col.getCategories().size(); i++) {
Categories cats = (Categories)col.getCategories().get(i);
if (cats.isFixed() && fixedCat == null) {
String scheme = cats.getScheme();
fixedCat = (Category)cats.getCategories().get(0);
if (fixedCat.getScheme() == null) fixedCat.setScheme(scheme);
entryCats.add(fixedCat);
} else if (!cats.isFixed() && unfixedCat == null) {
String scheme = cats.getScheme();
unfixedCat = new Category();
unfixedCat.setScheme(scheme);
unfixedCat.setTerm("tagster");
entryCats.add(unfixedCat);
}
}
m1.setCategories(entryCats);
col.addEntry(m1);
// entry should now exist on server
ClientEntry m2 = (ClientEntry)col.getEntry(m1.getEditURI());
assertNotNull(m2);
if (fixedCat != null) {
// we added a fixed category, let's make sure it's there
boolean foundCat = false;
for (Iterator catit = m2.getCategories().iterator(); catit.hasNext();) {
Category cat = (Category) catit.next();
if ( cat.getTerm().equals( fixedCat.getTerm())) {
foundCat = true;
}
}
assertTrue(foundCat);
}
if (unfixedCat != null) {
// we added an unfixed category, let's make sure it's there
boolean foundCat = false;
for (Iterator catit = m2.getCategories().iterator(); catit.hasNext();) {
Category cat = (Category) catit.next();
if (cat.getTerm().equals( unfixedCat.getTerm())) {
foundCat = true;
}
}
assertTrue(foundCat);
}
// remove entry
m2.remove();
// fetching entry now should result in exception
boolean failed = false;
try {
col.getEntry(m1.getEditURI());
} catch (ProponoException e) {
failed = true;
}
assertTrue(failed);
count++;
}
}
}
assertTrue(count > 0);
}
/**
* Post media entry to every media colletion avialable on server, then cleanup.
*/
public void testMediaPost() throws Exception {
assertNotNull(service);
assertTrue(service.getWorkspaces().size() > 0);
int count = 0;
for (Iterator it = service.getWorkspaces().iterator(); it.hasNext();) {
ClientWorkspace space = (ClientWorkspace) it.next();
assertNotNull(space.getTitle());
for (Iterator colit = space.getCollections().iterator(); colit.hasNext();) {
ClientCollection col = (ClientCollection) colit.next();
if (col.accepts("image/gif")) {
// we found a collection that accepts GIF, so post one
ClientMediaEntry m1 = col.createMediaEntry("duke"+count, "duke"+count, "image/gif",
new FileInputStream("test/testdata/duke-wave-shadow.gif"));
col.addEntry(m1);
// entry should now exist on server
ClientMediaEntry m2 = (ClientMediaEntry)col.getEntry(m1.getEditURI());
assertNotNull(m2);
// remove entry
m2.remove();
// fetching entry now should result in exception
boolean failed = false;
try {
col.getEntry(m1.getEditURI());
} catch (ProponoException e) {
failed = true;
}
assertTrue(failed);
count++;
}
}
}
assertTrue(count > 0);
}
/**
* Post X media entries each media collection found, test paging, then cleanup.
*
public void testMediaPaging() throws Exception {
ClientAtomService service = getClientAtomService();
assertNotNull(service);
assertTrue(service.getWorkspaces().size() > 0);
int count = 0;
for (Iterator it = service.getWorkspaces().iterator(); it.hasNext();) {
ClientWorkspace space = (ClientWorkspace) it.next();
assertNotNull(space.getTitle());
for (Iterator colit = space.getCollections().iterator(); colit.hasNext();) {
ClientCollection col = (ClientCollection) colit.next();
if (col.accepts("image/gif")) {
// we found a collection that accepts GIF, so post 100 of them
List posted = new ArrayList();
for (int i=0; i<maxPagingEntries; i++) {
ClientMediaEntry m1 = col.createMediaEntry("duke"+count, "duke"+count, "image/gif",
new FileInputStream("test/testdata/duke-wave-shadow.gif"));
col.addEntry(m1);
posted.add(m1);
}
int entryCount = 0;
for (Iterator iter = col.getEntries(); iter.hasNext();) {
ClientMediaEntry entry = (ClientMediaEntry) iter.next();
entryCount++;
}
for (Iterator delit = posted.iterator(); delit.hasNext();) {
ClientEntry entry = (ClientEntry) delit.next();
entry.remove();
}
assertTrue(entryCount >= maxPagingEntries);
count++;
break;
}
}
}
assertTrue(count > 0);
}*/
}

View file

@ -0,0 +1,86 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.client;
import com.sun.syndication.feed.atom.Content;
import java.util.Iterator;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Simple APP test designed to run against Blogger.com.
*/
public class BloggerDotComTest extends TestCase {
private String collectionURI = "http://www.blogger.com/feeds/BLOGID/posts/default";
private String atomServiceURI= "http://www.blogger.com/feeds/default/blogs?alt=atom-service";
private String email = "EMAIL";
private String password = "PASSWORD";
public BloggerDotComTest(String testName) {
super(testName);
}
protected void setUp() throws Exception {
}
protected void tearDown() throws Exception {
}
public static Test suite() {
TestSuite suite = new TestSuite(BloggerDotComTest.class);
return suite;
}
/**
* Verify that server returns service document containing workspaces containing collections.
*/
public void testGetEntries() throws Exception {
// no auth necessary for iterating through entries
ClientCollection col = AtomClientFactory.getCollection(collectionURI,
new GDataAuthStrategy(email, password, "blogger"));
assertNotNull(col);
int count = 0;
for (Iterator it = col.getEntries(); it.hasNext();) {
ClientEntry entry = (ClientEntry) it.next();
assertNotNull(entry);
count++;
}
assertTrue(count > 0);
col = AtomClientFactory.getCollection(collectionURI,
new GDataAuthStrategy(email, password, "blogger"));
ClientEntry p1 = col.createEntry();
p1.setTitle("Propono post");
Content c = new Content();
c.setValue("This is content from ROME Propono");
p1.setContent(c);
col.addEntry(p1);
ClientEntry p2 = col.getEntry(p1.getEditURI());
assertNotNull(p2);
ClientAtomService atomService = AtomClientFactory.getAtomService(
collectionURI, new GDataAuthStrategy(email, password, "blogger"));
assertNotNull(atomService);
}
}

View file

@ -0,0 +1,156 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.common;
import com.sun.syndication.feed.atom.Category;
import java.io.FileInputStream;
import java.util.Iterator;
import junit.framework.*;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
/**
* Tests reading and writing of service document, no server needed.
*/
public class AtomServiceTest extends TestCase {
public AtomServiceTest(String testName) {
super(testName);
}
protected void setUp() throws Exception {
}
protected void tearDown() throws Exception {
}
public static Test suite() {
TestSuite suite = new TestSuite(AtomServiceTest.class);
return suite;
}
/**
* Test of documentToService method, of class AtomService.
*/
public void testDocumentToService() {
try {
// Load service document from disk
SAXBuilder builder = new SAXBuilder();
Document document = builder.build(new FileInputStream("test/testdata/servicedoc1.xml"));
assertNotNull(document);
AtomService service = AtomService.documentToService(document);
int workspaceCount = 0;
// Verify that service contains expected workspaces, collections and categories
for (Iterator it = service.getWorkspaces().iterator(); it.hasNext();) {
Workspace space = (Workspace)it.next();
assertNotNull(space.getTitle());
workspaceCount++;
int collectionCount = 0;
for (Iterator colit = space.getCollections().iterator(); colit.hasNext();) {
Collection col = (Collection)colit.next();
assertNotNull(col.getTitle());
assertNotNull(col.getHrefResolved());
collectionCount++;
int catCount = 0;
if (col.getCategories().size() > 0) {
for (Iterator catsit = col.getCategories().iterator(); catsit.hasNext();) {
Categories cats = (Categories) catsit.next();
for (Iterator catit = cats.getCategories().iterator(); catit.hasNext();) {
Category cat = (Category) catit.next();
catCount++;
}
assertTrue(catCount > 0);
}
}
}
}
assertTrue(workspaceCount > 0);
} catch (Exception e) {
e.printStackTrace();
fail();
}
}
/**
* Test of documentToService method, of class AtomService.
*/
public void testServiceToDocument() {
try {
// Create service with workspace and collections
AtomService service = new AtomService();
Workspace workspace1 = new Workspace("workspace1", null);
Workspace workspace2 = new Workspace("workspace1", null);
service.addWorkspace(workspace1);
service.addWorkspace(workspace2);
Collection collection11 =
new Collection("collection11", null, "http://example.com/app/col11");
Collection collection12 =
new Collection("collection12", null, "http://example.com/app/col12");
workspace1.addCollection(collection11);
workspace1.addCollection(collection12);
Collection collection21 =
new Collection("collection21", null, "http://example.com/app/col21");
Collection collection22 =
new Collection("collection22", null, "http://example.com/app/col22");
workspace2.addCollection(collection21);
workspace2.addCollection(collection22);
// TODO: add categories at collection level
// Convert to JDOM document
Document document = service.serviceToDocument();
// verify that JDOM document contains service, workspace and collection
assertEquals("service", document.getRootElement().getName());
int workspaceCount = 0;
for (Iterator spaceit = document.getRootElement().getChildren().iterator(); spaceit.hasNext();) {
Element elem = (Element) spaceit.next();
if ("workspace".equals(elem.getName())) {
workspaceCount++;
}
boolean workspaceTitle = false;
int collectionCount = 0;
for (Iterator colit = elem.getChildren().iterator(); colit.hasNext();) {
Element colelem = (Element) colit.next();
if ("title".equals(colelem.getName())) {
workspaceTitle = true;
} else if ("collection".equals(colelem.getName())){
collectionCount++;
}
// TODO: test for categories at the collection level
}
assertTrue(workspaceTitle);
assertTrue(collectionCount > 0);
}
assertTrue(workspaceCount > 0);
} catch (Exception e) {
e.printStackTrace();
fail();
}
}
}

View file

@ -0,0 +1,67 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.common;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import junit.framework.*;
/**
* Tests Collection class, no server needed.
*/
public class CollectionTest extends TestCase {
public CollectionTest(String testName) {
super(testName);
}
protected void setUp() throws Exception {
}
protected void tearDown() throws Exception {
}
/**
* Test of accepts method, of class com.sun.syndication.propono.atom.common.Collection.
*/
public void testAccepts() {
Collection col =
new Collection("dummy_title","dummy_titletype","dummy_href");
col.setAccepts(Collections.singletonList("image/*"));
assertTrue(col.accepts("image/gif"));
assertTrue(col.accepts("image/jpg"));
assertTrue(col.accepts("image/png"));
assertFalse(col.accepts("test/html"));
List accepts = new ArrayList();
accepts.add("image/*");
accepts.add("text/*");
col.setAccepts(accepts);
assertTrue(col.accepts("image/gif"));
assertTrue(col.accepts("image/jpg"));
assertTrue(col.accepts("image/png"));
assertTrue(col.accepts("text/html"));
col.setAccepts(Collections.singletonList("*/*"));
assertTrue(col.accepts("image/gif"));
assertTrue(col.accepts("image/jpg"));
assertTrue(col.accepts("image/png"));
assertTrue(col.accepts("text/html"));
}
}

View file

@ -0,0 +1,122 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.server;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.mortbay.http.HttpContext;
import org.mortbay.http.HttpServer;
import org.mortbay.http.SocketListener;
import org.mortbay.jetty.servlet.ServletHandler;
/**
* Test Propono Atom Client against Atom Server via Jetty. Extends
* <code>AtomClientTest</code> to start Jetty server, run tests and then stop
* the Jetty server.
*/
public class AtomClientServerTest { // extends AtomClientTest {
private HttpServer server;
public static final int TESTPORT = 8283;
public static final String ENDPOINT = "http://localhost:" + TESTPORT + "/rome/app";
public static final String USERNAME = "admin";
public static final String PASSWORD = "admin";
public AtomClientServerTest(String s) {
//super(s);
}
public String getEndpoint() {
return ENDPOINT;
}
public String getUsername() {
return USERNAME;
}
public String getPassword() {
return PASSWORD;
}
public static Test suite() {
TestSuite suite = new TestSuite(AtomClientServerTest.class);
return suite;
}
protected HttpServer getServer() {
return server;
}
protected void setUp() throws Exception {
ConsoleHandler handler = new ConsoleHandler();
Logger logger = Logger.getLogger("com.sun.syndication.propono");
logger.setLevel(Level.FINEST);
logger.addHandler(handler);
setupServer();
HttpContext context = createContext();
ServletHandler servlets = createServletHandler();
context.addHandler(servlets);
server.addContext(context);
server.start();
}
private void setupServer() throws InterruptedException {
// Create the server
if (server != null) {
server.stop();
server = null;
}
server = new HttpServer();
// Create a port listener
SocketListener listener = new SocketListener();
listener.setPort(TESTPORT);
server.addListener(listener);
}
private ServletHandler createServletHandler() {
System.setProperty(
"com.sun.syndication.propono.atom.server.AtomHandlerFactory",
"com.sun.syndication.propono.atom.server.TestAtomHandlerFactory");
ServletHandler servlets = new ServletHandler();
servlets.addServlet(
"app", "/app/*",
"com.sun.syndication.propono.atom.server.AtomServlet");
return servlets;
}
private HttpContext createContext() {
HttpContext context = new HttpContext();
context.setContextPath("/rome/*");
return context;
}
protected void tearDown() throws Exception {
if (server != null) {
server.stop();
server.destroy();
server = null;
}
}
}

View file

@ -0,0 +1,27 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.server;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class TestAtomHandlerFactory extends AtomHandlerFactory {
public AtomHandler newAtomHandler(HttpServletRequest req, HttpServletResponse res) {
return new TestAtomHandlerImpl(req, "build/testuploaddir");
}
}

View file

@ -0,0 +1,31 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.atom.server;
import com.sun.syndication.propono.atom.server.impl.FileBasedAtomHandler;
import javax.servlet.http.HttpServletRequest;
public class TestAtomHandlerImpl extends FileBasedAtomHandler {
public TestAtomHandlerImpl(HttpServletRequest req, String uploaddir) {
super(req, uploaddir);
}
public boolean validateUser( String loginId, String password ) {
return AtomClientServerTest.USERNAME.equals(loginId)
&& AtomClientServerTest.PASSWORD.equals(password);
}
}

View file

@ -0,0 +1,215 @@
/*
* Copyright 2007 Sun Microsystems, Inc.
*
* Licensed 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 com.sun.syndication.propono.blogclient;
import com.sun.syndication.io.impl.Atom10Parser;
import com.sun.syndication.propono.utils.Utilities;
import java.io.File;
import java.util.Iterator;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Tests Atom and MetaWeblog API CRUD via BlogClient.
* Exclude this from automated tests because it requires a live blog server.
*/
public class SimpleBlogClientTest extends TestCase {
private String metaweblogEndpoint = "http://localhost:8080/roller/roller-services/xmlrpc";
//private String atomEndpoint = "http://localhost:8080/roller/roller-services/app";
private String atomEndpoint = "http://localhost:8080/sample-atomserver/app";
private String endpoint = "http://localhost:8080/atom-fileserver/app";
private String username = "admin";
private String password = "admin";
public SimpleBlogClientTest(String testName) {
super(testName);
}
protected void setUp() throws Exception {
}
protected void tearDown() throws Exception {
}
public void testBlogClientAtom() throws Exception {
testBlogClient("atom", atomEndpoint);
}
public void testBlogClientMetaWeblog() throws Exception{
testBlogClient("metaweblog", metaweblogEndpoint);
}
public void testBlogClient(String type, String endpoint) throws Exception {
BlogConnection conn = BlogConnectionFactory
.getBlogConnection(type, endpoint, username, password);
int blogCount = 0;
for (Iterator it = conn.getBlogs().iterator(); it.hasNext();) {
Blog blog = (Blog) it.next();
System.out.println(blog.getName());
blogCount++;
}
assertTrue(blogCount > 0);
}
public void testPostAndDeleteAtom() throws Exception {
testPostAndDelete("atom", atomEndpoint);
}
public void testPostAndDeleteMetaWeblog() throws Exception {
testPostAndDelete("metaweblog", metaweblogEndpoint);
}
public void testMediaPostAtom() throws Exception {
testMediaPost("atom", atomEndpoint);
}
public void testMediaPostMetaWeblog() throws Exception {
testMediaPost("metaweblog", metaweblogEndpoint);
}
public void testPostAndDelete(String type, String endpoint) throws Exception {
BlogConnection conn = BlogConnectionFactory
.getBlogConnection(type, endpoint, username, password);
assertNotNull(conn);
String title1 = "Test content";
String content1 = "Test content";
Blog blog = (Blog)conn.getBlogs().get(0);
BlogEntry entry = blog.newEntry();
entry.setTitle(title1);
entry.setContent(new BlogEntry.Content(content1));
entry.save();
String token = entry.getToken();
assertNotNull(token);
entry = blog.getEntry(token);
assertEquals(title1, entry.getTitle());
assertEquals(content1, entry.getContent().getValue());
assertNotNull(entry);
entry.delete();
entry = null;
boolean notFound = false;
try {
entry = blog.getEntry(token);
} catch (Exception e) {
notFound = true;
}
assertTrue(notFound);
}
/**
* Post media entry to every media colletion avialable on server, then cleanup.
*/
public void testMediaPost(String type, String endpoint) throws Exception {
BlogConnection conn = BlogConnectionFactory
.getBlogConnection(type, endpoint, username, password);
assertNotNull(conn);
assertTrue(conn.getBlogs().size() > 0);
int count = 0;
for (Iterator it = conn.getBlogs().iterator(); it.hasNext();) {
Blog blog = (Blog) it.next();
assertNotNull(blog.getName());
for (Iterator colit = blog.getCollections().iterator(); colit.hasNext();) {
Blog.Collection col = (Blog.Collection) colit.next();
if (col.accepts("image/gif")) {
// we found a collection that accepts GIF, so post one
BlogResource m1 = col.newResource("duke"+count, "image/gif",
Utilities.getBytesFromFile(new File("test/testdata/duke-wave-shadow.gif")));
col.saveResource(m1);
if ("atom".equals(type)) { // additional tests for Atom
// entry should now exist on server
BlogResource m2 = (BlogResource)blog.getEntry(m1.getToken());
assertNotNull(m2);
// remove entry
m2.delete();
// fetching entry now should result in exception
boolean failed = false;
try {
blog.getEntry(m1.getToken());
} catch (Exception e) {
failed = true;
}
assertTrue(failed);
}
count++;
}
}
}
assertTrue(count > 0);
}
public void testEntryIterationAtom() throws Exception {
testEntryIteration("atom", atomEndpoint);
}
public void testEntryIterationMetaWeblog() throws Exception {
testEntryIteration("metaweblog", metaweblogEndpoint);
}
public void testEntryIteration(String type, String endpoint) throws Exception {
BlogConnection conn = BlogConnectionFactory
.getBlogConnection(type, endpoint, username, password);
assertNotNull(conn);
String title1 = "Test content";
String content1 = "Test content";
Blog blog = (Blog)conn.getBlogs().get(0);
for (int i=0; i<10; i++) {
BlogEntry entry = blog.newEntry();
entry.setTitle(title1);
entry.setContent(new BlogEntry.Content(content1));
entry.save();
String token = entry.getToken();
assertTrue(Atom10Parser.isAbsoluteURI(token));
assertNotNull(token);
}
for (Iterator it = blog.getEntries(); it.hasNext();) {
BlogEntry blogEntry = (BlogEntry)it.next();
assertTrue(Atom10Parser.isAbsoluteURI(blogEntry.getToken()));
blogEntry.delete();
}
}
public static Test suite() {
TestSuite suite = new TestSuite(SimpleBlogClientTest.class);
return suite;
}
}

View file

@ -0,0 +1,16 @@
#
# Copyright 2007 Sun Microsystems, Inc.
#
# Licensed 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.
#
org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<app:service xmlns:app="http://www.w3.org/2007/app">
<app:workspace>
<atom:title xmlns:atom="http://www.w3.org/2005/Atom">adminblog1</atom:title>
<app:collection href="http://localhost:8080/roller/roller-services/app/adminblog/entries">
<atom:title xmlns:atom="http://www.w3.org/2005/Atom">Weblog Entries</atom:title>
<app:categories app:fixed="yes" app:scheme="http://localhost/roller/adminblog/">
<atom:category xmlns:atom="http://www.w3.org/2005/Atom" atom:term="/General" atom:label="General" />
<atom:category xmlns:atom="http://www.w3.org/2005/Atom" atom:term="/Status" atom:label="Status" />
</app:categories>
<app:accept>entry</app:accept>
</app:collection>
<app:collection href="http://localhost:8080/roller/roller-services/app/adminblog/resources">
<atom:title xmlns:atom="http://www.w3.org/2005/Atom">Media Files</atom:title>
<app:accept>*/*</app:accept>
</app:collection>
</app:workspace>
</app:service>

View file

@ -0,0 +1,19 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. 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. For additional information regarding
# copyright in this work, please see the NOTICE file in the top level
# directory of this distribution.
org.apache.commons.logging.simplelog.log.com.sun.syndication.propono.atom.server.impl.FileBasedAtomHandler=debug
org.apache.commons.logging.simplelog.log.com.sun.syndication.propono.atom.client.AtomClientTest=debug