Merge branch 'master' of https://code.google.com/p/plexi
Conflicts:
src/adaptorlib/CommandStreamParser.java
diff --git a/src/adaptorlib/AbstractDocumentTransform.java b/src/adaptorlib/AbstractDocumentTransform.java
new file mode 100644
index 0000000..75b05ea
--- /dev/null
+++ b/src/adaptorlib/AbstractDocumentTransform.java
@@ -0,0 +1,78 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// 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 adaptorlib;
+
+import java.util.Map;
+
+/**
+ * Convenience class for implementing {@code DocumentTransform}s.
+ * Implementations only need to implement {@link #transform}, although they
+ * should also likely have a static factory method as defined in {@link
+ * DocumentTransform}.
+ */
+public abstract class AbstractDocumentTransform implements DocumentTransform {
+ private String name = getClass().getName();
+ private boolean required = true;
+
+ public AbstractDocumentTransform() {}
+
+ /**
+ * If {@code name} is {@code null}, the default is used.
+ */
+ public AbstractDocumentTransform(String name, boolean required) {
+ if (name != null) {
+ this.name = name;
+ }
+ this.required = required;
+ }
+
+ /**
+ * Configure this instance with provided {@code config}. Accepts keys {@code
+ * "name"} and {@code "required"}. Unknown keys are ignored. This method is
+ * intended as a convenience for use in a static factory method.
+ */
+ protected void configure(Map<String, String> config) {
+ String name = config.get("name");
+ if (name != null) {
+ this.name = name;
+ }
+
+ String required = config.get("required");
+ if (required != null) {
+ this.required = Boolean.parseBoolean(required);
+ }
+ }
+
+ protected void setName(String name) {
+ if (name == null) {
+ throw new NullPointerException();
+ }
+ this.name = name;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ protected void setRequired(boolean required) {
+ this.required = required;
+ }
+
+ @Override
+ public boolean isRequired() {
+ return required;
+ }
+}
diff --git a/src/adaptorlib/Adaptor.java b/src/adaptorlib/Adaptor.java
index 92baeb9..a267121 100644
--- a/src/adaptorlib/Adaptor.java
+++ b/src/adaptorlib/Adaptor.java
@@ -44,8 +44,6 @@
* to three concurrent calls may be average during initial GSA crawling, but
* twenty or more concurrent calls is typical when the GSA is recrawling
* unmodified content.
- *
- * @throws java.io.FileNotFoundException when requested document doesn't exist
*/
public void getDocContent(Request request, Response response)
throws IOException;
@@ -81,8 +79,8 @@
* <p>If the document doesn't exist, then there are several possibilities. If
* the repository is fully-public then it will return {@code PERMIT}. This
* will allow the caller to provide a cached version of the file to the user
- * or call {@link #getDocContent} which should throw a {@link java.io.
- * FileNotFoundException}. If the adaptor is not sensitive to users knowing
+ * or call {@link #getDocContent} which should call {@link
+ * Response#respondNotFound}. If the adaptor is not sensitive to users knowing
* that certain documents do not exist, then it will return {@code
* INDETERMINATE}. This will be interpreted as the document does not exist; no
* cached copy will be provided to the user but the user may be informed the
diff --git a/src/adaptorlib/AutoUnzipAdaptor.java b/src/adaptorlib/AutoUnzipAdaptor.java
index 11336a5..d8622dd 100644
--- a/src/adaptorlib/AutoUnzipAdaptor.java
+++ b/src/adaptorlib/AutoUnzipAdaptor.java
@@ -93,8 +93,13 @@
try {
OutputStream os = new FileOutputStream(tmpFile);
try {
- Response resp = new GetContentsResponse(os);
+ GetContentsResponse resp = new GetContentsResponse(os);
super.getDocContent(new GetContentsRequest(docId), resp);
+ if (resp.isNotFound()) {
+ log.log(Level.FINE, "Unexpectedly, a doc just listed doesn't "
+ + "exist: {0}", docId);
+ continue;
+ }
} finally {
os.close();
}
@@ -242,6 +247,7 @@
return;
case NOTMODIFIED:
+ case NOTFOUND:
// No content needed, we are done here
return;
@@ -251,9 +257,10 @@
try {
extractDocFromZip(parts[1], tmpFile, new LazyOutputStream(resp));
} catch (FileNotFoundException e) {
- throw new FileNotFoundException(
- "Could not find file within zip for docId '" + docId.getUniqueId()
- + "': " + e.getMessage());
+ log.log(Level.FINE, "Could not find file within zip for docId ''{0}'': "
+ + "{1}", new Object[] {docId.getUniqueId(), e.getMessage()});
+ resp.respondNotFound();
+ return;
}
} finally {
tmpFile.delete();
@@ -353,8 +360,15 @@
}
@Override
- public void respondNotModified() {
+ public void respondNotModified() throws IOException {
state = State.NOTMODIFIED;
+ super.respondNotModified();
+ }
+
+ @Override
+ public void respondNotFound() throws IOException {
+ state = State.NOTFOUND;
+ super.respondNotFound();
}
@Override
@@ -368,7 +382,7 @@
return state;
}
- static enum State {NORESPONSE, NOTMODIFIED, CONTENT};
+ static enum State {NORESPONSE, NOTMODIFIED, NOTFOUND, CONTENT};
}
/**
@@ -388,7 +402,7 @@
* {@link Response#getOutputStream}, but calls {@code getOutputStream} only
* once needed. This allows for code to be provided an OutputStream that
* writes directly to the {@code Response}, but also allows the code to
- * throwing a {@link FileNotFoundException} before writing to the stream.
+ * call {@link Response#respondNotFound} before writing to the stream.
*/
private static class LazyOutputStream extends AbstractLazyOutputStream {
private Response resp;
@@ -397,6 +411,7 @@
this.resp = resp;
}
+ @Override
protected OutputStream retrieveOs() throws IOException {
return resp.getOutputStream();
}
diff --git a/src/adaptorlib/CommandStreamParser.java b/src/adaptorlib/CommandStreamParser.java
index 891e66c..7cd4c54 100644
--- a/src/adaptorlib/CommandStreamParser.java
+++ b/src/adaptorlib/CommandStreamParser.java
@@ -25,9 +25,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
-import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -110,7 +108,7 @@
* "up-to-date" -- specifies that the document is up-to-date with respect to its last crawled
* time.<p>
*
- * "document-not-found" -- the document does not exists in the repository<p>
+ * "not-found" -- the document does not exists in the repository<p>
*
* "mime-type=" -- specifies the document's mime-type. If unspecified then the GSA will
* automatically assign a type to the document. <p>
@@ -168,7 +166,7 @@
public class CommandStreamParser {
- public static enum Operation {
+ private static enum Operation {
ID,
LAST_MODIFIED,
CRAWL_IMMEDIATELY,
@@ -327,7 +325,7 @@
switch (command.getOperation()) {
case ID:
if (docId != null) {
- // TODO (johnfelton) add lister options when API is available
+ // TODO(johnfelton) add lister options when API is available
result.add(new DocIdPusher.Record.Builder(new DocId(docId)).build());
}
docId = command.getArgument();
@@ -357,7 +355,7 @@
}
command = readCommand();
}
- // TODO (johnfelton) add lister options when API is available
+ // TODO(johnfelton) add lister options when API is available
result.add(new DocIdPusher.Record.Builder(new DocId(docId)).build());
return result;
@@ -365,7 +363,7 @@
public RetrieverInfo readFromRetriever() throws IOException {
- Set<MetaItem> metadata = new HashSet<MetaItem>();
+ Metadata.Builder metadata = new Metadata.Builder();
byte[] content = null;
boolean upToDate = false;
boolean notFound = false;
@@ -412,7 +410,7 @@
command = readCommand();
}
- return new RetrieverInfo(new DocId(docId), new Metadata(metadata),
+ return new RetrieverInfo(new DocId(docId), metadata.build(),
content, upToDate, mimeType, notFound);
}
@@ -438,7 +436,7 @@
Operation operation = STRING_TO_OPERATION.get(commandTokens[0]);
// Skip over unrecognized commands
if (operation == null) {
- // TODO (johnfelton) add a warning about an unrecognized command
+ // TODO(johnfelton) add a warning about an unrecognized command
continue;
}
diff --git a/src/adaptorlib/DocumentHandler.java b/src/adaptorlib/DocumentHandler.java
index 2fc8c56..0b9dbdf 100644
--- a/src/adaptorlib/DocumentHandler.java
+++ b/src/adaptorlib/DocumentHandler.java
@@ -19,7 +19,6 @@
import com.sun.net.httpserver.HttpsExchange;
import java.io.ByteArrayOutputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
@@ -139,27 +138,15 @@
DocumentResponse response = new DocumentResponse(ex, docId);
journal.recordRequestProcessingStart();
try {
- try {
- adaptor.getDocContent(request, response);
- } catch (RuntimeException e) {
- journal.recordRequestProcessingFailure();
- throw e;
- } catch (FileNotFoundException e) {
- journal.recordRequestProcessingEnd(0);
- throw e;
- } catch (IOException e) {
- journal.recordRequestProcessingFailure();
- throw e;
- }
- journal.recordRequestProcessingEnd(response.getWrittenContentSize());
- } catch (FileNotFoundException e) {
- log.log(Level.FINE, "FileNotFound during getDocContent. Message: {0}",
- e.getMessage());
- log.log(Level.FINER, "Full FileNotFound information", e);
- cannedRespond(ex, HttpURLConnection.HTTP_NOT_FOUND, "text/plain",
- "Unknown document");
- return;
+ adaptor.getDocContent(request, response);
+ } catch (RuntimeException e) {
+ journal.recordRequestProcessingFailure();
+ throw e;
+ } catch (IOException e) {
+ journal.recordRequestProcessingFailure();
+ throw e;
}
+ journal.recordRequestProcessingEnd(response.getWrittenContentSize());
response.complete();
} else {
@@ -316,6 +303,8 @@
SETUP,
/** No content to send, but we do need a different response code. */
NOT_MODIFIED,
+ /** No content to send, but we do need a different response code. */
+ NOT_FOUND,
/** Must not respond with content, but otherwise act like normal. */
HEAD,
/** No need to buffer contents before sending. */
@@ -358,7 +347,14 @@
throw new IllegalStateException("Already responded");
}
state = State.NOT_MODIFIED;
- os = new SinkOutputStream();
+ }
+
+ @Override
+ public void respondNotFound() throws IOException {
+ if (state != State.SETUP) {
+ throw new IllegalStateException("Already responded");
+ }
+ state = State.NOT_FOUND;
}
@Override
@@ -374,6 +370,8 @@
return os;
case NOT_MODIFIED:
throw new IllegalStateException("respondNotModified already called");
+ case NOT_FOUND:
+ throw new IllegalStateException("respondNotFound already called");
default:
throw new IllegalStateException("Already responded");
}
@@ -425,6 +423,11 @@
respond(ex, HttpURLConnection.HTTP_NOT_MODIFIED, null, null);
break;
+ case NOT_FOUND:
+ cannedRespond(ex, HttpURLConnection.HTTP_NOT_FOUND, "text/plain",
+ "Unknown document");
+ break;
+
case TRANSFORM:
MaxBufferOutputStream mbos = (MaxBufferOutputStream) os;
byte[] buffer = mbos.getBufferedContent();
@@ -480,12 +483,11 @@
} catch (TransformException e) {
throw new IOException(e);
}
- Set<MetaItem> metadataSet
- = new HashSet<MetaItem>(metadataMap.size() * 2);
+ Metadata.Builder builder = new Metadata.Builder();
for (Map.Entry<String, String> me : metadataMap.entrySet()) {
- metadataSet.add(MetaItem.raw(me.getKey(), me.getValue()));
+ builder.add(MetaItem.raw(me.getKey(), me.getValue()));
}
- metadata = new Metadata(metadataSet);
+ metadata = builder.build();
contentType = params.get("Content-Type");
return contentOut;
}
diff --git a/src/adaptorlib/DocumentTransform.java b/src/adaptorlib/DocumentTransform.java
index de35aad..1289ebf 100644
--- a/src/adaptorlib/DocumentTransform.java
+++ b/src/adaptorlib/DocumentTransform.java
@@ -21,32 +21,33 @@
/**
* Represents an individual transform in the transform pipeline.
- * Subclass this to add your own custom behavior.
+ *
+ * <p>Implementations should also typically have a static factory method with a
+ * single {@code Map<String, String>} argument for creating instances based on
+ * configuration. Implementations are encouraged to accept "name" and
+ * "required" as configuration keys.
*/
-public class DocumentTransform {
-
- public DocumentTransform(String name) {
- this.name = name;
- }
-
+public interface DocumentTransform {
/**
- * Override this function to do the actual data transformation.
- * Read data from the ByteArrayOutputStream instances holding the incoming data,
- * and write them to the OutputStreams. Any changes to the params map will be
- * passed on the subsequent transforms.
+ * Read data from {@code contentIn}, transform it, and write it to {@code
+ * contentOut}. Any changes to {@code metadata} and {@code params} will be
+ * passed on to subsequent transforms. This method must be thread-safe.
*
* @throws TransformException
* @throws IOException
*/
- public void transform(ByteArrayOutputStream contentIn, OutputStream contentOut,
- Map<String, String> metadata, Map<String, String> params)
- throws TransformException, IOException {
- // Defaults to identity transform
- contentIn.writeTo(contentOut);
- }
+ public void transform(ByteArrayOutputStream contentIn,
+ OutputStream contentOut,
+ Map<String, String> metadata,
+ Map<String, String> params)
+ throws TransformException, IOException;
- public void name(String name) { this.name = name; }
- public String name() { return name; }
+ /**
+ * The name of this transform instance, typically provided by the user. It
+ * should not be {@code null}. Using the class name as a default is reasonable
+ * if no name has been provided.
+ */
+ public String getName();
/**
* If this property is true, a failure of this transform will cause the entire
@@ -57,14 +58,5 @@
* If this is false and a error occurs, this transform is treated as a
* identity transform.
*/
- public void errorHaltsPipeline(boolean errorHaltsPipeline) {
- this.errorHaltsPipeline = errorHaltsPipeline;
- }
-
- public boolean errorHaltsPipeline() {
- return errorHaltsPipeline;
- }
-
- private boolean errorHaltsPipeline = true;
- private String name = "";
+ public boolean isRequired();
}
diff --git a/src/adaptorlib/GsaCommunicationHandler.java b/src/adaptorlib/GsaCommunicationHandler.java
index 51e8247..cef5b09 100644
--- a/src/adaptorlib/GsaCommunicationHandler.java
+++ b/src/adaptorlib/GsaCommunicationHandler.java
@@ -26,7 +26,7 @@
import org.opensaml.DefaultBootstrap;
import org.opensaml.xml.ConfigurationException;
-import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.util.*;
import java.util.concurrent.*;
@@ -218,11 +218,20 @@
for (Map<String, String> element : pipelineConfig) {
final String name = element.get("name");
final String confPrefix = "transform.pipeline." + name + ".";
- String className = element.get("class");
- if (className == null) {
+ String factoryMethodName = element.get("factoryMethod");
+ if (factoryMethodName == null) {
throw new RuntimeException(
- "Missing " + confPrefix + "class configuration setting");
+ "Missing " + confPrefix + "factoryMethod configuration setting");
}
+ int sepIndex = factoryMethodName.lastIndexOf(".");
+ if (sepIndex == -1) {
+ throw new RuntimeException("Could not separate method name from class "
+ + "name");
+ }
+ String className = factoryMethodName.substring(0, sepIndex);
+ String methodName = factoryMethodName.substring(sepIndex + 1);
+ log.log(Level.FINE, "Split {0} into class {1} and method {2}",
+ new Object[] {factoryMethodName, className, methodName});
Class<?> klass;
try {
klass = Class.forName(className);
@@ -230,26 +239,26 @@
throw new RuntimeException(
"Could not load class for transform " + name, ex);
}
- Constructor<?> constructor;
+ Method method;
try {
- constructor = klass.getConstructor(Map.class);
+ method = klass.getDeclaredMethod(methodName, Map.class);
} catch (NoSuchMethodException ex) {
- throw new RuntimeException(
- "Could not find constructor for " + className + ". It must have a "
- + "constructor that accepts a Map as the lone parameter.", ex);
+ throw new RuntimeException("Could not find method " + methodName
+ + " on class " + className, ex);
}
+ log.log(Level.FINE, "Found method {0}", new Object[] {method});
Object o;
try {
- o = constructor.newInstance(Collections.unmodifiableMap(element));
+ o = method.invoke(null, Collections.unmodifiableMap(element));
} catch (Exception ex) {
- throw new RuntimeException("Could not instantiate " + className, ex);
+ throw new RuntimeException("Failure while running factory method "
+ + factoryMethodName, ex);
}
if (!(o instanceof DocumentTransform)) {
- throw new RuntimeException(className
+ throw new ClassCastException(o.getClass().getName()
+ " is not an instance of DocumentTransform");
}
DocumentTransform transform = (DocumentTransform) o;
- transform.name(name);
pipeline.add(transform);
}
// If we created an empty pipeline, then we don't need the pipeline at all.
diff --git a/src/adaptorlib/Metadata.java b/src/adaptorlib/Metadata.java
index a2295c0..26fdaab 100644
--- a/src/adaptorlib/Metadata.java
+++ b/src/adaptorlib/Metadata.java
@@ -14,29 +14,22 @@
package adaptorlib;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
+import java.util.*;
/** Represents a fixed set of validated {@link MetaItem}s. */
public final class Metadata implements Iterable<MetaItem> {
/** Empty convenience instance. */
- public static final Metadata EMPTY
- = new Metadata(Collections.<MetaItem>emptySet());
+ public static final Metadata EMPTY = new Metadata.Builder().build();
- private final Set<MetaItem> items;
+ private final Map<String, MetaItem> items;
/**
* Validates that each meta name is unique, there is either
* public-indicator or ACLs and that ACLs values are acceptable.
*/
- public Metadata(Set<MetaItem> allMeta) {
- items = Collections.unmodifiableSet(new TreeSet<MetaItem>(allMeta));
- checkConsistency(items, toMap());
+ private Metadata(Map<String, MetaItem> allMeta) {
+ items = Collections.unmodifiableMap(new TreeMap<String, MetaItem>(allMeta));
+ checkConsistency(items);
}
@Override
@@ -56,12 +49,12 @@
@Override
public Iterator<MetaItem> iterator() {
- return items.iterator();
+ return items.values().iterator();
}
@Override
public String toString() {
- return items.toString();
+ return items.values().toString();
}
public Map<String, String> toMap() {
@@ -80,33 +73,14 @@
return items.size();
}
- private static void checkConsistency(Set<MetaItem> items,
- Map<String, String> allMeta) {
- checkEachNameIsUnique(items);
+ private static void checkConsistency(Map<String, MetaItem> allMeta) {
checkNandPublicAndAcls(allMeta);
- checkBothOrNoneAcls(allMeta);
- checkPublicIsBoolean(allMeta);
- }
-
- /** Each MetaItem name needs be unique. */
- private static void checkEachNameIsUnique(Set<MetaItem> m) {
- HashSet<String> unique = new HashSet<String>();
- HashSet<String> dup = new HashSet<String>();
- for (MetaItem item : m) {
- String name = item.getName();
- if (unique.contains(name)) {
- dup.add(name);
- } else {
- unique.add(name);
- }
- }
- if (0 < dup.size()) {
- throw new IllegalArgumentException("duplicate names: " + dup);
- }
+ checkBothOrNoneAcls(allMeta);
+ checkPublicIsBoolean(allMeta);
}
/** Either have public indicator or ACLs, but not both. */
- private static void checkNandPublicAndAcls(Map<String, String> m) {
+ private static void checkNandPublicAndAcls(Map<String, MetaItem> m) {
boolean hasPublicName = m.containsKey("google:ispublic");
boolean hasAcls = m.containsKey("google:aclusers")
|| m.containsKey("google:aclgroups");
@@ -116,7 +90,7 @@
}
/** Cannot provide users without groups and vice-versa. */
- private static void checkBothOrNoneAcls(Map<String, String> m) {
+ private static void checkBothOrNoneAcls(Map<String, MetaItem> m) {
boolean hasUserAcls = m.containsKey("google:aclusers");
boolean hasGroupAcls = m.containsKey("google:aclgroups");
if (hasUserAcls && !hasGroupAcls) {
@@ -124,8 +98,8 @@
} else if (hasGroupAcls && !hasUserAcls) {
throw new IllegalArgumentException("has groups, but not users");
} else if (hasGroupAcls && hasUserAcls) {
- String userLine = m.get("google:aclusers").trim();
- String groupLine = m.get("google:aclgroups").trim();
+ String userLine = m.get("google:aclusers").getValue().trim();
+ String groupLine = m.get("google:aclgroups").getValue().trim();
if (userLine.isEmpty() && groupLine.isEmpty()) {
throw new IllegalArgumentException("both users and groups empty");
}
@@ -133,12 +107,52 @@
}
/** If has public indicator value is acceptable. */
- private static void checkPublicIsBoolean(Map<String, String> m) {
- String value = m.get("google:ispublic");
- if (null != value) {
+ private static void checkPublicIsBoolean(Map<String, MetaItem> m) {
+ MetaItem item = m.get("google:ispublic");
+ if (null != item) {
+ String value = item.getValue();
if (!"true".equals(value) && !"false".equals(value)) {
throw new IllegalArgumentException("ispublic is not true nor false");
}
}
}
+
+ /**
+ * Builder for instances of {@link Metadata}.
+ */
+ public static class Builder {
+ private Map<String, MetaItem> items = new TreeMap<String, MetaItem>();
+
+ /**
+ * Create new empty builder.
+ */
+ public Builder() {}
+
+ /**
+ * Initialize builder with {@code MetaItems} from {@code iterable}. Useful
+ * to make tweaked copies of {@link Metadata}.
+ */
+ public Builder(Iterable<MetaItem> iterable) {
+ for (MetaItem item : iterable) {
+ items.put(item.getName(), item);
+ }
+ }
+
+ /**
+ * Add a new {@code MetaItem} to the builder, replacing any previously-added
+ * {@code MetaItem} with the same name.
+ */
+ public Builder add(MetaItem item) {
+ items.put(item.getName(), item);
+ return this;
+ }
+
+ /**
+ * Returns a metadata instance that reflects current builder state. It does
+ * not reset the builder.
+ */
+ public Metadata build() {
+ return new Metadata(items);
+ }
+ }
}
diff --git a/src/adaptorlib/Request.java b/src/adaptorlib/Request.java
index 41a20ba..25846fe 100644
--- a/src/adaptorlib/Request.java
+++ b/src/adaptorlib/Request.java
@@ -49,8 +49,8 @@
* Provides the document ID for the document that is being requested. {@code
* DocId} was not necessarily provided previously by the Adaptor; <b>it is
* client-provided and must not be trusted</b>. If the document does not
- * exist, then {@link Adaptor#getDocContent} must throw {@link java.io.
- * FileNotFoundException}.
+ * exist, then {@link Adaptor#getDocContent} must call {@link
+ * Response#respondNotFound}.
*/
public DocId getDocId();
}
diff --git a/src/adaptorlib/Response.java b/src/adaptorlib/Response.java
index e53e469..a671c24 100644
--- a/src/adaptorlib/Response.java
+++ b/src/adaptorlib/Response.java
@@ -18,13 +18,12 @@
/**
* Interface provided to {@link Adaptor#getDocContent} for performing the
- * actions needed to satisfy a request. If the {@code DocId} provided by {@link
- * Request#getDocId} does not exist, a {@link java.io.FileNotFoundException}
- * should be thrown.
+ * actions needed to satisfy a request.
*
* <p>There are several ways that a request can be processed. In the simplest
* case an Adaptor always sets different pieces of metadata, calls {@link
- * #getOutputStream}, and writes the document contents.
+ * #getOutputStream}, and writes the document contents. If the document does not
+ * exist, it should call {@link #respondNotFound} instead.
*
* <p>For improved efficiency during recrawl by the GSA, an Adaptor should check
* {@link Request#hasChangedSinceLastAccess} and call {@link
@@ -37,22 +36,31 @@
* of a file and its metadata. If you have called other methods on this object
* to provide various metadata, the effects of those methods will be ignored.
*
- * <p>If called, this must be the last call to this interface. If the document
- * does not exist, you must throw {@link java.io.FileNotFoundException} and
- * not call this method. Once you call this method, for the rest of the
- * processing, exceptions may no longer be communicated to clients cleanly.
+ * <p>If called, this must be the last call to this interface. Once you call
+ * this method, for the rest of the processing, exceptions may no longer be
+ * communicated to clients cleanly.
*/
public void respondNotModified() throws IOException;
/**
+ * Respond to the GSA or other client that the request document does not
+ * exist. If you have called other methods on this object, the effects of
+ * those methods will be ignored.
+ *
+ * <p>If called, this must be the last call to this interface. Once you call
+ * this method, for the rest of the processing, exceptions may no longer be
+ * communicated to the clients cleanly.
+ */
+ public void respondNotFound() throws IOException;
+
+ /**
* Get stream to write document contents to. There is no need to flush or
* close the {@code OutputStream} when done.
*
* <p>If called, this must be the last call to this interface (although, for
- * convenience, you may call this method multiple times). If the document
- * does not exist, you must throw {@link java.io.FileNotFoundException} and
- * not call this method. Once you call this method, for the rest of the
- * processing, exceptions may no longer be communicated to clients cleanly.
+ * convenience, you may call this method multiple times). Once you call this
+ * method, for the rest of the processing, exceptions may no longer be
+ * communicated to clients cleanly.
*/
public OutputStream getOutputStream() throws IOException;
diff --git a/src/adaptorlib/TransformPipeline.java b/src/adaptorlib/TransformPipeline.java
index aa729ee..af1f8d1 100644
--- a/src/adaptorlib/TransformPipeline.java
+++ b/src/adaptorlib/TransformPipeline.java
@@ -75,12 +75,13 @@
transform.transform(new UnmodifiableWrapperByteArrayOutputStream(contentInTransit),
contentOutTransit, metadataOutTransit, paramsOutTransit);
} catch (TransformException e) {
- if (transform.errorHaltsPipeline()) {
- log.log(Level.WARNING, "Transform Exception. Aborting '" + transform.name() + "'", e);
+ if (transform.isRequired()) {
+ log.log(Level.WARNING, "Transform Exception. Aborting '"
+ + transform.getName() + "'", e);
throw e;
} else {
- log.log(Level.WARNING,
- "Transform Exception. Ignoring transform '" + transform.name() + "'", e);
+ log.log(Level.WARNING, "Transform Exception. Ignoring transform '"
+ + transform.getName() + "'", e);
continue;
}
}
diff --git a/src/adaptorlib/WrapperAdaptor.java b/src/adaptorlib/WrapperAdaptor.java
index b9fe991..3caf30d 100644
--- a/src/adaptorlib/WrapperAdaptor.java
+++ b/src/adaptorlib/WrapperAdaptor.java
@@ -106,6 +106,11 @@
}
@Override
+ public void respondNotFound() throws IOException {
+ response.respondNotFound();
+ }
+
+ @Override
public OutputStream getOutputStream() throws IOException {
return response.getOutputStream();
}
@@ -151,12 +156,14 @@
/**
* Counterpart of {@link GetContentsRequest} that allows easy calling of an
- * {@link Adaptor}. It does not support {@link #respondNotModified}.
+ * {@link Adaptor}. It does not support {@link #respondNotModified}. Be sure
+ * to check {@link #isNotFound()}.
*/
public static class GetContentsResponse implements Response {
private OutputStream os;
private String contentType;
private Metadata metadata;
+ private boolean notFound;
public GetContentsResponse(OutputStream os) {
this.os = os;
@@ -168,6 +175,11 @@
}
@Override
+ public void respondNotFound() {
+ notFound = true;
+ }
+
+ @Override
public OutputStream getOutputStream() {
return os;
}
@@ -189,6 +201,10 @@
public Metadata getMetadata() {
return metadata;
}
+
+ public boolean isNotFound() {
+ return notFound;
+ }
}
/**
diff --git a/src/adaptorlib/examples/AdaptorTemplate.java b/src/adaptorlib/examples/AdaptorTemplate.java
index d3130b4..23c8f10 100644
--- a/src/adaptorlib/examples/AdaptorTemplate.java
+++ b/src/adaptorlib/examples/AdaptorTemplate.java
@@ -51,10 +51,9 @@
} else if ("1002".equals(id.getUniqueId())) {
str = "Document 1002 says hello and banana strawberry";
} else {
- throw new FileNotFoundException(id.getUniqueId());
+ resp.respondNotFound();
+ return;
}
- // Must get the OutputStream after any possibility of throwing a
- // FileNotFoundException.
OutputStream os = resp.getOutputStream();
os.write(str.getBytes(encoding));
}
diff --git a/src/adaptorlib/examples/AdaptorWithCrawlTimeMetadataTemplate.java b/src/adaptorlib/examples/AdaptorWithCrawlTimeMetadataTemplate.java
index ed62362..a03d15e 100644
--- a/src/adaptorlib/examples/AdaptorWithCrawlTimeMetadataTemplate.java
+++ b/src/adaptorlib/examples/AdaptorWithCrawlTimeMetadataTemplate.java
@@ -48,36 +48,33 @@
String str;
if ("1001".equals(id.getUniqueId())) {
str = "Document 1001 says hello and apple orange";
- // Make set to accumulate meta items.
- Set<MetaItem> metaItems = new TreeSet<MetaItem>();
- // Add user ACL.
List<String> users1001 = Arrays.asList("peter", "bart", "simon");
- metaItems.add(MetaItem.permittedUsers(users1001));
- // Add group ACL.
List<String> groups1001 = Arrays.asList("support", "sales");
- metaItems.add(MetaItem.permittedGroups(groups1001));
- // Add custom meta items.
- metaItems.add(MetaItem.raw("my-special-key", "my-custom-value"));
- metaItems.add(MetaItem.raw("date", "not soon enough"));
// Make metadata object, which checks items for consistency.
// Must set metadata before getting OutputStream
- resp.setMetadata(new Metadata(metaItems));
+ resp.setMetadata(new Metadata.Builder()
+ // Add user ACL.
+ .add(MetaItem.permittedUsers(users1001))
+ // Add group ACL.
+ .add(MetaItem.permittedGroups(groups1001))
+ // Add custom meta items.
+ .add(MetaItem.raw("my-special-key", "my-custom-value"))
+ .add(MetaItem.raw("date", "not soon enough"))
+ .build());
} else if ("1002".equals(id.getUniqueId())) {
str = "Document 1002 says hello and banana strawberry";
- // Another example.
- Set<MetaItem> metaItems = new TreeSet<MetaItem>();
- // A document that's not public and has no ACLs causes head requests.
- metaItems.add(MetaItem.isNotPublic());
- // Add custom meta items.
- metaItems.add(MetaItem.raw("date", "better never than late"));
// Make metadata object, which checks items for consistency.
// Must set metadata before getting OutputStream
- resp.setMetadata(new Metadata(metaItems));
+ resp.setMetadata(new Metadata.Builder()
+ // A document that's not public and has no ACLs causes head requests.
+ .add(MetaItem.isNotPublic())
+ // Add custom meta items.
+ .add(MetaItem.raw("date", "better never than late"))
+ .build());
} else {
- throw new FileNotFoundException(id.getUniqueId());
+ resp.respondNotFound();
+ return;
}
- // Must get the OutputStream after any possibility of throwing a
- // FileNotFoundException.
OutputStream os = resp.getOutputStream();
os.write(str.getBytes(encoding));
}
diff --git a/src/adaptorlib/examples/CalaisNERTransform.java b/src/adaptorlib/examples/CalaisNERTransform.java
index b483b93..da2ff01 100644
--- a/src/adaptorlib/examples/CalaisNERTransform.java
+++ b/src/adaptorlib/examples/CalaisNERTransform.java
@@ -14,7 +14,7 @@
package adaptorlib.examples;
-import adaptorlib.DocumentTransform;
+import adaptorlib.AbstractDocumentTransform;
import adaptorlib.TransformException;
import mx.bigdata.jcalais.CalaisClient;
@@ -34,7 +34,7 @@
* extracts named entities. We then inject this info as metadata.
* We currently make the assumption that the incoming content is HTML.
*/
-public class CalaisNERTransform extends DocumentTransform {
+public class CalaisNERTransform extends AbstractDocumentTransform {
interface CalaisClientFactory {
CalaisClient makeClient(String apiKey);
@@ -43,7 +43,6 @@
private final CalaisClientFactory clientFactory;
CalaisNERTransform(CalaisClientFactory factory) {
- super("CalaisNERTransform");
this.clientFactory = factory;
}
@@ -117,4 +116,10 @@
content = content.replaceFirst("</(HEAD|head)", "\n" + sb.toString() + "</HEAD");
contentOut.write(content.getBytes());
}
+
+ public static CalaisNERTransform create(Map<String, String> config) {
+ CalaisNERTransform transform = new CalaisNERTransform();
+ transform.configure(config);
+ return transform;
+ }
}
diff --git a/src/adaptorlib/examples/DbAdaptorTemplate.java b/src/adaptorlib/examples/DbAdaptorTemplate.java
index 554f7b8..15733a7 100644
--- a/src/adaptorlib/examples/DbAdaptorTemplate.java
+++ b/src/adaptorlib/examples/DbAdaptorTemplate.java
@@ -91,7 +91,8 @@
// First handle cases with no data to return.
boolean hasResult = rs.next();
if (!hasResult) {
- throw new FileNotFoundException("no document with id: " + id);
+ resp.respondNotFound();
+ return;
}
ResultSetMetaData rsMetaData = rs.getMetaData();
int numberOfColumns = rsMetaData.getColumnCount();
diff --git a/src/adaptorlib/examples/FileSystemAdaptor.java b/src/adaptorlib/examples/FileSystemAdaptor.java
index 23af277..b06d0d0 100644
--- a/src/adaptorlib/examples/FileSystemAdaptor.java
+++ b/src/adaptorlib/examples/FileSystemAdaptor.java
@@ -77,9 +77,16 @@
// The DocId provided by Request.getDocId() MUST NOT be trusted. Here we
// try to verify that this file is allowed to be served.
if (!isFileDescendantOfServeDir(file)) {
- throw new FileNotFoundException();
+ resp.respondNotFound();
+ return;
}
- InputStream input = new FileInputStream(file);
+ InputStream input;
+ try {
+ input = new FileInputStream(file);
+ } catch (FileNotFoundException ex) {
+ resp.respondNotFound();
+ return;
+ }
try {
IOHelper.copyStream(input, resp.getOutputStream());
} finally {
diff --git a/src/adaptorlib/examples/MetaTaggerTransform.java b/src/adaptorlib/examples/MetaTaggerTransform.java
index 4c9c97a..7f5de6b 100644
--- a/src/adaptorlib/examples/MetaTaggerTransform.java
+++ b/src/adaptorlib/examples/MetaTaggerTransform.java
@@ -14,7 +14,7 @@
package adaptorlib.examples;
-import adaptorlib.DocumentTransform;
+import adaptorlib.AbstractDocumentTransform;
import adaptorlib.TransformException;
import java.io.ByteArrayOutputStream;
@@ -26,7 +26,6 @@
import java.util.Scanner;
import java.util.SortedMap;
import java.util.TreeMap;
-import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
@@ -35,21 +34,13 @@
* the associated metadata is inserted at the end of the HEAD section of the
* HTML. If no HEAD section exists, nothing gets inserted.
*/
-public class MetaTaggerTransform extends DocumentTransform {
+public class MetaTaggerTransform extends AbstractDocumentTransform {
private static final Logger log = Logger.getLogger(MetaTaggerTransform.class.getName());
- public MetaTaggerTransform() {
- super("MetaTaggerTransform");
- }
+ public MetaTaggerTransform() {}
- public MetaTaggerTransform(String patternFile) {
- super("MetaTaggerTransform");
- try {
- loadPatternFile(patternFile);
- } catch (IOException ex) {
- log.log(Level.SEVERE, "MetaTaggerTransform encountered an error while " +
- "loading pattern file: " + patternFile, ex);
- }
+ public MetaTaggerTransform(String patternFile) throws IOException {
+ loadPatternFile(patternFile);
}
@Override
@@ -111,4 +102,17 @@
return p1.toString().equals(p2.toString());
}
}
+
+ public static MetaTaggerTransform create(Map<String, String> config)
+ throws IOException {
+ String patternFile = config.get("patternFile");
+ MetaTaggerTransform transform;
+ if (patternFile == null) {
+ transform = new MetaTaggerTransform();
+ } else {
+ transform = new MetaTaggerTransform(patternFile);
+ }
+ transform.configure(config);
+ return transform;
+ }
}
diff --git a/src/adaptorlib/examples/TableGeneratorTransform.java b/src/adaptorlib/examples/TableGeneratorTransform.java
index 15c02d2..86682c0 100644
--- a/src/adaptorlib/examples/TableGeneratorTransform.java
+++ b/src/adaptorlib/examples/TableGeneratorTransform.java
@@ -14,7 +14,7 @@
package adaptorlib.examples;
-import adaptorlib.DocumentTransform;
+import adaptorlib.AbstractDocumentTransform;
import adaptorlib.TransformException;
import au.com.bytecode.opencsv.CSVReader;
@@ -30,7 +30,6 @@
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;
-import java.util.logging.Level;
import java.util.logging.Logger;
/**
@@ -39,21 +38,13 @@
* In the template HTML file, place <code>&#0;</code> where you'd like the table
* to be inserted.
*/
-public class TableGeneratorTransform extends DocumentTransform {
+public class TableGeneratorTransform extends AbstractDocumentTransform {
private static final Logger log = Logger.getLogger(TableGeneratorTransform.class.getName());
- public TableGeneratorTransform() {
- super("TableGeneratorTransform");
- }
+ public TableGeneratorTransform() {}
- public TableGeneratorTransform(String templateFile) {
- super("TableGeneratorTransform");
- try {
- loadTemplateFile(templateFile);
- } catch (IOException e) {
- log.log(Level.WARNING, "TableGeneratorTransform could not load templateFile: " +
- templateFile, e);
- }
+ public TableGeneratorTransform(String templateFile) throws IOException {
+ loadTemplateFile(templateFile);
}
@Override
@@ -98,4 +89,17 @@
* the escaped null character, because it is explicitly disallowed in HTML.
*/
private static final String SIGIL = "�";
+
+ public static TableGeneratorTransform create(Map<String, String> config)
+ throws IOException {
+ String templateFile = config.get("templateFile");
+ TableGeneratorTransform transform;
+ if (templateFile == null) {
+ transform = new TableGeneratorTransform();
+ } else {
+ transform = new TableGeneratorTransform(templateFile);
+ }
+ transform.configure(config);
+ return transform;
+ }
}
diff --git a/src/adaptorlib/prebuilt/CommandLineAdaptor.java b/src/adaptorlib/prebuilt/CommandLineAdaptor.java
index 61cba07..73662ad 100644
--- a/src/adaptorlib/prebuilt/CommandLineAdaptor.java
+++ b/src/adaptorlib/prebuilt/CommandLineAdaptor.java
@@ -22,10 +22,8 @@
import adaptorlib.Response;
import java.io.ByteArrayInputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.Charset;
-import java.util.ArrayList;
import java.util.Date;
import java.util.logging.Logger;
@@ -96,9 +94,8 @@
+ "document " + retrieverInfo.getDocId() + ".");
}
if (retrieverInfo.notFound()) {
- throw new FileNotFoundException("Could not find file '" + retrieverInfo.getDocId());
- }
- else if (retrieverInfo.isUpToDate()) {
+ resp.respondNotFound();
+ } else if (retrieverInfo.isUpToDate()) {
log.finest("Retriever: " + id.getUniqueId() + " is up to date.");
resp.respondNotModified();
@@ -107,12 +104,12 @@
log.finest("Retriever: " + id.getUniqueId() + " has mime-type "
+ retrieverInfo.getMimeType());
resp.setContentType(retrieverInfo.getMimeType());
- };
+ }
if (retrieverInfo.getMetadata() != null) {
log.finest("Retriever: " + id.getUniqueId() + " has metadata "
+ retrieverInfo.getMetadata());
resp.setMetadata(retrieverInfo.getMetadata());
- };
+ }
if (retrieverInfo.getContents() != null) {
resp.getOutputStream().write(retrieverInfo.getContents());
} else {
diff --git a/src/adaptorlib/prebuilt/CommandLineTransform.java b/src/adaptorlib/prebuilt/CommandLineTransform.java
index ee1c22a..9797b85 100644
--- a/src/adaptorlib/prebuilt/CommandLineTransform.java
+++ b/src/adaptorlib/prebuilt/CommandLineTransform.java
@@ -14,7 +14,7 @@
package adaptorlib.prebuilt;
-import adaptorlib.DocumentTransform;
+import adaptorlib.AbstractDocumentTransform;
import adaptorlib.IOHelper;
import adaptorlib.TransformException;
@@ -27,47 +27,61 @@
* A conduit that allows a simple way to create a document transform based on
* a command line program.
*/
-public class CommandLineTransform extends DocumentTransform {
+public class CommandLineTransform extends AbstractDocumentTransform {
private static final Logger log
= Logger.getLogger(CommandLineTransform.class.getName());
private static final int STDERR_BUFFER_SIZE = 51200; // 50 kB
private final Charset charset = Charset.forName("UTF-8");
+ private boolean commandAcceptsParameters = true;
+ private List<String> transformCommand;
+ private File workingDirectory;
- public CommandLineTransform(String name) {
- super(name);
- }
+ public CommandLineTransform() {}
- public CommandLineTransform(Map<String, String> config) {
- super("CommandLineTransform");
- List<String> cmd = new ArrayList<String>();
- for (Map.Entry<String, String> me : config.entrySet()) {
- String key = me.getKey();
- String value = me.getValue();
- if ("cmd".equals(key)) {
- cmd.add(value);
- } else if ("workingDirectory".equals(key)) {
- workingDirectory(new File(value));
- } else if ("errorHaltsPipeline".equals(key)) {
- errorHaltsPipeline(Boolean.parseBoolean(value));
- }
+ /**
+ * Accepts keys {@code "cmd"}, {@code "workingDirectory"}, {@code "arg?"}, and
+ * any keys accepted by the super class. The {@code "arg?"} configuration
+ * values should be numerically increasing starting from one: {@code "arg1"},
+ * {@code "arg2"}, {@code "arg3}, ...
+ */
+ protected void configure(Map<String, String> config) {
+ super.configure(config);
+
+ List<String> cmdList = new ArrayList<String>();
+ String cmd = config.get("cmd");
+ if (cmd != null) {
+ cmdList.add(cmd);
+ } else {
+ throw new RuntimeException("'cmd' not defined in configuration");
}
- if (cmd.size() == 0) {
- throw new RuntimeException("cmd configuration property must be set");
+
+ String workingDirectory = config.get("workingDirectory");
+ if (workingDirectory != null) {
+ setWorkingDirectory(new File(workingDirectory));
}
+
+ String cmdAcceptsParameters = config.get("cmdAcceptsParameters");
+ if (cmdAcceptsParameters != null) {
+ this.commandAcceptsParameters
+ = Boolean.parseBoolean(cmdAcceptsParameters);
+ }
+
for (int i = 1;; i++) {
String value = config.get("arg" + i);
if (value == null) {
break;
}
- cmd.add(value);
+ cmdList.add(value);
}
- transformCommand = cmd;
+ transformCommand = cmdList;
}
@Override
- public void transform(ByteArrayOutputStream contentIn, OutputStream contentOut,
- Map<String, String> metadata, Map<String, String> params)
+ public void transform(ByteArrayOutputStream contentIn,
+ OutputStream contentOut,
+ Map<String, String> metadata,
+ Map<String, String> params)
throws TransformException, IOException {
if (transformCommand == null) {
throw new NullPointerException("transformCommand must not be null");
@@ -100,7 +114,8 @@
// Handle stderr
if (exitCode != 0) {
String errorOutput = new String(command.getStderr(), charset);
- throw new TransformException("Exit code " + exitCode + ". Stderr: " + errorOutput);
+ throw new TransformException("Exit code " + exitCode + ". Stderr: "
+ + errorOutput);
}
if (command.getStderr().length > 0) {
@@ -125,15 +140,17 @@
}
}
- private File writeMapToTempFile(Map<String, String> map) throws IOException, TransformException {
+ private File writeMapToTempFile(Map<String, String> map)
+ throws IOException, TransformException {
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> me : map.entrySet()) {
if (me.getKey().contains("\0")) {
- throw new TransformException("Key cannot contain the null character: " + me.getKey());
+ throw new TransformException("Key cannot contain the null character: "
+ + me.getKey());
}
if (me.getValue().contains("\0")) {
- throw new TransformException("Value for key '" + me.getKey() + "' cannot contain the null "
- + "character: " + me.getKey());
+ throw new TransformException("Value for key '" + me.getKey()
+ + "' cannot contain the null " + "character: " + me.getKey());
}
sb.append(me.getKey()).append('\0');
sb.append(me.getValue()).append('\0');
@@ -163,11 +180,11 @@
* along to the actual call to the command. This is useful in the case where a
* binary might return erros when unexpected command line flags are passed in.
*/
- public void commandAcceptsParameters(boolean commandAcceptsParameters) {
+ public void setCommandAcceptsParameters(boolean commandAcceptsParameters) {
this.commandAcceptsParameters = commandAcceptsParameters;
}
- public boolean commandAcceptsParameters() {
+ public boolean getCommandAcceptsParameters() {
return commandAcceptsParameters;
}
@@ -179,11 +196,11 @@
* Errors should be printed to stderr. If anything is printed to stderr, it
* will cause a failure for this transform operation.
*/
- public void transformCommand(List<String> transformCommand) {
+ public void setTransformCommand(List<String> transformCommand) {
this.transformCommand = new ArrayList<String>(transformCommand);
}
- public List<String> transformCommand() {
+ public List<String> getTransformCommand() {
return Collections.unmodifiableList(transformCommand);
}
@@ -192,7 +209,7 @@
*
* @throws IllegalArgumentException if {@code dir} is not a directory
*/
- public void workingDirectory(File dir) {
+ public void setWorkingDirectory(File dir) {
if (!dir.isDirectory()) {
throw new IllegalArgumentException("File must be a directory");
}
@@ -202,11 +219,23 @@
/**
* @return The working directory for the command line process.
*/
- public File workingDirectory() {
+ public File getWorkingDirectory() {
return workingDirectory;
}
- private boolean commandAcceptsParameters = true;
- private List<String> transformCommand;
- private File workingDirectory;
+ @Override
+ public void setName(String name) {
+ super.setName(name);
+ }
+
+ @Override
+ public void setRequired(boolean required) {
+ super.setRequired(required);
+ }
+
+ public static CommandLineTransform create(Map<String, String> config) {
+ CommandLineTransform transform = new CommandLineTransform();
+ transform.configure(config);
+ return transform;
+ }
}
diff --git a/src/adaptorlib/prebuilt/FileSystemAdaptor.java b/src/adaptorlib/prebuilt/FileSystemAdaptor.java
index 659299d..4a0c5c8 100644
--- a/src/adaptorlib/prebuilt/FileSystemAdaptor.java
+++ b/src/adaptorlib/prebuilt/FileSystemAdaptor.java
@@ -99,13 +99,20 @@
File file = new File(serveDir, id.getUniqueId()).getCanonicalFile();
if (!file.exists() || !isFileDescendantOfServeDir(file)
|| !isFileAllowed(file)) {
- throw new FileNotFoundException();
+ resp.respondNotFound();
+ return;
}
if (!req.hasChangedSinceLastAccess(new Date(file.lastModified()))) {
resp.respondNotModified();
return;
}
- InputStream input = new FileInputStream(file);
+ InputStream input;
+ try {
+ input = new FileInputStream(file);
+ } catch (FileNotFoundException ex) {
+ resp.respondNotFound();
+ return;
+ }
try {
IOHelper.copyStream(input, resp.getOutputStream());
} finally {
diff --git a/test/adaptorlib/AutoUnzipAdaptorTest.java b/test/adaptorlib/AutoUnzipAdaptorTest.java
index 47b885d..83eac4f 100644
--- a/test/adaptorlib/AutoUnzipAdaptorTest.java
+++ b/test/adaptorlib/AutoUnzipAdaptorTest.java
@@ -114,7 +114,8 @@
public void getDocContent(Request req, Response resp) throws IOException {
DocId docId = req.getDocId();
if (!"!test.zip".equals(docId.getUniqueId())) {
- throw new FileNotFoundException(docId.getUniqueId());
+ resp.respondNotFound();
+ return;
}
ZipOutputStream zos = new ZipOutputStream(resp.getOutputStream());
for (String entry : original) {
diff --git a/test/adaptorlib/DocumentHandlerTest.java b/test/adaptorlib/DocumentHandlerTest.java
index e1d4b8e..1f70f9c 100644
--- a/test/adaptorlib/DocumentHandlerTest.java
+++ b/test/adaptorlib/DocumentHandlerTest.java
@@ -226,7 +226,7 @@
final byte[] golden = new byte[] {2, 3, 4};
final String key = "testing key";
TransformPipeline transform = new TransformPipeline();
- transform.add(new DocumentTransform("testing") {
+ transform.add(new AbstractDocumentTransform() {
@Override
public void transform(ByteArrayOutputStream contentIn,
OutputStream contentOut,
@@ -242,9 +242,8 @@
@Override
public void getDocContent(Request request, Response response)
throws IOException {
- Set<MetaItem> metaSet = new HashSet<MetaItem>();
- metaSet.add(MetaItem.raw(key, "testing value"));
- response.setMetadata(new Metadata(metaSet));
+ response.setMetadata(new Metadata.Builder()
+ .add(MetaItem.raw(key, "testing value")).build());
super.getDocContent(request, response);
}
};
@@ -266,7 +265,7 @@
@Test
public void testTransformDocumentTooLarge() throws Exception {
TransformPipeline transform = new TransformPipeline();
- transform.add(new DocumentTransform("testing") {
+ transform.add(new AbstractDocumentTransform() {
@Override
public void transform(ByteArrayOutputStream contentIn,
OutputStream contentOut,
@@ -349,7 +348,7 @@
@Override
public void getDocContent(Request request, Response response)
throws IOException {
- throw new FileNotFoundException();
+ response.respondNotFound();
}
};
DocumentHandler handler = createDefaultHandlerForAdaptor(adaptor);
@@ -494,7 +493,8 @@
public void getDocContent(Request request, Response response)
throws IOException {
if (!request.getDocId().equals(new DocId("http://localhost/"))) {
- throw new FileNotFoundException();
+ response.respondNotFound();
+ return;
}
if (!request.hasChangedSinceLastAccess(new Date(1 * 1000))) {
response.respondNotModified();
@@ -535,8 +535,8 @@
@Override
public void getDocContent(Request request, Response response)
throws IOException {
- response.setMetadata(new Metadata(Collections.singleton(
- MetaItem.raw("test", "ing"))));
+ response.setMetadata(new Metadata.Builder()
+ .add(MetaItem.raw("test", "ing")).build());
response.getOutputStream();
}
};
@@ -559,20 +559,19 @@
@Test
public void testFormMetadataHeader() {
- Set<MetaItem> items = new HashSet<MetaItem>();
- items.add(MetaItem.isPublic());
- items.add(MetaItem.raw("test", "ing"));
- items.add(MetaItem.raw("another", "item"));
- items.add(MetaItem.raw("equals=", "=="));
- String result = DocumentHandler.formMetadataHeader(new Metadata(items));
+ String result = DocumentHandler.formMetadataHeader(new Metadata.Builder()
+ .add(MetaItem.isPublic())
+ .add(MetaItem.raw("test", "ing"))
+ .add(MetaItem.raw("another", "item"))
+ .add(MetaItem.raw("equals=", "=="))
+ .build());
assertEquals("another=item,equals%3D=%3D%3D,google%3Aispublic=true,"
+ "test=ing", result);
}
@Test
public void testFormMetadataHeaderEmpty() {
- String header = DocumentHandler.formMetadataHeader(
- new Metadata(new HashSet<MetaItem>()));
+ String header = DocumentHandler.formMetadataHeader(Metadata.EMPTY);
assertEquals("", header);
}
diff --git a/test/adaptorlib/GsaCommunicationHandlerTest.java b/test/adaptorlib/GsaCommunicationHandlerTest.java
index 2d8958d..1255363 100644
--- a/test/adaptorlib/GsaCommunicationHandlerTest.java
+++ b/test/adaptorlib/GsaCommunicationHandlerTest.java
@@ -19,6 +19,7 @@
import org.junit.*;
import org.junit.rules.ExpectedException;
+import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;
@@ -104,14 +105,14 @@
{
Map<String, String> map = new HashMap<String, String>();
map.put("name", "testing");
- map.put("class", InstantiatableTransform.class.getName());
+ map.put("factoryMethod", getClass().getName() + ".factoryMethod");
config.add(map);
}
TransformPipeline pipeline
= GsaCommunicationHandler.createTransformPipeline(config);
assertEquals(1, pipeline.size());
- assertEquals(InstantiatableTransform.class, pipeline.get(0).getClass());
- assertEquals("testing", pipeline.get(0).name());
+ assertEquals(IdentityTransform.class, pipeline.get(0).getClass());
+ assertEquals("testing", pipeline.get(0).getName());
}
@Test
@@ -139,7 +140,7 @@
{
Map<String, String> map = new HashMap<String, String>();
map.put("name", "testing");
- map.put("class", "adaptorlib.NotARealClass");
+ map.put("factoryMethod", "adaptorlib.NotARealClass.fakeMethod");
config.add(map);
}
thrown.expect(RuntimeException.class);
@@ -153,7 +154,7 @@
{
Map<String, String> map = new HashMap<String, String>();
map.put("name", "testing");
- map.put("class", WrongConstructorTransform.class.getName());
+ map.put("factoryMethod", getClass().getName() + ".wrongFactoryMethod");
config.add(map);
}
thrown.expect(RuntimeException.class);
@@ -167,7 +168,8 @@
{
Map<String, String> map = new HashMap<String, String>();
map.put("name", "testing");
- map.put("class", CantInstantiateTransform.class.getName());
+ map.put("factoryMethod",
+ getClass().getName() + ".cantInstantiateFactoryMethod");
config.add(map);
}
thrown.expect(RuntimeException.class);
@@ -181,7 +183,22 @@
{
Map<String, String> map = new HashMap<String, String>();
map.put("name", "testing");
- map.put("class", WrongTypeTransform.class.getName());
+ map.put("factoryMethod",
+ getClass().getName() + ".wrongTypeFactoryMethod");
+ config.add(map);
+ }
+ thrown.expect(ClassCastException.class);
+ TransformPipeline pipeline
+ = GsaCommunicationHandler.createTransformPipeline(config);
+ }
+
+ @Test
+ public void testCreateTransformPipelineNoMethod() throws Exception {
+ List<Map<String, String>> config = new ArrayList<Map<String, String>>();
+ {
+ Map<String, String> map = new HashMap<String, String>();
+ map.put("name", "testing");
+ map.put("factoryMethod", "noFactoryMethodToBeFound");
config.add(map);
}
thrown.expect(RuntimeException.class);
@@ -213,26 +230,32 @@
}
}
- static class InstantiatableTransform extends DocumentTransform {
- public InstantiatableTransform(Map<String, String> config) {
- super("Test");
+ static class IdentityTransform extends AbstractDocumentTransform {
+ @Override
+ public void transform(ByteArrayOutputStream contentIn,
+ OutputStream contentOut,
+ Map<String, String> metadata,
+ Map<String, String> params) throws IOException {
+ contentIn.writeTo(contentOut);
}
}
- static class WrongConstructorTransform extends DocumentTransform {
- public WrongConstructorTransform() {
- super("Test");
- }
+ public static IdentityTransform factoryMethod(Map<String, String> config) {
+ IdentityTransform transform = new IdentityTransform();
+ transform.configure(config);
+ return transform;
}
- static class CantInstantiateTransform extends DocumentTransform {
- public CantInstantiateTransform(Map<String, String> config) {
- super("Test");
- throw new RuntimeException("This always seems to happen");
- }
+ public static IdentityTransform wrongFactoryMethod() {
+ return factoryMethod(Collections.<String, String>emptyMap());
}
- static class WrongTypeTransform {
- public WrongTypeTransform(Map<String, String> config) {}
+ public static IdentityTransform cantInstantiateFactoryMethod(
+ Map<String, String> config) {
+ throw new RuntimeException("This always seems to happen");
+ }
+
+ public static Object wrongTypeFactoryMethod(Map<String, String> config) {
+ return new Object();
}
}
diff --git a/test/adaptorlib/MetadataTest.java b/test/adaptorlib/MetadataTest.java
index edb25e5..fc0e817 100644
--- a/test/adaptorlib/MetadataTest.java
+++ b/test/adaptorlib/MetadataTest.java
@@ -19,24 +19,22 @@
import org.junit.*;
import org.junit.rules.ExpectedException;
-import java.util.Set;
-import java.util.TreeSet;
-
/** Tests for {@link MetaItem}. */
public class MetadataTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
- private Metadata couple = new Metadata(makeCouple());
- private Metadata coupleB = new Metadata(makeCouple());
- private Metadata triple = new Metadata(makeTriple());
- private Metadata tripleB = new Metadata(makeTriple());
+ private Metadata couple = makeCouple();
+ private Metadata coupleB = makeCouple();
+ private Metadata triple = makeTriple();
+ private Metadata tripleB = makeTriple();
@Test
public void testEquals() {
assertEquals(couple, coupleB);
+ assertEquals(couple, new Metadata.Builder(couple).build());
assertEquals(triple, tripleB);
- assertEquals(Metadata.EMPTY, new Metadata(new TreeSet<MetaItem>()));
+ assertEquals(Metadata.EMPTY, new Metadata.Builder().build());
assertFalse(couple.equals(triple));
assertFalse(triple.equals(couple));
assertFalse(Metadata.EMPTY.equals(new Object()));
@@ -63,91 +61,82 @@
}
@Test
- public void testEachNameUnique() {
- Set<MetaItem> items = new TreeSet<MetaItem>();
- items.add(MetaItem.raw("a", "barney"));
- items.add(MetaItem.raw("a", "frank"));
- thrown.expect(IllegalArgumentException.class);
- Metadata box = new Metadata(items);
- }
-
- @Test
public void testWithPublicAndWithAcls() {
- Set<MetaItem> items = new TreeSet<MetaItem>();
- items.add(MetaItem.raw("google:aclusers", "peter,mathew"));
- items.add(MetaItem.raw("google:aclgroups", "apostles"));
- items.add(MetaItem.raw("google:ispublic", "true"));
+ Metadata.Builder builder = new Metadata.Builder()
+ .add(MetaItem.raw("google:aclusers", "peter,mathew"))
+ .add(MetaItem.raw("google:aclgroups", "apostles"))
+ .add(MetaItem.raw("google:ispublic", "true"));
thrown.expect(IllegalArgumentException.class);
- Metadata box = new Metadata(items);
+ Metadata box = builder.build();
}
@Test
public void testNoPublicNoAcls() {
- Set<MetaItem> items = new TreeSet<MetaItem>();
- items.add(MetaItem.raw("X", "peter,mathew"));
- items.add(MetaItem.raw("Y", "apostles"));
- items.add(MetaItem.raw("Z", "true"));
- Metadata box = new Metadata(items);
+ Metadata box = new Metadata.Builder()
+ .add(MetaItem.raw("X", "peter,mathew"))
+ .add(MetaItem.raw("Y", "apostles"))
+ .add(MetaItem.raw("Z", "true"))
+ .build();
}
@Test
public void testNoPublicWithAcls() {
- Set<MetaItem> items = new TreeSet<MetaItem>();
- items.add(MetaItem.raw("google:aclusers", "peter,mathew"));
- items.add(MetaItem.raw("google:aclgroups", "apostles"));
- items.add(MetaItem.raw("Z", "true"));
- Metadata box = new Metadata(items);
+ Metadata box = new Metadata.Builder()
+ .add(MetaItem.raw("google:aclusers", "peter,mathew"))
+ .add(MetaItem.raw("google:aclgroups", "apostles"))
+ .add(MetaItem.raw("Z", "true"))
+ .build();
}
@Test
public void testWithPublicNoAcls() {
- Set<MetaItem> items = new TreeSet<MetaItem>();
- items.add(MetaItem.raw("X", "peter,mathew"));
- items.add(MetaItem.raw("Y", "apostles"));
- items.add(MetaItem.raw("google:ispublic", "true"));
- Metadata box = new Metadata(items);
+ Metadata box = new Metadata.Builder()
+ .add(MetaItem.raw("X", "peter,mathew"))
+ .add(MetaItem.raw("Y", "apostles"))
+ .add(MetaItem.raw("google:ispublic", "true"))
+ .build();
}
@Test
public void testWithUsersNoGroups() {
- Set<MetaItem> items = new TreeSet<MetaItem>();
- items.add(MetaItem.raw("google:aclusers", "peter,mathew"));
- items.add(MetaItem.raw("Y", "apostles"));
- items.add(MetaItem.raw("Z", "true"));
+ Metadata.Builder builder = new Metadata.Builder()
+ .add(MetaItem.raw("google:aclusers", "peter,mathew"))
+ .add(MetaItem.raw("Y", "apostles"))
+ .add(MetaItem.raw("Z", "true"));
thrown.expect(IllegalArgumentException.class);
- Metadata box = new Metadata(items);
+ Metadata box = builder.build();
}
@Test
public void testNoUsersWithGroups() {
- Set<MetaItem> items = new TreeSet<MetaItem>();
- items.add(MetaItem.raw("X", "peter,mathew"));
- items.add(MetaItem.raw("google:aclgroups", "apostles"));
- items.add(MetaItem.raw("Z", "true"));
+ Metadata.Builder builder = new Metadata.Builder()
+ .add(MetaItem.raw("X", "peter,mathew"))
+ .add(MetaItem.raw("google:aclgroups", "apostles"))
+ .add(MetaItem.raw("Z", "true"));
thrown.expect(IllegalArgumentException.class);
- Metadata box = new Metadata(items);
+ Metadata box = builder.build();
}
@Test
public void testPublicCanBeTrue() {
- Set<MetaItem> items = new TreeSet<MetaItem>();
- items.add(MetaItem.raw("google:ispublic", "true"));
- Metadata box = new Metadata(items);
+ Metadata box = new Metadata.Builder()
+ .add(MetaItem.raw("google:ispublic", "true"))
+ .build();
}
@Test
public void testPublicCanBeFalse() {
- Set<MetaItem> items = new TreeSet<MetaItem>();
- items.add(MetaItem.raw("google:ispublic", "false"));
- Metadata box = new Metadata(items);
+ Metadata box = new Metadata.Builder()
+ .add(MetaItem.raw("google:ispublic", "false"))
+ .build();
}
@Test
public void testPublicMustBeBoolean() {
- Set<MetaItem> items = new TreeSet<MetaItem>();
- items.add(MetaItem.raw("google:ispublic", "dog"));
+ Metadata.Builder builder = new Metadata.Builder()
+ .add(MetaItem.raw("google:ispublic", "dog"));
thrown.expect(IllegalArgumentException.class);
- Metadata box = new Metadata(items);
+ Metadata box = builder.build();
}
@Test
@@ -161,18 +150,18 @@
assertEquals(true, Metadata.EMPTY.isEmpty());
}
- private static Set<MetaItem> makeCouple() {
- Set<MetaItem> coupleItems = new TreeSet<MetaItem>();
- coupleItems.add(MetaItem.raw("google:ispublic", "true"));
- coupleItems.add(MetaItem.raw("author", "iceman"));
- return coupleItems;
+ private static Metadata makeCouple() {
+ return new Metadata.Builder()
+ .add(MetaItem.raw("google:ispublic", "true"))
+ .add(MetaItem.raw("author", "iceman"))
+ .build();
}
- private static Set<MetaItem> makeTriple() {
- Set<MetaItem> tripleItems = new TreeSet<MetaItem>();
- tripleItems.add(MetaItem.raw("google:aclusers", "peter,mathew"));
- tripleItems.add(MetaItem.raw("google:aclgroups", "apostles"));
- tripleItems.add(MetaItem.raw("where", "there"));
- return tripleItems;
+ private static Metadata makeTriple() {
+ return new Metadata.Builder()
+ .add(MetaItem.raw("google:aclusers", "peter,mathew"))
+ .add(MetaItem.raw("google:aclgroups", "apostles"))
+ .add(MetaItem.raw("where", "there"))
+ .build();
}
}
diff --git a/test/adaptorlib/TestHelper.java b/test/adaptorlib/TestHelper.java
index b97785a..9438f7b 100644
--- a/test/adaptorlib/TestHelper.java
+++ b/test/adaptorlib/TestHelper.java
@@ -16,8 +16,7 @@
import static org.junit.Assume.*;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
+import java.io.*;
import java.util.List;
/**
@@ -56,8 +55,12 @@
public static byte[] getDocContent(Adaptor adaptor, DocId docId) throws IOException,
InterruptedException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
- adaptor.getDocContent(new WrapperAdaptor.GetContentsRequest(docId),
- new WrapperAdaptor.GetContentsResponse(baos));
+ WrapperAdaptor.GetContentsResponse resp
+ = new WrapperAdaptor.GetContentsResponse(baos);
+ adaptor.getDocContent(new WrapperAdaptor.GetContentsRequest(docId), resp);
+ if (resp.isNotFound()) {
+ throw new FileNotFoundException("Could not find " + docId);
+ }
return baos.toByteArray();
}
diff --git a/test/adaptorlib/TransformPipelineTest.java b/test/adaptorlib/TransformPipelineTest.java
index eca603f..c6f56ee 100644
--- a/test/adaptorlib/TransformPipelineTest.java
+++ b/test/adaptorlib/TransformPipelineTest.java
@@ -68,7 +68,7 @@
params.put("key2", "value2");
TransformPipeline pipeline = new TransformPipeline();
- pipeline.add(new DocumentTransform("Metadata/Param Transform") {
+ pipeline.add(new AbstractDocumentTransform() {
@Override
public void transform(ByteArrayOutputStream cIn, OutputStream cOut, Map<String, String> m,
Map<String, String> p) throws TransformException, IOException {
@@ -125,8 +125,7 @@
public void testNotLastTransformError() throws IOException, TransformException {
TransformPipeline pipeline = new TransformPipeline();
pipeline.add(new IncrementTransform());
- pipeline.add(new ErroringTransform());
- pipeline.get(1).errorHaltsPipeline(false);
+ pipeline.add(new ErroringTransform(false));
ByteArrayOutputStream out = new ByteArrayOutputStream();
Map<String, String> metadata = new HashMap<String, String>();
metadata.put("int", "0");
@@ -143,8 +142,7 @@
@Test
public void testLastTransformError() throws IOException, TransformException {
TransformPipeline pipeline = new TransformPipeline();
- pipeline.add(new ErroringTransform());
- pipeline.get(0).errorHaltsPipeline(false);
+ pipeline.add(new ErroringTransform(false));
pipeline.add(new IncrementTransform());
ByteArrayOutputStream out = new ByteArrayOutputStream();
Map<String, String> metadata = new HashMap<String, String>();
@@ -163,8 +161,7 @@
public void testTransformErrorFatal() throws IOException, TransformException {
TransformPipeline pipeline = new TransformPipeline();
pipeline.add(new IncrementTransform());
- pipeline.add(new ErroringTransform());
- pipeline.get(1).errorHaltsPipeline(true);
+ pipeline.add(new ErroringTransform(true));
ByteArrayOutputStream out = new ByteArrayOutputStream();
Map<String, String> metadata = new HashMap<String, String>();
metadata.put("int", "0");
@@ -181,11 +178,7 @@
}
}
- private static class IncrementTransform extends DocumentTransform {
- public IncrementTransform() {
- super("incrementTransform");
- }
-
+ private static class IncrementTransform extends AbstractDocumentTransform {
@Override
public void transform(ByteArrayOutputStream contentIn, OutputStream contentOut,
Map<String, String> metadata, Map<String, String> p)
@@ -200,11 +193,10 @@
}
}
- private static class ProductTransform extends DocumentTransform {
+ private static class ProductTransform extends AbstractDocumentTransform {
private int factor;
public ProductTransform(int factor) {
- super("productTransform");
this.factor = factor;
}
@@ -222,9 +214,9 @@
}
}
- private static class ErroringTransform extends DocumentTransform {
- public ErroringTransform() {
- super("erroringTransform");
+ private static class ErroringTransform extends AbstractDocumentTransform {
+ public ErroringTransform(boolean required) {
+ super(null, required);
}
@Override
diff --git a/test/adaptorlib/prebuilt/CommandLineAdaptorTest.java b/test/adaptorlib/prebuilt/CommandLineAdaptorTest.java
index bde4961..d8fa8d0 100644
--- a/test/adaptorlib/prebuilt/CommandLineAdaptorTest.java
+++ b/test/adaptorlib/prebuilt/CommandLineAdaptorTest.java
@@ -14,13 +14,13 @@
package adaptorlib.prebuilt;
+import static adaptorlib.TestHelper.getDocIds;
+
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import adaptorlib.*;
-import static adaptorlib.TestHelper.getDocIds;
-
import org.junit.Test;
import java.io.ByteArrayOutputStream;
@@ -31,10 +31,8 @@
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Set;
/**
* Tests for {@link CommandLineAdaptor}.
@@ -99,13 +97,13 @@
ID_TO_LAST_CRAWLED = Collections.unmodifiableMap(idToLastCrawled);
Map<String, Metadata> idToMetadata = new HashMap<String, Metadata>();
- Set<MetaItem> metadataSet1002 = new HashSet<MetaItem>();
- metadataSet1002.add(MetaItem.raw("metaname-1002a", "metavalue-1002a"));
- metadataSet1002.add(MetaItem.raw("metaname-1002b", "metavalue-1002b"));
- idToMetadata.put("1002", new adaptorlib.Metadata(metadataSet1002));
- Set<MetaItem> metadataSet1003 = new HashSet<MetaItem>();
- metadataSet1003.add(MetaItem.raw("metaname-1003", "metavalue-1003"));
- idToMetadata.put("1003", new adaptorlib.Metadata(metadataSet1003));
+ idToMetadata.put("1002", new Metadata.Builder()
+ .add(MetaItem.raw("metaname-1002a", "metavalue-1002a"))
+ .add(MetaItem.raw("metaname-1002b", "metavalue-1002b"))
+ .build());
+ idToMetadata.put("1003", new Metadata.Builder()
+ .add(MetaItem.raw("metaname-1003", "metavalue-1003"))
+ .build());
ID_TO_METADATA = Collections.unmodifiableMap(idToMetadata);
}
@@ -193,11 +191,12 @@
}
}
- public static class ContentsResponseTestMock implements Response {
+ private static class ContentsResponseTestMock implements Response {
private OutputStream os;
private String contentType;
private Metadata metadata;
private boolean notModified;
+ private boolean notFound;
public ContentsResponseTestMock(OutputStream os) {
this.os = os;
@@ -210,6 +209,11 @@
}
@Override
+ public void respondNotFound() {
+ notFound = true;
+ }
+
+ @Override
public OutputStream getOutputStream() {
return os;
}
@@ -235,6 +239,10 @@
public boolean getNotModified() {
return notModified;
}
+
+ public boolean getNotFound() {
+ return notFound;
+ }
}
@@ -278,4 +286,3 @@
}
-
diff --git a/test/adaptorlib/prebuilt/CommandLineTransformTest.java b/test/adaptorlib/prebuilt/CommandLineTransformTest.java
index 22114b9..d4f27a4 100644
--- a/test/adaptorlib/prebuilt/CommandLineTransformTest.java
+++ b/test/adaptorlib/prebuilt/CommandLineTransformTest.java
@@ -43,9 +43,9 @@
Map<String, String> params = new HashMap<String, String>();
params.put("key1", "value1");
- CommandLineTransform cmd = new CommandLineTransform("regex replace");
- cmd.transformCommand(Arrays.asList(new String[] {"sed", "s/i/1/"}));
- cmd.commandAcceptsParameters(false);
+ CommandLineTransform cmd = new CommandLineTransform();
+ cmd.setTransformCommand(Arrays.asList(new String[] {"sed", "s/i/1/"}));
+ cmd.setCommandAcceptsParameters(false);
pipeline.add(cmd);
pipeline.transform(testStr.getBytes(), contentOut, new HashMap<String, String>(), params);
@@ -69,8 +69,8 @@
Map<String, String> params = new HashMap<String, String>();
params.put("key1", "value1");
- CommandLineTransform cmd = new CommandLineTransform("regex replace");
- cmd.transformCommand(Arrays.asList(new String[] {"/bin/sh", "-c",
+ CommandLineTransform cmd = new CommandLineTransform();
+ cmd.setTransformCommand(Arrays.asList(new String[] {"/bin/sh", "-c",
// Process content.
"sed s/i/1/; META=\"$0\"; PARAM=\"$1\"; TMPFILE=$(tempfile);"
// Process metadata.
@@ -80,7 +80,7 @@
// Cleanup.
+ "rm \"$TMPFILE\" >&2;"
}));
- cmd.commandAcceptsParameters(true);
+ cmd.setCommandAcceptsParameters(true);
pipeline.add(cmd);
pipeline.transform(testStr.getBytes(), contentOut, metadata, params);