Java tutorial
/* Copyright 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.feedserver.client; import com.google.gdata.client.GoogleService; import com.google.gdata.util.ServiceException; import com.google.inject.Inject; import com.google.feedserver.util.FeedServerClientException; import org.apache.commons.beanutils.BeanMap; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; /** * Implements a parameterized Gdata feed client for FeedServer "payload-in-content" feeds employing * java beans to represent the data. Create a java bean that represents the entity data and * use it as the parameterized type for the feed client. * * @author r@kuci.org (Ray Colline) */ public class FeedServerClient<T> { private static final String ID_ELEMENT = "id"; private static final String NAME_ELEMENT = "name"; // Logging instance private static final Logger LOG = Logger.getLogger(FeedServerClient.class.getName()); // Dependencies private GoogleService service; private Class<T> entityClass; // Java bean /** * Creates client using supplied service and entityClass * * @param service the configured Gdata service. */ @Inject public FeedServerClient(GoogleService service, Class<T> entityClass) { this.service = service; this.entityClass = entityClass; } /** * Fetches generic "payload-in-content" entry into a {@link FeedServerEntry}. The * FeedServerEntry allows you to return the content of the entry as a java bean. * * @param entryUrl the entry URL which can contain any valid ATOM "query" * @return the populated entry. * @throws FeedServerClientException if we cannot contact the feedserver, fetch the URL, or * parse the XML. * @throws RuntimeException if the bean is not constructed properly and is missing fields. */ public FeedServerEntry getEntry(URL entryUrl) throws FeedServerClientException { try { return service.getEntry(entryUrl, FeedServerEntry.class); } catch (IOException e) { throw new FeedServerClientException("Error while fetching " + entryUrl, e); } catch (ServiceException e) { throw new FeedServerClientException(e); } } /** * Fetches generic "payload-in-content" entity into a predefined java bean. This bean should * have fields necessary to receive all the elements of the feed. Using a bean, requires you * know the schema of your feed ahead of time, but gives you the convenience of having first * class object access. * * @param feedUrl the feed URL which can contain any valid ATOM "query" * @return the populated bean. * @throws FeedServerClientException if we cannot contact the feedserver, fetch the URL, or * parse the XML. * @throws RuntimeException if the bean is not constructed properly and is missing fields. */ public T getEntity(URL feedUrl) throws FeedServerClientException { return getEntry(feedUrl).getEntity(entityClass); } /** * Fetches generic "payload-in-content" entry into a list of {@link FeedServerEntry}. The * FeedServerEntry allows you to return the content of the entry as a java bean. * * @param feedUrl the feed URL which can contain any valid ATOM "query" * @return the list of populated entries. * @throws FeedServerClientException if we cannot contact the feedserver, fetch the URL, or * parse the XML. * @throws RuntimeException if the bean is not constructed properly and is missing fields. */ public List<FeedServerEntry> getEntries(URL feedUrl) throws FeedServerClientException { try { FeedServerFeed feed = service.getFeed(feedUrl, FeedServerFeed.class); return feed.getEntries(); } catch (IOException e) { throw new FeedServerClientException("Error while fetching " + feedUrl, e); } catch (ServiceException e) { throw new FeedServerClientException(e); } catch (IllegalArgumentException e) { throw new RuntimeException("Invalid bean " + entityClass.getName(), e); } } /** * Fetches generic "payload-in-content" feed . * * @param feedUrl the feed URL which can contain any valid ATOM "query" * @return the populated feed. * @throws FeedServerClientException if we cannot contact the feedserver, fetch the URL, or * parse the XML. * @throws RuntimeException if the bean is not constructed properly and is missing fields. */ public FeedServerFeed getFeed(URL feedUrl) throws FeedServerClientException { try { return service.getFeed(feedUrl, FeedServerFeed.class); } catch (IOException e) { throw new FeedServerClientException("Error while fetching " + feedUrl, e); } catch (ServiceException e) { throw new FeedServerClientException(e); } catch (IllegalArgumentException e) { throw new RuntimeException("Invalid bean " + entityClass.getName(), e); } } /** * Fetches generic "payload-in-content" entity into a list of predefined java bean. This * bean should have fields necessary to receive all the elements of the feed. Using a bean, * requires you know the schema of your feed ahead of time, but gives you the convenience of * having first class object access. * * @param feedUrl the feed URL which can contain any valid ATOM "query" * @return a list of populated beans representing an entry's entity. * @throws FeedServerClientException if we cannot contact the feedserver, fetch the URL, or * parse the XML. * @throws RuntimeException if the bean is not constructed properly and is missing fields. */ public List<T> getEntities(URL feedUrl) throws FeedServerClientException { List<FeedServerEntry> entries = getEntries(feedUrl); List<T> entities = new ArrayList<T>(); for (FeedServerEntry entry : entries) { entities.add(entry.getEntity(entityClass)); } return entities; } /** * Deletes entry specified by supplied URL. This URL must include the ID. * * @param entryUrl the full URL to the entry in this feed. * @throws FeedServerClientException if any communication issues occur with the feed or the * feed ID is invalid or malformed.. */ public void deleteEntry(URL entryUrl) throws FeedServerClientException { try { service.delete(entryUrl); } catch (IOException e) { throw new FeedServerClientException("Error while deleting " + entryUrl, e); } catch (ServiceException e) { throw new FeedServerClientException(e); } } /** * Deletes specified entry using "name" property contained in the entry's entity. * * @param baseUrl Feed url not including ID * @param entry valid entry containing an entity bean. * @throws FeedServerClientException if any communication issues occur with the feed or the * feed ID is invalid or malformed. */ public void deleteEntry(URL baseUrl, FeedServerEntry entry) throws FeedServerClientException { Object id = getBeanProperty(NAME_ELEMENT, entry.getEntity(entityClass)); if (id == null) { id = getBeanProperty(ID_ELEMENT, entry.getEntity(entityClass)); } if (id == null) { throw new FeedServerClientException("name or id is required in the entry to update"); } try { URL feedUrl = new URL(baseUrl.toString() + "/" + id); LOG.info("deleting entry at feed " + feedUrl); deleteEntry(feedUrl); } catch (MalformedURLException e) { throw new FeedServerClientException("invalid base URL", e); } } /** * Deletes specified entry using "name" property contained in the supplied entity bean. * * @param baseUrl Feed url not including ID * @param entity valid entry bean. * @throws FeedServerClientException if any communication issues occur with the feed or the * feed ID is invalid or malformed. */ public void deleteEntity(URL baseUrl, T entity) throws FeedServerClientException { Object id = getBeanProperty(NAME_ELEMENT, entity); if (id == null) { id = getBeanProperty(ID_ELEMENT, entity); } if (id == null) { throw new FeedServerClientException("name or id is required in the entry to update"); } try { URL feedUrl = new URL(baseUrl.toString() + "/" + id); LOG.info("deleting entry at feed " + feedUrl); deleteEntry(feedUrl); } catch (MalformedURLException e) { throw new FeedServerClientException("invalid base URL", e); } } /** * Deletes specified entries using "name" property contained in the entry's entity. This * makes one request per entry. * * @param baseUrl Feed url not including ID * @param entries list of valid populated entries. * @throws FeedServerClientException if any communication issues occur with the feed or the * feed ID is invalid or malformed. */ public void deleteEntries(URL baseUrl, List<FeedServerEntry> entries) throws FeedServerClientException { for (FeedServerEntry entry : entries) { deleteEntry(baseUrl, entry); } } /** * Deletes specified entries using "name" property contained in the entity bean. This makes one * request per entry. * * @param baseUrl Feed url not including ID * @param entities list of valid entity beans. * @throws FeedServerClientException if any communication issues occur with the feed or the * feed ID is invalid or malformed. */ public void deleteEntities(URL baseUrl, List<T> entities) throws FeedServerClientException { for (T entity : entities) { deleteEntity(baseUrl, entity); } } /** * Updates the entry using the baseUrl plus the ID contained in the entry's entity. * * @param baseUrl fully qualified feed URL. * @param entry populated entry object. * @throws FeedServerClientException if any feed communication errors occur. */ public void updateEntry(URL baseUrl, FeedServerEntry entry) throws FeedServerClientException { Object id = getBeanProperty(NAME_ELEMENT, entry.getEntity(entityClass)); if (id == null) { id = getBeanProperty(ID_ELEMENT, entry.getEntity(entityClass)); } if (id == null) { throw new FeedServerClientException("name or id is required in the entry to update"); } try { LOG.info("updating entry at feed " + baseUrl + "/" + id); URL url = new URL(baseUrl + "/" + id); service.update(url, entry); } catch (IOException e) { throw new FeedServerClientException(e); } catch (ServiceException e) { throw new FeedServerClientException(e); } } /** * Updates the entry using the baseUrl plus the ID contained in the entity. * * @param baseUrl feed URL without an ID. * @param entity a bean representing a feed entry. * @throws FeedServerClientException if any feed communication issues occur or the URL is * malformed. */ public void updateEntity(URL baseUrl, T entity) throws FeedServerClientException { FeedServerEntry entry = new FeedServerEntry(entity); updateEntry(baseUrl, entry); } /** * Updates the entries using the baseUrl plus the ID contained in each entry's entity. * * @param baseUrl feed URL without an ID. * @param entries a list of entries * @throws FeedServerClientException if any feed communication issues occur or the URL is * malformed. */ public void updateEntries(URL baseUrl, List<FeedServerEntry> entries) throws FeedServerClientException { for (FeedServerEntry entry : entries) { updateEntry(baseUrl, entry); } } /** * Updates the entries using the baseUrl plus the ID contained in each entity. * * @param baseUrl feed URL without an ID. * @param entities a list of beans representing feed entries. * @throws FeedServerClientException if any feed communication issues occur or the URL is * malformed. */ public void updateEntities(URL baseUrl, List<T> entities) throws FeedServerClientException { for (T entity : entities) { updateEntity(baseUrl, entity); } } /** * Creates a new entry from the given entity and inserts it. * * @param baseUrl feed URL without an ID. * @param entity a bean representing a feed entry. * @throws FeedServerClientException if any feed communication issues occur or the URL is * malformed. */ @SuppressWarnings("unchecked") public T insertEntity(URL baseUrl, T entity) throws FeedServerClientException { FeedServerEntry entry = new FeedServerEntry(entity); try { LOG.info("inserting entry at feed " + baseUrl); entry = service.insert(baseUrl, entry); return (T) entry.getEntity(entity.getClass()); } catch (IOException e) { throw new FeedServerClientException(e); } catch (ServiceException e) { throw new FeedServerClientException(e); } } /** * Inserts the entry using the baseUrl provided. * * @param baseUrl feed URL without an ID. * @param entry a populated feed entry. * @throws FeedServerClientException if any feed communication issues occur or the URL is * malformed. */ public void insertEntry(URL baseUrl, FeedServerEntry entry) throws FeedServerClientException { try { LOG.info("inserting entry at feed " + baseUrl); service.insert(baseUrl, entry); } catch (IOException e) { throw new FeedServerClientException(e); } catch (ServiceException e) { throw new FeedServerClientException(e); } } /** * Creates an entry for each provided entity and inserts this. This results in one request * for each given entity. * * @param baseUrl feed URL without an ID. * @param entities a list of entity beans each representing a feed entry. * @throws FeedServerClientException if any feed communication issues occur or the URL is * malformed. */ public void insertEntities(URL baseUrl, List<T> entities) throws FeedServerClientException { for (T entity : entities) { insertEntity(baseUrl, entity); } } /** * Inserts the entries provided using the baseUrl provided. This results in one request for * each given entry. * * @param baseUrl feed URL without an ID. * @param entries a list of feed entries. * @throws FeedServerClientException if any feed communication issues occur or the URL is * malformed. */ public void insertEntries(URL baseUrl, List<FeedServerEntry> entries) throws FeedServerClientException { for (FeedServerEntry entry : entries) { insertEntry(baseUrl, entry); } } /** * Helper method to retrieve a property from the provided bean. * * @param propertyName the property to read from the bean. * @param bean the bean to read from. * @return the container supplied. * @throws FeedServerClientException if any problems exist with the bean. */ private Object getBeanProperty(String propertyName, T bean) throws FeedServerClientException { try { BeanMap beanMap = new BeanMap(bean); return beanMap.get(propertyName); } catch (IllegalArgumentException e) { throw new RuntimeException("Invalid bean " + bean.getClass().getName(), e); } catch (SecurityException e) { throw new RuntimeException("Invalid bean " + bean.getClass().getName(), e); } } public GoogleService getService() { return service; } }