Package org.b3log.latke.remote

Source Code of org.b3log.latke.remote.RepositoryAccessor

/*
* Copyright (c) 2009, 2010, 2011, 2012, B3log Team
*
* 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 org.b3log.latke.remote;

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.b3log.latke.Keys;
import org.b3log.latke.Latkes;
import org.b3log.latke.annotation.RequestProcessing;
import org.b3log.latke.annotation.RequestProcessor;
import org.b3log.latke.model.Pagination;
import org.b3log.latke.repository.AbstractRepository;
import org.b3log.latke.repository.Query;
import org.b3log.latke.repository.Repositories;
import org.b3log.latke.repository.Repository;
import org.b3log.latke.repository.Transaction;
import org.b3log.latke.servlet.HTTPRequestContext;
import org.b3log.latke.servlet.HTTPRequestMethod;
import org.b3log.latke.servlet.renderer.JSONRenderer;
import org.b3log.latke.util.Strings;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
* Accesses repository via HTTP protocol.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.3, Apr 22, 2012
*/
@RequestProcessor
public final class RepositoryAccessor {

    /**
     * Logger.
     */
    private static final Logger LOGGER = Logger.getLogger(RepositoryAccessor.class.getName());

    /**
     * Gets whether repositories is writable.
     *
     * <p>
     * Query parameters:
     * /latke/remote/repositories/writable?<em>userName=xxx&password=xxx</em><br/>
     * All parameters are required.
     * </p>
     *
     * <p>
     * Renders response like the following:
     * <pre>
     * {
     *     "sc":200,
     *     "writable": true,
     *     "msg":"Gets repositories writable[true]"
     * }
     * </pre>
     * </p>
     *
     * @param context the specified HTTP request context
     * @param request the specified HTTP servlet request
     * @param response the specified HTTP servlet response
     */
    @RequestProcessing(value = "/latke/remote/repositories/writable", method = HTTPRequestMethod.GET)
    public void getRepositoriesWritable(final HTTPRequestContext context, final HttpServletRequest request,
                                        final HttpServletResponse response) {
        final JSONRenderer renderer = new JSONRenderer();
        context.setRenderer(renderer);

        final JSONObject jsonObject = new JSONObject();
        renderer.setJSONObject(jsonObject);

        if (!authSucc(request, jsonObject)) {
            return;
        }

        final boolean writable = Repositories.getReposirotiesWritable();

        jsonObject.put(Keys.STATUS_CODE, HttpServletResponse.SC_OK);
        jsonObject.put(Keys.MSG, "Gets repositories writable[" + writable + "]");
        jsonObject.put("writable", writable);
    }

    /**
     * Sets whether repositories is writable.
     *
     * <p>
     * Query parameters:
     * /latke/remote/repositories/writable?<em>userName=xxx&password=xxx&writable=true</em><br/>
     * All parameters are required.
     * </p>
     *
     * <p>
     * Renders response like the following:
     * <pre>
     * {
     *     "sc":200,
     *     "msg":"Sets repositories writable[true]"
     * }
     * </pre>
     * </p>
     *
     * @param context the specified HTTP request context
     * @param request the specified HTTP servlet request
     * @param response the specified HTTP servlet response
     */
    @RequestProcessing(value = "/latke/remote/repositories/writable", method = HTTPRequestMethod.PUT)
    public void setRepositoriesWritable(final HTTPRequestContext context, final HttpServletRequest request,
                                        final HttpServletResponse response) {
        final JSONRenderer renderer = new JSONRenderer();
        context.setRenderer(renderer);

        final JSONObject jsonObject = new JSONObject();
        renderer.setJSONObject(jsonObject);

        final String writable = request.getParameter("writable");
        if (!"true".equals(writable) && !"false".equals(writable)) {
            jsonObject.put(Keys.STATUS_CODE, HttpServletResponse.SC_BAD_REQUEST);
            jsonObject.put(Keys.MSG, "Requires parameter[writable], optional value is [true] or [false]");

            return;
        }

        if (!authSucc(request, jsonObject)) {
            return;
        }

        Repositories.setRepositoriesWritable(Boolean.parseBoolean(writable));

        jsonObject.put(Keys.STATUS_CODE, HttpServletResponse.SC_OK);
        jsonObject.put(Keys.MSG, "Sets repositories writable[" + writable + "]");
    }

    /**
     * Gets repository names.
     *
     * <p>
     * Query parameters:
     * /latke/remote/repository/names?<em>userName=xxx&password=xxx</em><br/>
     * All parameters are required.
     * </p>
     *
     * <p>
     * Renders response like the following:
     * <pre>
     * {
     *     "sc":200,
     *     "msg":"Got data",
     *     "repositoryNames" : [
     *         "repository1", "repository2", ....
     *       ]
     * }
     * </pre>
     * </p>
     *
     * @param context the specified HTTP request context
     * @param request the specified HTTP servlet request
     * @param response the specified HTTP servlet response
     */
    @RequestProcessing(value = "/latke/remote/repository/names", method = HTTPRequestMethod.GET)
    public void getRepositoryNames(final HTTPRequestContext context, final HttpServletRequest request,
                                   final HttpServletResponse response) {
        final JSONRenderer renderer = new JSONRenderer();
        context.setRenderer(renderer);

        final JSONObject jsonObject = new JSONObject();
        renderer.setJSONObject(jsonObject);

        jsonObject.put(Keys.STATUS_CODE, HttpServletResponse.SC_OK);
        jsonObject.put(Keys.MSG, "Got data");

        if (!authSucc(request, jsonObject)) {
            return;
        }

        jsonObject.put("repositoryNames", Repositories.getRepositoryNames());
    }

    /**
     * Gets repository data.
     *
     * <p>
     * Query parameters:
     * /latke/remote/repository/data?<em>userName=xxx&password=xxx&repositoryName=xxx&pageNum=xxx&pageSize=xxx</em><br/>
     * All parameters are required.
     * </p>
     *
     * <p>
     * Renders response like the following:
     * <pre>
     * {
     *   "sc":200,
     *   "msg":"Got data",
     *   "pagination":{
     *      "paginationPageCount":11
     *   },
     *   "rslts":[{}, {}, ....]
     * }
     * </pre>
     * </p>
     *
     * @param context the specified HTTP request context
     * @param request the specified HTTP servlet request
     * @param response the specified HTTP servlet response
     */
    @RequestProcessing(value = "/latke/remote/repository/data", method = HTTPRequestMethod.GET)
    public void getData(final HTTPRequestContext context, final HttpServletRequest request, final HttpServletResponse response) {
        final JSONRenderer renderer = new JSONRenderer();
        context.setRenderer(renderer);

        final JSONObject jsonObject = new JSONObject();
        renderer.setJSONObject(jsonObject);

        jsonObject.put(Keys.STATUS_CODE, HttpServletResponse.SC_OK);
        jsonObject.put(Keys.MSG, "Got data");

        if (badGetDataRequest(request, jsonObject) || !authSucc(request, jsonObject)) {
            return;
        }

        final String repositoryName = request.getParameter("repositoryName");
        final Repository repository = Repositories.getRepository(repositoryName);
        if (null == repository) {
            jsonObject.put(Keys.STATUS_CODE, HttpServletResponse.SC_BAD_REQUEST);
            jsonObject.put(Keys.MSG, "Not found repository[name=" + repositoryName + "]");

            return;
        }

        final boolean cacheEnabled = repository.isCacheEnabled();

        repository.setCacheEnabled(false);

        final Query query = new Query().setCurrentPageNum(Integer.valueOf(request.getParameter("pageNum"))).
                setPageSize(Integer.valueOf(request.getParameter("pageSize")));

        try {
            final JSONObject result = repository.get(query);
            final JSONObject pagination = result.getJSONObject(Pagination.PAGINATION);
            final JSONArray data = result.getJSONArray(Keys.RESULTS);

            jsonObject.put(Pagination.PAGINATION, pagination);
            jsonObject.put(Keys.RESULTS, data);
        } catch (final Exception e) {
            LOGGER.log(Level.SEVERE, "Gets data failed", e);

            jsonObject.put(Keys.STATUS_CODE, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            jsonObject.put(Keys.MSG, "Gets data failed[errorMsg=" + e.getMessage() + "]");
        } finally {
            repository.setCacheEnabled(cacheEnabled);
        }
    }

    /**
     * Puts data to repository.
     *
     * <p>
     * Query parameters:
     * /latke/remote/repository/data?<em>userName=xxx&password=xxx&repositoryName=xxx</em><br/>
     * All parameters are required.
     * </p>
     *
     * <p>
     * The post body, for example, "data": {....} or [] // JSON object or JSON array, content of the backup file
     * </p>
     *
     * <p>
     * Renders response like the following:
     * <pre>
     * {
     *   "sc":200,
     *   "msg":"Put data"
     * }
     * </pre>
     * </p>
     *
     * @param context the specified HTTP request context
     * @param request the specified HTTP servlet request
     * @param response the specified HTTP servlet response
     */
    @RequestProcessing(value = "/latke/remote/repository/data", method = HTTPRequestMethod.POST)
    public void putData(final HTTPRequestContext context, final HttpServletRequest request, final HttpServletResponse response) {
        final JSONRenderer renderer = new JSONRenderer();
        context.setRenderer(renderer);

        final JSONObject jsonObject = new JSONObject();
        renderer.setJSONObject(jsonObject);

        jsonObject.put(Keys.STATUS_CODE, HttpServletResponse.SC_OK);
        jsonObject.put(Keys.MSG, "Put data");

        if (badPutDataRequest(request, jsonObject) || !authSucc(request, jsonObject)) {
            return;
        }

        final String repositoryName = request.getParameter("repositoryName");
        Repository repository = Repositories.getRepository(repositoryName);
        if (null == repository) {
            repository = new AbstractRepository(repositoryName) {
            };
        }

        repository.setCacheEnabled(false);

        final Transaction transaction = repository.beginTransaction();
        try {
            final String dataContent = request.getParameter("data").trim();
            final JSONArray data = new JSONArray(dataContent);
            for (int i = 0; i < data.length(); i++) {
                final JSONObject record = data.getJSONObject(i);
                repository.add(record);
            }

            transaction.commit();
        } catch (final Exception e) {
            if (transaction.isActive()) {
                transaction.rollback();
            }

            LOGGER.log(Level.SEVERE, "Gets data failed", e);

            jsonObject.put(Keys.STATUS_CODE, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            jsonObject.put(Keys.MSG, "Gets data failed[errorMsg=" + e.getMessage() + "]");
        } finally {
            repository.setCacheEnabled(true);
        }
    }

    /**
     * Determines whether the specified request is authenticated.
     *
     * <p>
     * If the specified request is unauthenticated, puts {@link Keys#STATUS_CODE sc} and {@link Keys#MSG msg}
     * into the specified json object to render.
     * </p>
     *
     * @param request the specified request
     * @param jsonObject the specified json object
     * @return {@code true} if authenticated, returns {@code false} otherwise
     */
    private boolean authSucc(final HttpServletRequest request, final JSONObject jsonObject) {
        if (!Latkes.isRemoteEnabled()) {
            jsonObject.put(Keys.STATUS_CODE, HttpServletResponse.SC_NOT_IMPLEMENTED);
            jsonObject.put(Keys.MSG, "Latke remote interfaces are disabled");
            return false;
        }

        final String userName = request.getParameter("userName");
        final String password = request.getParameter("password");

        if (Strings.isEmptyOrNull(userName)) {
            jsonObject.put(Keys.STATUS_CODE, HttpServletResponse.SC_BAD_REQUEST);
            jsonObject.put(Keys.MSG, "Requires parameter[userName]");
            return false;
        }

        if (Strings.isEmptyOrNull(password)) {
            jsonObject.put(Keys.STATUS_CODE, HttpServletResponse.SC_BAD_REQUEST);
            jsonObject.put(Keys.MSG, "Requires parameter[password]");
            return false;
        }

        final String repositoryAccessorUserName = Latkes.getRemoteProperty("repositoryAccessor.userName");
        final String repositoryAccessorPassword = Latkes.getRemoteProperty("repositoryAccessor.password");

        if (userName.equals(repositoryAccessorUserName) && password.equals(repositoryAccessorPassword)) {
            return true;
        }

        jsonObject.put(Keys.STATUS_CODE, HttpServletResponse.SC_FORBIDDEN);
        jsonObject.put(Keys.MSG, "Auth failed[userName=" + userName + ", password=" + password + "]");

        return false;
    }

    /**
     * Determines whether the specified get data request is bad.
     *
     * <p>
     * If the specified request is bad, puts {@link Keys#STATUS_CODE sc} and {@link Keys#MSG msg}
     * into the specified json object to render.
     * </p>
     *
     * @param request the specified request
     * @param jsonObject the specified jsonObject
     * @return {@code true} if it is bad, returns {@code false} otherwise
     */
    private boolean badGetDataRequest(final HttpServletRequest request, final JSONObject jsonObject) {
        final String repositoryName = request.getParameter("repositoryName");
        final String pageNumString = request.getParameter("pageNum");
        final String pageSizeString = request.getParameter("pageSize");

        if (Strings.isEmptyOrNull(repositoryName)) {
            jsonObject.put(Keys.STATUS_CODE, HttpServletResponse.SC_BAD_REQUEST);
            jsonObject.put(Keys.MSG, "Requires parameter[repositoryName]");
            return true;
        }

        if (Strings.isEmptyOrNull(pageNumString)) {
            jsonObject.put(Keys.STATUS_CODE, HttpServletResponse.SC_BAD_REQUEST);
            jsonObject.put(Keys.MSG, "Requires parameter[pageNum]");
            return true;
        }

        if (Strings.isEmptyOrNull(pageSizeString)) {
            jsonObject.put(Keys.STATUS_CODE, HttpServletResponse.SC_BAD_REQUEST);
            jsonObject.put(Keys.MSG, "Requires parameter[pageSize]");
            return true;
        }

        try {
            Integer.parseInt(pageNumString);
        } catch (final Exception e) {
            jsonObject.put(Keys.STATUS_CODE, HttpServletResponse.SC_BAD_REQUEST);
            jsonObject.put(Keys.MSG, "Parameter[pageNum] must be a integer");
            return true;
        }

        try {
            Integer.parseInt(pageSizeString);
        } catch (final Exception e) {
            jsonObject.put(Keys.STATUS_CODE, HttpServletResponse.SC_BAD_REQUEST);
            jsonObject.put(Keys.MSG, "Parameter[pageSize] must be a integer");
            return true;
        }

        return false;
    }

    /**
     * Determines whether the specified put data request is bad.
     *
     * <p>
     * If the specified request is bad, puts {@link Keys#STATUS_CODE sc} and {@link Keys#MSG msg}
     * into the specified json object to render.
     * </p>
     *
     * @param request the specified request
     * @param jsonObject the specified jsonObject
     * @return {@code true} if it is bad, returns {@code false} otherwise
     */
    private boolean badPutDataRequest(final HttpServletRequest request, final JSONObject jsonObject) {
        final String repositoryName = request.getParameter("repositoryName");
        if (Strings.isEmptyOrNull(repositoryName)) {
            jsonObject.put(Keys.STATUS_CODE, HttpServletResponse.SC_BAD_REQUEST);
            jsonObject.put(Keys.MSG, "Requires parameter[repositoryName]");
            return true;
        }

        final String dataContent = request.getParameter("data");
        if (Strings.isEmptyOrNull(dataContent)) {
            jsonObject.put(Keys.STATUS_CODE, HttpServletResponse.SC_BAD_REQUEST);
            jsonObject.put(Keys.MSG, "Requires parameter[data]");
            return true;
        }

        try {
            new JSONArray(dataContent);
        } catch (final JSONException e) {
            jsonObject.put(Keys.STATUS_CODE, HttpServletResponse.SC_BAD_REQUEST);
            jsonObject.put(Keys.MSG, "Parameter[data] must be a JSON object or a JSON array");
            return true;
        }

        return false;
    }
}
TOP

Related Classes of org.b3log.latke.remote.RepositoryAccessor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.