com.rometools.propono.atom.server.impl.FileBasedCollection Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rome-propono Show documentation
Show all versions of rome-propono Show documentation
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.
/*
* 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.rometools.propono.atom.server.impl;
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.Locale;
import java.util.StringTokenizer;
import javax.activation.FileTypeMap;
import javax.activation.MimetypesFileTypeMap;
import org.jdom2.Document;
import org.jdom2.output.XMLOutputter;
import com.rometools.propono.atom.common.Categories;
import com.rometools.propono.atom.common.Collection;
import com.rometools.propono.atom.common.rome.AppModule;
import com.rometools.propono.atom.common.rome.AppModuleImpl;
import com.rometools.propono.atom.server.AtomException;
import com.rometools.propono.atom.server.AtomMediaResource;
import com.rometools.propono.atom.server.AtomNotFoundException;
import com.rometools.propono.utils.Utilities;
import com.rometools.rome.feed.WireFeed;
import com.rometools.rome.feed.atom.Category;
import com.rometools.rome.feed.atom.Content;
import com.rometools.rome.feed.atom.Entry;
import com.rometools.rome.feed.atom.Feed;
import com.rometools.rome.feed.atom.Link;
import com.rometools.rome.feed.module.Module;
import com.rometools.rome.io.FeedException;
import com.rometools.rome.io.WireFeedInput;
import com.rometools.rome.io.WireFeedOutput;
import com.rometools.rome.io.impl.Atom10Generator;
import com.rometools.rome.io.impl.Atom10Parser;
/**
* 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 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 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(final String title, final String handle, final String collection, final String singular, final String accept,
final boolean inlineCats, final String[] catNames, final boolean relativeURIs, final String contextURI, final String contextPath,
final String servletPath, final 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.servletPath = servletPath;
addAccept(accept);
}
/**
* Get feed document representing collection.
*
* @throws com.rometools.rome.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 {
final WireFeedInput input = new WireFeedInput();
final WireFeed wireFeed = input.build(new InputStreamReader(in, "UTF-8"));
return (Feed) wireFeed;
} catch (final 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(final boolean inline) {
final Categories cats = new Categories();
cats.setFixed(true);
cats.setScheme(contextURI + "/" + handle + "/" + singular);
if (inline) {
for (final String catName : catNames) {
final Category cat = new Category();
cat.setTerm(catName);
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.
*/
@Override
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(final Entry entry) throws Exception {
synchronized (FileStore.getFileStore()) {
final Feed f = getFeedDocument();
final String fsid = FileStore.getFileStore().getNextId();
updateTimestamps(entry);
// Save entry to file
final String entryPath = getEntryPath(fsid);
final 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 [collection-plural]/[entryid]/media/[entryid]
. An Atom entry will be
* created to store metadata for the entry and it will exist at the path
* [collection-plural]/[entryid]/entry.xml
. 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(final Entry entry, final String slug, final InputStream is) throws Exception {
synchronized (FileStore.getFileStore()) {
// Save media file temp file
final Content content = entry.getContents().get(0);
if (entry.getTitle() == null) {
entry.setTitle(slug);
}
final String fileName = createFileName(slug != null ? slug : entry.getTitle(), content.getType());
final File tempFile = File.createTempFile(fileName, "tmp");
final FileOutputStream fos = new FileOutputStream(tempFile);
Utilities.copyInputToOutput(is, fos);
fos.close();
// Save media file
final FileInputStream fis = new FileInputStream(tempFile);
saveMediaFile(fileName, content.getType(), tempFile.length(), fis);
fis.close();
final File resourceFile = new File(getEntryMediaPath(fileName));
// Create media-link entry
updateTimestamps(entry);
// Save media-link entry
final String entryPath = getEntryPath(fileName);
final 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
final 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());
}
final String entryPath = getEntryPath(fsid);
checkExistence(entryPath);
final InputStream in = FileStore.getFileStore().getFileInputStream(entryPath);
final Entry entry;
final 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(final String fileName) throws Exception {
final String filePath = getEntryMediaPath(fileName);
final 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(final Entry entry, String fsid) throws Exception {
synchronized (FileStore.getFileStore()) {
final 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);
final String entryPath = getEntryPath(fsid);
final 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(final String fileName, final String contentType, final InputStream is) throws Exception {
synchronized (FileStore.getFileStore()) {
final File tempFile = File.createTempFile(fileName, "tmp");
final FileOutputStream fos = new FileOutputStream(tempFile);
Utilities.copyInputToOutput(is, fos);
fos.close();
// Update media file
final FileInputStream fis = new FileInputStream(tempFile);
saveMediaFile(fileName, contentType, tempFile.length(), fis);
fis.close();
final File resourceFile = new File(getEntryMediaPath(fileName));
// Load media-link entry to return
final String entryPath = getEntryPath(fileName);
final InputStream in = FileStore.getFileStore().getFileInputStream(entryPath);
final Entry atomEntry = loadAtomResourceEntry(in, resourceFile);
updateTimestamps(atomEntry);
updateMediaEntryAppLinks(atomEntry, fileName, false);
// Update feed with new entry
final Feed f = getFeedDocument();
updateFeedDocumentWithExistingEntry(f, atomEntry);
// Save updated media-link entry
final 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(final String fsid) throws Exception {
synchronized (FileStore.getFileStore()) {
// Remove entry from Feed
final Feed feed = getFeedDocument();
updateFeedDocumentRemovingEntry(feed, fsid);
final String entryFilePath = getEntryPath(fsid);
FileStore.getFileStore().deleteFile(entryFilePath);
final String entryMediaPath = getEntryMediaPath(fsid);
if (entryMediaPath != null) {
FileStore.getFileStore().deleteFile(entryMediaPath);
}
final String entryDirPath = getEntryDirPath(fsid);
FileStore.getFileStore().deleteDirectory(entryDirPath);
try {
Thread.sleep(500L);
} catch (final Exception ignored) {
}
}
}
private void updateFeedDocumentWithNewEntry(final Feed f, final Entry e) throws AtomException {
boolean inserted = false;
for (int i = 0; i < f.getEntries().size(); i++) {
final Entry entry = f.getEntries().get(i);
final AppModule mod = (AppModule) entry.getModule(AppModule.URI);
final 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(final Feed f, final String id) throws AtomException {
final Entry e = findEntry("urn:uuid:" + id, f);
f.getEntries().remove(e);
updateFeedDocument(f);
}
private void updateFeedDocumentWithExistingEntry(final Feed f, final Entry e) throws AtomException {
final Entry old = findEntry(e.getId(), f);
f.getEntries().remove(old);
boolean inserted = false;
for (int i = 0; i < f.getEntries().size(); i++) {
final Entry entry = f.getEntries().get(i);
final AppModule entryAppModule = (AppModule) entry.getModule(AppModule.URI);
final 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(final String id, final Feed feed) {
for (final Entry entry : feed.getEntries()) {
if (id.equals(entry.getId())) {
return entry;
}
}
return null;
}
private void updateFeedDocument(final Feed f) throws AtomException {
try {
synchronized (FileStore.getFileStore()) {
final WireFeedOutput wireFeedOutput = new WireFeedOutput();
final Document feedDoc = wireFeedOutput.outputJDom(f);
final XMLOutputter outputter = new XMLOutputter();
// outputter.setFormat(Format.getPrettyFormat());
final OutputStream fos = FileStore.getFileStore().getFileOutputStream(getFeedPath());
outputter.output(feedDoc, new OutputStreamWriter(fos, "UTF-8"));
}
} catch (final FeedException fex) {
throw new AtomException(fex);
} catch (final IOException ex) {
throw new AtomException(ex);
}
}
private InputStream createDefaultFeedDocument(final String uri) throws AtomException {
final Feed f = new Feed();
f.setTitle("Feed");
f.setId(uri);
f.setFeedType(FEED_TYPE);
final Link selfLink = new Link();
selfLink.setRel("self");
selfLink.setHref(uri);
f.getOtherLinks().add(selfLink);
try {
final WireFeedOutput wireFeedOutput = new WireFeedOutput();
final Document feedDoc = wireFeedOutput.outputJDom(f);
final XMLOutputter outputter = new XMLOutputter();
// outputter.setFormat(Format.getCompactFormat());
final OutputStream fos = FileStore.getFileStore().getFileOutputStream(getFeedPath());
outputter.output(feedDoc, new OutputStreamWriter(fos, "UTF-8"));
} catch (final FeedException ex) {
throw new AtomException(ex);
} catch (final IOException ex) {
throw new AtomException(ex);
} catch (final Exception e) {
e.printStackTrace();
}
return FileStore.getFileStore().getFileInputStream(getFeedPath());
}
private Entry loadAtomResourceEntry(final InputStream in, final File file) {
try {
final Entry entry = Atom10Parser.parseEntry(new BufferedReader(new InputStreamReader(in)), null, Locale.US);
updateMediaEntryAppLinks(entry, file.getName(), true);
return entry;
} catch (final Exception e) {
e.printStackTrace();
return null;
}
}
private void updateEntryAppLinks(final Entry entry, final String fsid, final 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 (final Link link : altLinks) {
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 (final Link link : otherLinks) {
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(final Entry entry, final String fileName, final boolean singleEntry) {
// TODO: figure out why PNG is missing from Java MIME types
final FileTypeMap map = FileTypeMap.getDefaultFileTypeMap();
if (map instanceof MimetypesFileTypeMap) {
try {
((MimetypesFileTypeMap) map).addMimeTypes("image/png png PNG");
} catch (final Exception ignored) {
}
}
entry.setId(getEntryMediaViewURI(fileName));
entry.setTitle(fileName);
entry.setUpdated(new Date());
final List otherlinks = new ArrayList();
entry.setOtherLinks(otherlinks);
final Link editlink = new Link();
editlink.setRel("edit");
editlink.setHref(getEntryEditURI(fileName, relativeURIs, singleEntry));
otherlinks.add(editlink);
final Link editMedialink = new Link();
editMedialink.setRel("edit-media");
editMedialink.setHref(getEntryMediaEditURI(fileName, relativeURIs, singleEntry));
otherlinks.add(editMedialink);
final Content content = entry.getContents().get(0);
content.setSrc(getEntryMediaViewURI(fileName));
final 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(final InputStream in) {
try {
return Atom10Parser.parseEntry(new BufferedReader(new InputStreamReader(in, "UTF-8")), null, Locale.US);
} catch (final Exception e) {
e.printStackTrace();
return null;
}
}
/**
* Update existing or add new app:edited.
*/
private void updateTimestamps(final 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();
final 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(final String name, final String contentType, final long size, final InputStream is) throws AtomException {
final byte[] buffer = new byte[8192];
int bytesRead = 0;
final 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 (final Exception e) {
throw new AtomException("ERROR uploading file", e);
} finally {
try {
bos.flush();
bos.close();
} catch (final 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(final String title, final 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;
final 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.
final String[] typeTokens = contentType.split("/");
final String ext = typeTokens[1];
if (title != null && !title.trim().equals("")) {
// We've got a title, so use it to build file name
final String base = Utilities.replaceNonAlphanumeric(title, ' ');
final 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(final String fsid, final boolean relative, final 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(final String fsid) {
return contextURI + "/" + handle + "/" + collection + "/" + fsid + "/entry.xml";
}
private String getEntryMediaEditURI(final String fsid, final boolean relative, final 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(final 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(final String id) {
return getBaseDir() + handle + File.separator + collection + File.separator + id;
}
private String getEntryPath(final String id) {
return getEntryDirPath(id) + File.separator + "entry.xml";
}
private String getEntryMediaPath(final String id) {
return getEntryDirPath(id) + File.separator + "media" + File.separator + id;
}
private static void checkExistence(final String path) throws AtomNotFoundException {
if (!FileStore.getFileStore().exists(path)) {
throw new AtomNotFoundException("Entry does not exist");
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy