/* * Copyright Robert Newson * * 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.github.rnewson.couchdb.lucene.rhino; import com.github.rnewson.couchdb.lucene.Tika; import com.github.rnewson.couchdb.lucene.couchdb.Database; import com.github.rnewson.couchdb.lucene.couchdb.FieldType; import com.github.rnewson.couchdb.lucene.couchdb.ViewSettings; import com.github.rnewson.couchdb.lucene.util.Utils; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.ResponseHandler; import org.apache.lucene.document.Document; import org.apache.lucene.queryparser.classic.ParseException; import org.mozilla.javascript.*; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * Collect data from the user. * * @author rnewson */ public final class RhinoDocument extends ScriptableObject { private static class RhinoAttachment { private String attachmentName; private String fieldName; } private static class RhinoField { private NativeObject settings; private Object value; } private static final long serialVersionUID = 1L; public static Scriptable jsConstructor(final Context cx, final Object[] args, final Function ctorObj, final boolean inNewExpr) { final RhinoDocument doc = new RhinoDocument(); if (args.length >= 2) { jsFunction_add(cx, doc, args, ctorObj); } return doc; } public static void jsFunction_add(final Context cx, final Scriptable thisObj, final Object[] args, final Function funObj) { final RhinoDocument doc = checkInstance(thisObj); if (args.length < 1 || args.length > 2) { throw Context.reportRuntimeError("Invalid number of arguments."); } if (args[0] == null) { // Ignore. return; } if (args[0] instanceof Undefined) { // Ignore return; } final String className = args[0].getClass().getName(); if (className.equals("org.mozilla.javascript.NativeDate")) { args[0] = (Date) Context.jsToJava(args[0], Date.class); } if (!className.startsWith("java.lang.") && !className.equals("org.mozilla.javascript.NativeObject") && !className.equals("org.mozilla.javascript.NativeDate")) { throw Context.reportRuntimeError(className + " is not supported."); } if (args.length == 2 && (args[1] == null || args[1] instanceof NativeObject == false)) { throw Context.reportRuntimeError("second argument must be an object."); } final RhinoField field = new RhinoField(); field.value = args[0]; if (args.length == 2) { field.settings = (NativeObject) args[1]; } doc.fields.add(field); } public static void jsFunction_attachment(final Context cx, final Scriptable thisObj, final Object[] args, final Function funObj) throws IOException { final RhinoDocument doc = checkInstance(thisObj); if (args.length < 2) { throw Context.reportRuntimeError("Invalid number of arguments."); } final RhinoAttachment attachment = new RhinoAttachment(); attachment.fieldName = args[0].toString(); attachment.attachmentName = args[1].toString(); doc.attachments.add(attachment); } private static RhinoDocument checkInstance(final Scriptable obj) { if (obj == null || !(obj instanceof RhinoDocument)) { throw Context.reportRuntimeError("called on incompatible object."); } return (RhinoDocument) obj; } private final List<RhinoAttachment> attachments = new ArrayList<>(); private final List<RhinoField> fields = new ArrayList<>(); public RhinoDocument() { } public Document toDocument(final String id, final ViewSettings defaults, final Database database) throws IOException, ParseException { final Document result = new Document(); // Add id. result.add(Utils.token("_id", id, true)); // Add user-supplied fields. for (final RhinoField field : fields) { addField(field, defaults, result); } // Parse user-requested attachments. for (final RhinoAttachment attachment : attachments) { addAttachment(attachment, id, database, result); } return result; } @Override public String getClassName() { return "Document"; } private void addAttachment(final RhinoAttachment attachment, final String id, final Database database, final Document out) throws IOException { final ResponseHandler<Void> handler = new ResponseHandler<Void>() { public Void handleResponse(final HttpResponse response) throws ClientProtocolException, IOException { final HttpEntity entity = response.getEntity(); try { Tika.INSTANCE.parse(entity.getContent(), entity.getContentType().getValue(), attachment.fieldName, out); } finally { entity.consumeContent(); } return null; } }; database.handleAttachment(id, attachment.attachmentName, handler); } private void addField(final RhinoField field, final ViewSettings defaults, final Document out) throws ParseException { final ViewSettings settings = new ViewSettings(field.settings, defaults); final FieldType type = settings.getFieldType(); type.addFields(settings.getField(), field.value, settings, out); } }