package br.uff.ic.dyevc.services; //~--- non-JDK imports -------------------------------------------------------- import br.uff.ic.dyevc.application.IConstants; import br.uff.ic.dyevc.exception.DyeVCException; import br.uff.ic.dyevc.exception.ServiceException; import br.uff.ic.dyevc.gui.core.MessageManager; import br.uff.ic.dyevc.model.CommitInfo; import br.uff.ic.dyevc.model.topology.RepositoryInfo; import br.uff.ic.dyevc.persistence.MongoLabServiceParms; import br.uff.ic.dyevc.utils.PreferencesManager; import org.codehaus.jackson.map.annotate.JsonSerialize; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.type.TypeReference; import org.jboss.resteasy.client.ClientRequest; import org.jboss.resteasy.client.ClientResponse; import org.jboss.resteasy.client.core.BaseClientResponse; import org.jboss.resteasy.util.GenericType; import org.slf4j.LoggerFactory; //~--- JDK imports ------------------------------------------------------------ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Set; /** * This class provides access to services hosted in Mongo Labs * * @author Cristiano */ public class MongoLabProvider { /** Path to access mongo lab collection for repositories */ public static final String COLLECTION_REPOSITORIES = "/collections/repositories"; /** Path to access mongo lab collection for commits */ public static final String COLLECTION_COMMITS = "/collections/commits"; private static final String API_KEY = PreferencesManager.getInstance().loadPreferences().getAppKey(); private static final String BASE_URL = PreferencesManager.getInstance().loadPreferences().getDatabasePath(); private static final String KEY_MESSAGE_WHEN_ERROR_OCCURRED = "message"; private static final ObjectMapper mapper = new ObjectMapper(); static { MessageManager.getInstance().addMessage("Using database hosted at: " + BASE_URL); } // <editor-fold defaultstate="collapsed" desc="repositories"> /** * Retrieves a list of repositories from the database * * @param params A mapping of parameter names and parameter values to be * used in the service invocation * @return The list of repositories retrieved from the database * * @throws ServiceException */ public static ArrayList<RepositoryInfo> getRepositories(MongoLabServiceParms params) throws ServiceException { LoggerFactory.getLogger(MongoLabProvider.class).trace("getRepositories -> Entry"); ArrayList<RepositoryInfo> result = null; ClientRequest req; ClientResponse<ArrayList<RepositoryInfo>> res; try { req = prepareRequest(COLLECTION_REPOSITORIES, params); res = req.get(new GenericType<ArrayList<RepositoryInfo>>() {} ); if (res.getStatus() == 200) { result = res.getEntity(); } else { throwErrorMessage(COLLECTION_REPOSITORIES, res.getStatus(), params); } } catch (ServiceException se) { throw se; } catch (Exception ex) { LoggerFactory.getLogger(MongoLabProvider.class).error("Error getting repositories.", ex); throw new ServiceException(ex); } LoggerFactory.getLogger(MongoLabProvider.class).trace("getRepositories -> Exit"); return result; } /** * Upserts a repository to the database, this is, if the specified id does not exist, * inserts it, otherwise, updates it * * @param body The repository to be upserted * @return The result of the service invocation * @throws ServiceException In case of any exception during the service invocation */ public static Object upsertRepository(RepositoryInfo body) throws ServiceException { LoggerFactory.getLogger(MongoLabProvider.class).trace("upsertRepository -> Entry"); LinkedHashMap result = null; ClientRequest req; ClientResponse<LinkedHashMap> res; try { mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL); String serviceName = COLLECTION_REPOSITORIES + "/" + body.getId(); req = prepareRequest(serviceName, null, new String(mapper.writeValueAsBytes(body))); res = req.put(new GenericType<LinkedHashMap>() {} ); result = res.getEntity(); if (res.getStatus() != 200) { throwErrorMessage(serviceName, res.getStatus(), null); } } catch (ServiceException se) { throw se; } catch (Exception ex) { LoggerFactory.getLogger(MongoLabProvider.class).error("Error updating repository <" + body.getId() + ">", ex); throw new ServiceException(ex); } LoggerFactory.getLogger(MongoLabProvider.class).trace("upsertRepository -> Exit"); return result; } /** * Deletes a repository from the database. The application should first check * if the repository is not referenced anywhere, otherwise there will be inconsistency * in the database * * @param id The id of the repository to be deleted * @return The result of the service invocation * * @throws ServiceException */ public static Object deleteRepository(String id) throws ServiceException { LoggerFactory.getLogger(MongoLabProvider.class).trace("deleteRepository -> Entry"); LinkedHashMap result = null; ClientRequest req; ClientResponse<LinkedHashMap> res; try { String serviceName = COLLECTION_REPOSITORIES + "/" + id; req = prepareRequest(serviceName, null); res = req.delete(new GenericType<LinkedHashMap>() {} ); result = res.getEntity(); if (res.getStatus() != 200) { throwErrorMessage(serviceName, result.get(KEY_MESSAGE_WHEN_ERROR_OCCURRED), res.getStatus(), null); } } catch (ServiceException se) { throw se; } catch (Exception ex) { LoggerFactory.getLogger(MongoLabProvider.class).error("Error deleting repository <" + id + ">", ex); throw new ServiceException(ex); } LoggerFactory.getLogger(MongoLabProvider.class).trace("deleteRepository -> Exit"); return result; } // </editor-fold> // <editor-fold defaultstate="collapsed" desc="commits"> /** * Retrieves a list of commits from the database * * @param params A mapping of parameter names and parameter values to be * used in the service invocation * @return The list of commits retrieved from the database * * @throws ServiceException */ public static Set<CommitInfo> getCommits(MongoLabServiceParms params) throws ServiceException { LoggerFactory.getLogger(MongoLabProvider.class).trace("getCommits -> Entry"); Object result = null; ClientRequest req; BaseClientResponse<Object> res; try { req = prepareRequest(COLLECTION_COMMITS, params); res = (BaseClientResponse<Object>)req.get(Object.class); if (res.getStatus() == 200) { result = res.getEntity(); } else { throwErrorMessage(COLLECTION_COMMITS, res.getStatus(), params); } } catch (ServiceException se) { throw se; } catch (Exception ex) { LoggerFactory.getLogger(MongoLabProvider.class).error("Error getting commits.", ex); throw new ServiceException(ex); } LoggerFactory.getLogger(MongoLabProvider.class).trace("getCommits -> Exit"); return mapper.convertValue(result, new TypeReference<Set<CommitInfo>>() {} ); } /** * Retrieves the number of commits that match the criteria specified in params. * * @param params A mapping of parameter names and parameter values to be * used in the service invocation * @return The number of commits that match the criteria specified in params. * * @throws ServiceException */ public static Integer countCommits(MongoLabServiceParms params) throws ServiceException { LoggerFactory.getLogger(MongoLabProvider.class).trace("countCommits -> Entry"); Integer result = null; ClientRequest req; ClientResponse<Integer> res; try { req = prepareRequest(COLLECTION_COMMITS, params); req.queryParameter(MongoLabServiceParms.PARAM_COUNT, Boolean.toString(true)); res = req.get(new GenericType<Integer>() {} ); if (res.getStatus() == 200) { result = res.getEntity(); } else { throwErrorMessage(COLLECTION_COMMITS, res.getStatus(), params); } } catch (ServiceException se) { throw se; } catch (Exception ex) { LoggerFactory.getLogger(MongoLabProvider.class).error("Error counting commits.", ex); throw new ServiceException(ex); } LoggerFactory.getLogger(MongoLabProvider.class).trace("countCommits -> Exit"); return result; } /** * Inserts a collection of commits in the database * * @param commits The collection of commits to be inserted * @return The result of the service invocation * @throws DyeVCException In case of any exception during the service * invocation */ public static Object insertCommits(Collection<CommitInfo> commits) throws DyeVCException { LoggerFactory.getLogger(MongoLabProvider.class).trace("insertCommits -> Entry"); LinkedHashMap result = null; ClientRequest req; ClientResponse<LinkedHashMap> res; try { mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL); String serviceName = COLLECTION_COMMITS; req = prepareRequest(serviceName, null, new String(mapper.writeValueAsBytes(commits))); res = req.post(new GenericType<LinkedHashMap>() {} ); result = res.getEntity(); if (res.getStatus() != 200) { throwErrorMessage(serviceName, result.get(KEY_MESSAGE_WHEN_ERROR_OCCURRED), res.getStatus(), null); } } catch (ServiceException se) { throw se; } catch (Exception ex) { LoggerFactory.getLogger(MongoLabProvider.class).error("Error inserting commits.", ex); throw new ServiceException(ex); } LoggerFactory.getLogger(MongoLabProvider.class).trace("insertCommits -> Exit"); return result; } /** * Updates a list of commits, according to query embedded in <code>parms</code>, with values specified in <code>updateCmd</code> * @param parms The parameters to be used in the update * @param updateCmd The update value * * @return * * @throws ServiceException */ public static Object updateCommits(MongoLabServiceParms parms, String updateCmd) throws ServiceException { LoggerFactory.getLogger(MongoLabProvider.class).trace("updateCommits -> Entry"); LinkedHashMap result = null; ClientRequest req; ClientResponse<LinkedHashMap> res; try { String serviceName = COLLECTION_COMMITS; req = prepareRequest(serviceName, parms, updateCmd); res = req.put(new GenericType<LinkedHashMap>() {} ); result = res.getEntity(); if (res.getStatus() != 200) { throwErrorMessage(serviceName, result.get("message"), res.getStatus(), parms); } } catch (Exception ex) { LoggerFactory.getLogger(MongoLabProvider.class).error("Error updating commits with command: <" + updateCmd + ">", ex); throw new ServiceException(ex); } LoggerFactory.getLogger(MongoLabProvider.class).trace("updateCommits -> Exit"); return result; } /** * Deletes all commits, according to query embedded in <code>parms</code></code> * @param parms The parameters to be used during the deletion * * @return * * @throws ServiceException */ public static Object deleteCommits(MongoLabServiceParms parms) throws ServiceException { LoggerFactory.getLogger(MongoLabProvider.class).trace("deleteCommits -> Entry"); LinkedHashMap result = null; ClientRequest req; ClientResponse<LinkedHashMap> res; try { String serviceName = COLLECTION_COMMITS; req = prepareRequest(serviceName, parms); req.body("application/json", "[ ]"); res = req.put(new GenericType<LinkedHashMap>() {} ); result = res.getEntity(); if (res.getStatus() != 200) { throwErrorMessage(serviceName, result.get(KEY_MESSAGE_WHEN_ERROR_OCCURRED), res.getStatus(), null); } } catch (Exception ex) { LoggerFactory.getLogger(MongoLabProvider.class).error("Error deleting commits.", ex); throw new ServiceException(ex); } LoggerFactory.getLogger(MongoLabProvider.class).trace("deleteCommits -> Exit"); return result; } // </editor-fold> // <editor-fold defaultstate="collapsed" desc="request prepare"> private static ClientRequest prepareRequest(String service, HashMap<String, Object> params) { ClientRequest req; req = new ClientRequest(BASE_URL + service); req.queryParameter("apiKey", API_KEY); if (params != null) { for (String key : params.keySet()) { req.queryParameter(key, params.get(key)); } } return req; } private static ClientRequest prepareRequest(String service, HashMap<String, Object> params, String body) { ClientRequest req; req = prepareRequest(service, params); if (body != null) { req.body("application/json", body); } return req; } // </editor-fold> // <editor-fold defaultstate="collapsed" desc="error handling"> private static void throwErrorMessage(String service, Object error, int status, HashMap<String, Object> params) throws ServiceException { StringBuilder message = createErrorMessage(service, error, status, params); LoggerFactory.getLogger(MongoLabProvider.class).error(message.toString()); throw new ServiceException(message.toString()); } private static void throwErrorMessage(String service, int status, HashMap<String, Object> params) throws ServiceException { Object error = null; StringBuilder message = createErrorMessage(service, error, status, params); LoggerFactory.getLogger(MongoLabProvider.class).error(message.toString()); throw new ServiceException(message.toString()); } private static StringBuilder createErrorMessage(String service, Object error, int status, HashMap<String, Object> params) throws ServiceException { StringBuilder message = new StringBuilder("Error invoking service: ").append(service).append( ". Return code received on service invocation: ").append(status).append( " - ").append(HttpStatus.getStatusText(status)); if (error != null) { message.append(IConstants.LINE_SEPARATOR).append("\tError message: ").append(error.toString()); } if ((params != null) &&!params.isEmpty()) { message.append(IConstants.LINE_SEPARATOR).append("\tParams used on invocation: ").append( IConstants.LINE_SEPARATOR); for (String key : params.keySet()) { message.append("\t\t").append(key).append(": ").append(params.get(key)).append( IConstants.LINE_SEPARATOR); } } return message; } // </editor-fold> }