/* Copyright (c) 2008 Google 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.google.gdata.data.photos;
import com.google.gdata.util.common.xml.XmlWriter;
import com.google.gdata.data.BaseEntry;
import com.google.gdata.data.ExtensionProfile;
import com.google.gdata.data.Link;
import com.google.gdata.data.TextConstruct;
import com.google.gdata.data.Kind.AdaptorException;
import com.google.gdata.data.media.MediaEntry;
import com.google.gdata.data.photos.impl.GphotoDataImpl;
import com.google.gdata.util.ServiceException;
import java.io.IOException;
import java.net.URL;
/**
* The base entry class for Picasaweb data. This class provides access to the
* fields that all Picasaweb data objects contain, as well as helper methods
* for subclasses to use. It is also responsible for making the handling of
* the description field consistent across both atom and RSS, allowing the rss
* entries to match the atom entries in a more consistent fashion.
*
*
*/
public class GphotoEntry<E extends GphotoEntry<E>> extends MediaEntry<E>
implements GphotoData, AtomData {
// The gphoto data instance used as a delegate.
private final GphotoData delegate;
/**
* Constructs a new Entry instance.
*/
public GphotoEntry() {
super();
this.delegate = new GphotoDataImpl(this);
}
/**
* Constructs a new entry instance using the source for a shallow copy.
*/
protected GphotoEntry(BaseEntry<?> sourceEntry) {
super(sourceEntry);
this.delegate = new GphotoDataImpl(this);
}
/*
* Declare all extensions on our delegate.
*/
@Override
public void declareExtensions(ExtensionProfile extProfile) {
delegate.declareExtensions(extProfile);
super.declareExtensions(extProfile);
}
/**
* Retrieves the feed link. This is a link to the entry-as-feed, if this
* entry has associated data.
*/
public Link getFeedLink() {
Link feedLink = getLink(Link.Rel.FEED, Link.Type.ATOM);
return feedLink;
}
/**
* Get the feed of entries related to this entry. The kinds parameter is
* a vararg array of associated kinds to return as entries. If the
* kinds parameter is empty, the default kind associated with this feed class
* will be used.
*/
public <F extends GphotoFeed<F>> F getFeed(Class<F> feedClass,
String... kinds) throws IOException, ServiceException {
if (state.service == null) {
throw new ServiceException(
"Entry is not associated with a GData service.");
}
Link feedLink = getFeedLink();
if (feedLink == null) {
throw new UnsupportedOperationException("Missing feed link.");
}
String feedHref = feedLink.getHref();
if (kinds != null && kinds.length > 0) {
StringBuilder kindBuilder = new StringBuilder();
for (int i = 0; i < kinds.length; i++) {
if (i > 0) kindBuilder.append(',');
kindBuilder.append(kinds[i]);
}
if (feedHref.indexOf('?') == -1) {
feedHref += "?kind=" + kindBuilder;
} else {
feedHref += "&kind=" + kindBuilder;
}
}
URL feedUrl = new URL(feedHref);
return state.service.getFeed(feedUrl, feedClass);
}
/**
* Return the gphoto:id.
*/
public String getGphotoId() {
return delegate.getGphotoId();
}
/**
* Set the gphoto:id.
*/
public void setGphotoId(Long id) {
delegate.setGphotoId(id);
}
/**
* Set the gphoto:id.
*/
public void setGphotoId(String id) {
delegate.setGphotoId(id);
}
/**
* Description on an entry is just the summary.
*/
public TextConstruct getDescription() {
return getSummary();
}
/**
* Description on an entry is just the summary.
*/
public void setDescription(TextConstruct description) {
setSummary(description);
}
/*
* This is a hack to allow rss to contain both description and enclosure.
* ATOM summary maps to RSS description, the content will map to enclosure.
*/
@Override
public void generateRss(XmlWriter w, ExtensionProfile extProfile)
throws IOException {
TextConstruct summary = getSummary();
try {
if (summary != null) {
setSummary(new SummaryTextConstruct(summary));
}
super.generateRss(w, extProfile);
} finally {
if (summary != null) {
setSummary(summary);
}
}
}
/**
* Returns an adapted entry that is a subclass of GphotoEntry.
*/
@Override
public GphotoEntry<?> getAdaptedEntry() throws AdaptorException {
return (GphotoEntry<?>) super.getAdaptedEntry();
}
/**
* This class tricks gdata into outputing description instead of atom:summary
* when outputing to RSS. This keeps the handling of the feeds consistent
* to both creators and consumers.
*/
private static class SummaryTextConstruct extends TextConstruct {
private final TextConstruct wrapped;
public SummaryTextConstruct(TextConstruct wrapped) {
this.wrapped = wrapped;
}
@Override
public void generateAtom(XmlWriter w, String elementName)
throws IOException {
wrapped.generateRss(w, "description", RssFormat.FULL_HTML);
}
@Override
public void generateRss(XmlWriter w, String elementName,
RssFormat rssFormat) throws IOException {
wrapped.generateRss(w, elementName, rssFormat);
}
@Override
public String getPlainText() {
return wrapped.getPlainText();
}
@Override
public int getType() {
return wrapped.getType();
}
@Override
public boolean isEmpty() {
return wrapped.isEmpty();
}
}
}