org.testmp.datastore.client.DataStoreClient.java Source code

Java tutorial

Introduction

Here is the source code for org.testmp.datastore.client.DataStoreClient.java

Source

/*
 * TestMP (Test Management Platform)
 * Copyright 2013 and beyond, Zhaowei Ding.
 *
 * TestMP is free software; you can redistribute it and/or modify it
 * under the terms of the MIT License (MIT).
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 */

package org.testmp.datastore.client;

import java.io.File;
import java.io.PrintWriter;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;

public class DataStoreClient {

    private static Logger log = Logger.getLogger(DataStoreClient.class.getSimpleName());

    // private HttpClient httpClient = new DefaultHttpClient();

    private URI dataStoreURL;

    /**
     * Construct a client to specified data store
     * 
     * @param url
     *            the data store location
     */
    public DataStoreClient(URI url) {
        this.dataStoreURL = url;
    }

    public DataStoreClient(String url) {
        this.dataStoreURL = URI.create(url);
    }

    public String getDataStoreURL() {
        return dataStoreURL.toString();
    }

    /**
     * Count the total data in the store
     * 
     * @return
     * @throws DataStoreClientException
     */
    public int countTotalData() throws DataStoreClientException {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(dataStoreURL);
        try {
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("action", "count"));
            params.add(new BasicNameValuePair("type", "data"));
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "UTF-8");
            httpPost.setEntity(entity);
            HttpResponse resp = httpClient.execute(httpPost);
            if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                String count = EntityUtils.toString(resp.getEntity(), "UTF-8");
                return Integer.parseInt(count);
            } else {
                StatusLine status = resp.getStatusLine();
                log.severe(status.getStatusCode() + ": " + status.getReasonPhrase());
                return -1;
            }
        } catch (Exception e) {
            throw new DataStoreClientException("Failed to count data", e);
        } finally {
            httpPost.releaseConnection();
        }
    }

    /**
     * Get wrapped tagged data of specified type by specified tags and
     * properties
     * 
     * @param type
     * @param tags
     * @param properties
     * @return
     * @throws DataStoreClientException
     */
    public <T> List<DataInfo<T>> getData(Class<T> type, String[] tags, Map<String, Object> properties)
            throws DataStoreClientException {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(dataStoreURL);
        try {
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("action", "get"));
            params.add(new BasicNameValuePair("type", "data"));
            if (tags != null && tags.length > 0) {
                String tagListParam = this.convertListToRequestParam(Arrays.asList(tags));
                params.add(new BasicNameValuePair("tag", tagListParam));
            }
            if (properties != null && !properties.isEmpty()) {
                ObjectMapper mapper = new ObjectMapper();
                params.add(new BasicNameValuePair("property", mapper.writeValueAsString(properties)));
            }
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "UTF-8");
            httpPost.setEntity(entity);
            HttpResponse resp = httpClient.execute(httpPost);
            if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                String json = EntityUtils.toString(resp.getEntity(), "UTF-8");
                return convertJsonToDataInfoList(json, type);
            } else {
                StatusLine status = resp.getStatusLine();
                log.severe(status.getStatusCode() + ": " + status.getReasonPhrase());
                return new LinkedList<DataInfo<T>>();
            }
        } catch (Exception e) {
            throw new DataStoreClientException("Failed to get data", e);
        } finally {
            httpPost.releaseConnection();
        }
    }

    /**
     * Find the data id with specified tags and properties
     * 
     * @param tags
     * @param properties
     * @return
     * @throws DataStoreClientException
     */
    public List<Integer> findData(String[] tags, Map<String, Object> properties) throws DataStoreClientException {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(dataStoreURL);
        try {
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("action", "find"));
            params.add(new BasicNameValuePair("type", "data"));
            if (tags != null && tags.length > 0) {
                String tagListParam = this.convertListToRequestParam(Arrays.asList(tags));
                params.add(new BasicNameValuePair("tag", tagListParam));
            }
            if (properties != null && !properties.isEmpty()) {
                ObjectMapper mapper = new ObjectMapper();
                params.add(new BasicNameValuePair("property", mapper.writeValueAsString(properties)));
            }
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "UTF-8");
            httpPost.setEntity(entity);
            HttpResponse resp = httpClient.execute(httpPost);
            if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                String json = EntityUtils.toString(resp.getEntity(), "UTF-8");
                ObjectMapper mapper = new ObjectMapper();
                return mapper.readValue(json, new TypeReference<List<Integer>>() {
                });
            } else {
                StatusLine status = resp.getStatusLine();
                log.severe(status.getStatusCode() + ": " + status.getReasonPhrase());
                return new LinkedList<Integer>();
            }
        } catch (Exception e) {
            throw new DataStoreClientException("Failed to find data", e);
        } finally {
            httpPost.releaseConnection();
        }
    }

    /**
     * Get wrapped tagged data of specified type by specified tags
     * 
     * @param type
     * @param tags
     * @return
     * @throws DataStoreClientException
     */
    public <T> List<DataInfo<T>> getDataByTag(Class<T> type, String... tags) throws DataStoreClientException {
        return getData(type, tags, null);
    }

    /**
     * Find the data id with specified tags
     * 
     * @param tags
     * @return
     * @throws DataStoreClientException
     */
    public List<Integer> findDataByTag(String... tags) throws DataStoreClientException {
        return findData(tags, null);
    }

    /**
     * Get wrapped tagged data of specified type by specified properties
     * 
     * @param <T>
     * @param type
     * @param properties
     * @return
     * @throws DataStoreClientException
     */
    public <T> List<DataInfo<T>> getDataByProperty(Class<T> type, Map<String, Object> properties)
            throws DataStoreClientException {
        return getData(type, null, properties);
    }

    /**
     * Find the data id with specified properties
     * 
     * @param properties
     * @return
     * @throws DataStoreClientException
     */
    public List<Integer> findDataByProperty(Map<String, Object> properties) throws DataStoreClientException {
        return findData(null, properties);
    }

    /**
     * Get wrapped tagged data of specified type by id
     * 
     * @param type
     * @param id
     * @return
     * @throws DataStoreClientException
     */
    public <T> DataInfo<T> getDataById(Class<T> type, int id) throws DataStoreClientException {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(dataStoreURL);
        try {
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("action", "get"));
            params.add(new BasicNameValuePair("type", "data"));
            params.add(new BasicNameValuePair("id", "" + id));
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "UTF-8");
            httpPost.setEntity(entity);
            HttpResponse resp = httpClient.execute(httpPost);
            if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                String json = EntityUtils.toString(resp.getEntity(), "UTF-8");
                List<DataInfo<T>> result = convertJsonToDataInfoList(json, type);
                return result.isEmpty() ? null : result.get(0);
            } else {
                StatusLine status = resp.getStatusLine();
                log.severe(status.getStatusCode() + ": " + status.getReasonPhrase());
                return null;
            }
        } catch (Exception e) {
            throw new DataStoreClientException("Failed to get data by id", e);
        } finally {
            httpPost.releaseConnection();
        }
    }

    /**
     * Get wrapped tagged data of specified id range
     * 
     * @param type
     * @param startId
     * @param endId
     * @return
     * @throws DataStoreClientException
     */
    public <T> List<DataInfo<T>> getDataByRange(Class<T> type, int startId, int endId)
            throws DataStoreClientException {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(dataStoreURL);
        try {
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("action", "get"));
            params.add(new BasicNameValuePair("type", "data"));
            params.add(new BasicNameValuePair("range", startId + "," + endId));
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "UTF-8");
            httpPost.setEntity(entity);
            HttpResponse resp = httpClient.execute(httpPost);
            if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                String json = EntityUtils.toString(resp.getEntity(), "UTF-8");
                List<DataInfo<T>> result = convertJsonToDataInfoList(json, type);
                return result;
            } else {
                StatusLine status = resp.getStatusLine();
                log.severe(status.getStatusCode() + ": " + status.getReasonPhrase());
                return new LinkedList<DataInfo<T>>();
            }
        } catch (Exception e) {
            throw new DataStoreClientException("Failed to get data by range", e);
        } finally {
            httpPost.releaseConnection();
        }
    }

    /**
     * Merge several data into single new data. The properties of the previous
     * specified data takes precedence than the followings
     * 
     * @param type
     * @param id
     * @param anotherIds
     * @return
     * @throws DataStoreClientException
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public <T> DataInfo<T> mergeData(Class<T> type, int id, int... anotherIds) throws DataStoreClientException {
        DataInfo<Map> dataInfo = getDataById(Map.class, id);
        List<String> tags = dataInfo.getTags();
        Map data = dataInfo.getData();
        for (int anotherId : anotherIds) {
            DataInfo<Map> anotherDataInfo = getDataById(Map.class, anotherId);
            for (String tag : anotherDataInfo.getTags()) {
                if (!tags.contains(tag)) {
                    tags.add(tag);
                }
            }
            for (Object entry : anotherDataInfo.getData().entrySet()) {
                Object key = ((Map.Entry) entry).getKey();
                Object value = ((Map.Entry) entry).getValue();
                if (!data.containsKey(key)) {
                    data.put(key, value);
                }
            }

        }
        dataInfo.setTags(tags);
        dataInfo.setData(data);
        ObjectMapper mapper = new ObjectMapper();
        try {
            return DataInfo.valueOf(mapper.writeValueAsString(dataInfo), type);
        } catch (Exception e) {
            throw new DataStoreClientException(e);
        }
    }

    /**
     * Add one or more wrapped tagged data
     * 
     * @param someDataInfo
     * @return
     * @throws DataStoreClientException
     */
    @SuppressWarnings("unchecked")
    public List<Integer> addData(DataInfo<?>... someDataInfo) throws DataStoreClientException {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(dataStoreURL);
        try {
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("action", "add"));
            params.add(new BasicNameValuePair("type", "data"));
            params.add(new BasicNameValuePair("content", converDataInfoListToJson(Arrays.asList(someDataInfo))));
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "UTF-8");
            httpPost.setEntity(entity);
            HttpResponse resp = httpClient.execute(httpPost);
            if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                String json = EntityUtils.toString(resp.getEntity(), "UTF-8");
                ObjectMapper mapper = new ObjectMapper();
                return mapper.readValue(json, List.class);
            } else {
                StatusLine status = resp.getStatusLine();
                log.severe(status.getStatusCode() + ": " + status.getReasonPhrase());
                return new LinkedList<Integer>();
            }
        } catch (Exception e) {
            throw new DataStoreClientException("Failed to add data", e);
        } finally {
            httpPost.releaseConnection();
        }
    }

    /**
     * Delete one or more tagged data by id
     * 
     * @param ids
     * @return
     * @throws DataStoreClientException
     */
    public boolean deleteData(Integer... ids) throws DataStoreClientException {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(dataStoreURL);
        try {
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("action", "delete"));
            params.add(new BasicNameValuePair("type", "data"));
            String idListParam = convertListToRequestParam(Arrays.asList(ids));
            params.add(new BasicNameValuePair("id", idListParam));
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "UTF-8");
            httpPost.setEntity(entity);
            HttpResponse resp = httpClient.execute(httpPost);
            return resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK;
        } catch (Exception e) {
            throw new DataStoreClientException("Failed to delete data", e);
        } finally {
            httpPost.releaseConnection();
        }
    }

    /**
     * Get all the stored tags
     * 
     * @return
     * @throws DataStoreClientException
     */
    public List<Tag> getTags() throws DataStoreClientException {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(dataStoreURL);
        try {
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("action", "get"));
            params.add(new BasicNameValuePair("type", "tag"));
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "UTF-8");
            httpPost.setEntity(entity);
            HttpResponse resp = httpClient.execute(httpPost);
            if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                String json = EntityUtils.toString(resp.getEntity(), "UTF-8");
                return convertJsonToObjectList(json, Tag.class);
            } else {
                StatusLine status = resp.getStatusLine();
                log.severe(status.getStatusCode() + ": " + status.getReasonPhrase());
                return new LinkedList<Tag>();
            }
        } catch (Exception e) {
            throw new DataStoreClientException("Failed to get tags", e);
        } finally {
            httpPost.releaseConnection();
        }
    }

    /**
     * Add a tag to the data of specified id
     * 
     * @param dataId
     * @param tag
     * @return
     * @throws DataStoreClientException
     */
    public boolean addTagToData(int dataId, String tag) throws DataStoreClientException {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(dataStoreURL);
        try {
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("action", "add"));
            params.add(new BasicNameValuePair("type", "tag"));
            params.add(new BasicNameValuePair("id", "" + dataId));
            params.add(new BasicNameValuePair("tag", tag));
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "UTF-8");
            httpPost.setEntity(entity);
            HttpResponse resp = httpClient.execute(httpPost);
            return resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK;
        } catch (Exception e) {
            throw new DataStoreClientException("Failed to add tag", e);
        } finally {
            httpPost.releaseConnection();
        }
    }

    /**
     * Delete a tag from the data of specified id
     * 
     * @param dataId
     * @param tag
     * @return
     * @throws DataStoreClientException
     */
    public boolean deleteTagFromData(int dataId, String tag) throws DataStoreClientException {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(dataStoreURL);
        try {
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("action", "delete"));
            params.add(new BasicNameValuePair("type", "tag"));
            params.add(new BasicNameValuePair("id", "" + dataId));
            params.add(new BasicNameValuePair("tag", tag));
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "UTF-8");
            httpPost.setEntity(entity);
            HttpResponse resp = httpClient.execute(httpPost);
            return resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK;
        } catch (Exception e) {
            throw new DataStoreClientException("Failed to delete tag", e);
        } finally {
            httpPost.releaseConnection();
        }
    }

    /**
     * Get all the stored string property values mapping to the specified key
     * 
     * @param key
     * @param tags
     *            - limit the range of properties by specifying related tags
     * @return
     * @throws DataStoreClientException
     */
    public List<String> getPropertyValues(String key, String... tags) throws DataStoreClientException {
        return getPropertyValues(String.class, key, tags);
    }

    /**
     * Get all the stored property values mapping to the specified key
     * 
     * @param type
     * @param key
     * @param tags
     *            - limit the range of properties by specifying related tags
     * @return
     * @throws DataStoreClientException
     */
    public <T> List<T> getPropertyValues(Class<T> type, String key, String... tags)
            throws DataStoreClientException {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(dataStoreURL);
        try {
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("action", "get"));
            params.add(new BasicNameValuePair("type", "property"));
            params.add(new BasicNameValuePair("key", key));
            params.add(new BasicNameValuePair("tag", convertListToRequestParam(Arrays.asList(tags))));
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "UTF-8");
            httpPost.setEntity(entity);
            HttpResponse resp = httpClient.execute(httpPost);
            if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                String json = EntityUtils.toString(resp.getEntity(), "UTF-8");
                List<T> result = convertJsonToObjectList(json, type);
                return result;
            } else {
                StatusLine status = resp.getStatusLine();
                log.severe(status.getStatusCode() + ": " + status.getReasonPhrase());
                return new LinkedList<T>();
            }
        } catch (Exception e) {
            throw new DataStoreClientException("Failed to get data by range", e);
        } finally {
            httpPost.releaseConnection();
        }
    }

    /**
     * Add a property to the data of specified id
     * 
     * @param dataId
     * @param key
     * @param value
     * @return
     * @throws DataStoreClientException
     */
    public boolean addPropertyToData(int dataId, String key, Object value) throws DataStoreClientException {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(dataStoreURL);
        try {
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("action", "add"));
            params.add(new BasicNameValuePair("type", "property"));
            params.add(new BasicNameValuePair("id", "" + dataId));

            Map<String, Object> property = new HashMap<String, Object>();
            property.put("key", key);
            property.put("value", value);
            ObjectMapper mapper = new ObjectMapper();
            params.add(new BasicNameValuePair("property", mapper.writeValueAsString(property)));

            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "UTF-8");
            httpPost.setEntity(entity);
            HttpResponse resp = httpClient.execute(httpPost);
            return resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK;
        } catch (Exception e) {
            throw new DataStoreClientException("Failed to add property", e);
        } finally {
            httpPost.releaseConnection();
        }
    }

    /**
     * Delete a property from the data of specified id
     * 
     * @param dataId
     * @param key
     * @return
     * @throws DataStoreClientException
     */
    public boolean deletePropertyFromData(int dataId, String key) throws DataStoreClientException {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(dataStoreURL);
        try {
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("action", "delete"));
            params.add(new BasicNameValuePair("type", "property"));
            params.add(new BasicNameValuePair("id", "" + dataId));
            params.add(new BasicNameValuePair("key", key));
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "UTF-8");
            httpPost.setEntity(entity);
            HttpResponse resp = httpClient.execute(httpPost);
            return resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK;
        } catch (Exception e) {
            throw new DataStoreClientException("Failed to delete property", e);
        } finally {
            httpPost.releaseConnection();
        }
    }

    /**
     * Save data in data store into specified file with JSON representation
     * 
     * @param filepath
     * @throws DataStoreClientException
     */
    public void saveDataToFile(String filepath) throws DataStoreClientException {
        List<Tag> tags = getTags();
        HashSet<Integer> idSet = new HashSet<Integer>();
        for (Tag tag : tags) {
            idSet.addAll(tag.getRelatedDataIds());
        }
        LinkedList<Integer> idList = new LinkedList<Integer>(idSet);
        Collections.sort(idList);
        int maxDataToGetEachTime = 500, i = 0;
        PrintWriter writer = null;
        try {
            writer = new PrintWriter(filepath, "UTF-8");
            writer.print("[");
            boolean isFirst = true;
            while (i < idList.size()) {
                int startId = idList.get(i);
                i = i + maxDataToGetEachTime - 1;
                int endId = (i >= idList.size() ? idList.getLast() : idList.get(i));
                i++;
                List<DataInfo<Object>> dataInfoList = getDataByRange(Object.class, startId, endId);
                for (DataInfo<Object> dataInfo : dataInfoList) {
                    if (!isFirst) {
                        writer.println(",");
                    } else {
                        isFirst = false;
                    }
                    writer.print(dataInfo.toString());
                }
            }
            writer.println("]");
        } catch (Exception e) {
            throw new DataStoreClientException("Failed to save data to file", e);
        } finally {
            if (writer != null) {
                writer.close();
            }
        }
    }

    /**
     * Upload data from specified file of JSON representation to data store
     * 
     * @param filepath
     * @return the id list of uploaded data
     * @throws DataStoreClientException
     */
    public List<Integer> uploadDataFromFile(String filepath) throws DataStoreClientException {
        ObjectMapper mapper = new ObjectMapper();
        try {
            List<DataInfo<Object>> dataInfoList = mapper.readValue(new File(filepath),
                    new TypeReference<List<DataInfo<Object>>>() {
                    });
            return addData(dataInfoList.toArray(new DataInfo[0]));
        } catch (Exception e) {
            throw new DataStoreClientException("Failed to upload data from file", e);
        }
    }

    /**
     * Get the meta info of data of specified id
     * 
     * @param dataIds
     * @return
     * @throws DataStoreClientException
     */
    public List<MetaInfo> getMetaInfo(Integer... dataIds) throws DataStoreClientException {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(dataStoreURL);
        try {
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("action", "get"));
            params.add(new BasicNameValuePair("type", "meta"));
            String idListParam = convertListToRequestParam(Arrays.asList(dataIds));
            params.add(new BasicNameValuePair("id", idListParam));
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "UTF-8");
            httpPost.setEntity(entity);
            HttpResponse resp = httpClient.execute(httpPost);
            if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                String json = EntityUtils.toString(resp.getEntity(), "UTF-8");
                List<MetaInfo> result = convertJsonToObjectList(json, MetaInfo.class);
                return result;
            } else {
                StatusLine status = resp.getStatusLine();
                log.severe(status.getStatusCode() + ": " + status.getReasonPhrase());
                return new LinkedList<MetaInfo>();
            }
        } catch (Exception e) {
            throw new DataStoreClientException("Failed to get meta data", e);
        } finally {
            httpPost.releaseConnection();
        }
    }

    /**
     * Update the meta info of data of specified id
     * 
     * @param key
     * @param value
     * @param dataIds
     * @return
     * @throws Exception
     */
    @SuppressWarnings("unused")
    private void updateMetaInfo(String key, Object value, Integer... dataIds) throws Exception {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(dataStoreURL);
        try {
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("type", "meta"));
            String idListParam = convertListToRequestParam(Arrays.asList(dataIds));
            params.add(new BasicNameValuePair("id", idListParam));
            params.add(new BasicNameValuePair("key", key));
            if (value != null) {
                params.add(new BasicNameValuePair("action", "add"));
                ObjectMapper mapper = new ObjectMapper();
                params.add(new BasicNameValuePair("value", mapper.writeValueAsString(value)));
            } else {
                params.add(new BasicNameValuePair("action", "delete"));
            }
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, "UTF-8");
            httpPost.setEntity(entity);
            HttpResponse resp = httpClient.execute(httpPost);
            if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
                log.warning("Failed to update meta info [" + key + ":" + value + "] for " + dataIds);
            }
        } finally {
            httpPost.releaseConnection();
        }
    }

    @SuppressWarnings("unused")
    private URIBuilder getCustomURIBuilder() {
        URIBuilder builder = new URIBuilder();
        builder.setScheme(dataStoreURL.getScheme());
        builder.setHost(dataStoreURL.getHost());
        builder.setPort(dataStoreURL.getPort());
        builder.setPath(dataStoreURL.getPath());
        return builder;
    }

    private <T> String convertListToRequestParam(List<T> list) {
        StringBuilder sb = new StringBuilder();
        for (T elem : list) {
            sb.append(elem.toString()).append(",");
        }
        if (sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1);
        }
        return sb.toString();
    }

    private String converDataInfoListToJson(List<DataInfo<?>> dataInfoList) {
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        boolean isFirst = true;
        for (DataInfo<?> dataInfo : dataInfoList) {
            if (!isFirst) {
                sb.append(",");
            } else {
                isFirst = false;
            }
            sb.append(dataInfo.toString());
        }
        sb.append("]");
        return sb.toString();
    }

    private <T> List<DataInfo<T>> convertJsonToDataInfoList(String s, Class<T> type) {
        List<DataInfo<T>> dataInfoList = new LinkedList<DataInfo<T>>();
        ObjectMapper mapper = new ObjectMapper();
        try {
            JsonNode dataInfoListNode = mapper.readTree(s);
            for (int i = 0; i < dataInfoListNode.size(); i++) {
                JsonNode dataInfoNode = dataInfoListNode.get(i);
                dataInfoList.add(DataInfo.valueOf(dataInfoNode.toString(), type));
            }
        } catch (Exception e) {
            throw new RuntimeException("Failed to convert JSON: " + s, e);
        }
        return dataInfoList;
    }

    private <T> List<T> convertJsonToObjectList(String s, Class<T> type) {
        List<T> objList = new LinkedList<T>();
        ObjectMapper mapper = new ObjectMapper();
        try {
            JsonNode objListNode = mapper.readTree(s);
            for (int i = 0; i < objListNode.size(); i++) {
                JsonNode objNode = objListNode.get(i);
                objList.add(mapper.readValue(objNode.toString(), type));
            }
        } catch (Exception e) {
            throw new RuntimeException("Failed to convert JSON: " + s, e);
        }
        return objList;
    }
}