com.github.rnewson.couchdb.lucene.DocumentConverter.java Source code

Java tutorial

Introduction

Here is the source code for com.github.rnewson.couchdb.lucene.DocumentConverter.java

Source

/*
 * 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;

import com.github.rnewson.couchdb.lucene.couchdb.CouchDocument;
import com.github.rnewson.couchdb.lucene.couchdb.Database;
import com.github.rnewson.couchdb.lucene.couchdb.View;
import com.github.rnewson.couchdb.lucene.couchdb.ViewSettings;
import com.github.rnewson.couchdb.lucene.rhino.JSLog;
import com.github.rnewson.couchdb.lucene.rhino.RhinoDocument;
import org.apache.log4j.Logger;
import org.apache.lucene.document.Document;
import org.apache.lucene.queryparser.classic.ParseException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.javascript.*;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;

public final class DocumentConverter {

    private static final Collection<Document> NO_DOCUMENTS = Collections.emptyList();
    private static final Logger LOG = Logger.getLogger(DocumentConverter.class);

    private final Context context;
    private final Function viewFun;
    private final ScriptableObject scope;

    public DocumentConverter(final Context context, final View view) throws IOException, JSONException {
        this.context = context;
        scope = context.initStandardObjects();
        context.setLanguageVersion(Context.VERSION_1_8);

        // Allow custom document helper class.
        try {
            ScriptableObject.defineClass(scope, RhinoDocument.class);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }

        // Add a log object
        ScriptableObject.putProperty(scope, "log", new JSLog());

        // Compile user-specified function
        try {
            viewFun = view.compileFunction(context, scope);
        } catch (final RhinoException e) {
            LOG.error("View code for " + view + " does not compile.");
            throw e;
        }
    }

    public Collection<Document> convert(final CouchDocument doc, final ViewSettings defaults,
            final Database database) throws IOException, ParseException, JSONException {
        final Object result;
        final Scriptable scriptable = convertObject(doc.asJson());

        try {
            result = viewFun.call(context, scope, null, new Object[] { scriptable });
        } catch (final JavaScriptException e) {
            LOG.warn(doc + " caused exception during conversion.", e);
            return NO_DOCUMENTS;
        }

        if (result == null || result instanceof Undefined) {
            return NO_DOCUMENTS;
        }

        if (result instanceof RhinoDocument) {
            final RhinoDocument rhinoDocument = (RhinoDocument) result;
            final Document document = rhinoDocument.toDocument(doc.getId(), defaults, database);
            return Collections.singleton(document);
        }

        if (result instanceof NativeArray) {
            final NativeArray nativeArray = (NativeArray) result;
            final Collection<Document> arrayResult = new ArrayList<Document>((int) nativeArray.getLength());
            for (int i = 0; i < (int) nativeArray.getLength(); i++) {
                if (nativeArray.get(i, null) instanceof RhinoDocument) {
                    final RhinoDocument rhinoDocument = (RhinoDocument) nativeArray.get(i, null);
                    final Document document = rhinoDocument.toDocument(doc.getId(), defaults, database);
                    arrayResult.add(document);
                }
            }
            return arrayResult;
        }

        return null;
    }

    private Object convert(final Object obj) throws JSONException {
        if (obj instanceof JSONArray) {
            return convertArray((JSONArray) obj);
        } else if (obj == JSONObject.NULL) {
            return null;
        } else if (obj instanceof JSONObject) {
            return convertObject((JSONObject) obj);
        } else {
            return obj;
        }
    }

    private Scriptable convertArray(final JSONArray array) throws JSONException {
        final Scriptable result = context.newArray(scope, array.length());
        for (int i = 0, max = array.length(); i < max; i++) {
            ScriptableObject.putProperty(result, i, convert(array.get(i)));
        }
        return result;
    }

    private Scriptable convertObject(final JSONObject obj) throws JSONException {
        if (obj == JSONObject.NULL) {
            return null;
        }
        final Scriptable result = context.newObject(scope);
        final Iterator<?> it = obj.keys();
        while (it.hasNext()) {
            final String key = (String) it.next();
            final Object value = obj.get(key);
            ScriptableObject.putProperty(result, key, convert(value));
        }
        return result;
    }

}