/**
* <copyright>
*
* Copyright (c) 2009, 2010, 2012 Springsite BV (The Netherlands) and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Martin Taal - Initial API and implementation
* Dzmitry [zmicer] Harachka - implementation
* </copyright>
*
* $Id: RetrieveModelOperation.java,v 1.7 2011/09/04 20:04:19 mtaal Exp $
*/
package org.eclipse.emf.texo.server.service;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.texo.provider.IdProvider;
import org.eclipse.emf.texo.server.model.request.QueryType;
import org.eclipse.emf.texo.server.model.response.ResponseModelPackage;
import org.eclipse.emf.texo.server.model.response.ResponseType;
import org.eclipse.emf.texo.utils.Check;
import org.eclipse.emf.texo.utils.ModelUtils;
/**
* The model operation which takes care of retrieving data. The conversion to the expected format is done by the
* implementing subclass.
*
* The following type of request uris are supported here:
* <ul>
* <li>http://www.test.com/XMLService?query=select o from Order&firstResult=10&maxResults=50 a query with paging
* parameters</li>
* <li>http://www.test.com/XMLService?id=http://www.test.com/XMLService/Order/123 an uri with an id parameter
* <li>http://www.test.com/XMLService/Order/123 a direct uri with a type and id</li>
* <li>http://www.test.com/XMLService/Order an uri with just a type (and optional page parameters).</li>
* <li>http://www.test.com/XMLService/model/eclass?id=Library</li>
* <li>http://www.test.com/XMLService/model/epackage?id=</li>
* </ul>
*
* The response of this web service is an instance of the {@link ResponseType}.
*
* @author <a href="mtaal@elver.org">Martin Taal</a>
* @version $Revision: 1.7 $
*/
public class RetrieveModelOperation extends ModelOperation {
private static final String FALSE = Boolean.FALSE.toString();
@SuppressWarnings("unchecked")
@Override
protected void internalExecute() {
final String[] segments = ServiceUtils.getSegments(getServiceContext().getServiceRequestURI());
// 0) a post with a json object or 1) a query
QueryType queryType = getQueryType();
if (queryType != null) {
int maxResults = queryType.getMaxResults();
int startRow = queryType.getFirstResult() == -1 ? 0 : queryType.getFirstResult();
if (!queryType.isDoCount() && maxResults != -1 && maxResults != Integer.MAX_VALUE) {
// try to get one more than the requested result size
// if we should not do count
maxResults++;
}
final Map<String, Object> parameters = getParameters(queryType);
final List<Object> resultList;
if (queryType.getNamedQuery() != null) {
resultList = (List<Object>) getObjectStore().namedQuery(queryType.getNamedQuery(), parameters, startRow,
maxResults);
} else {
resultList = (List<Object>) getObjectStore().query(queryType.getQuery(), parameters, startRow, maxResults);
}
// now do smart things, to prevent unnecessary count operations
long cnt;
if (resultList.size() < maxResults) {
// we did not get everything so we reached the end anyway
cnt = resultList.size() + startRow;
} else if (maxResults == -1 || maxResults == Integer.MAX_VALUE) {
// if there were no paging limitations then this is the size
cnt = resultList.size() + startRow;
} else if (queryType.isDoCount()) {
if (queryType.getNamedQuery() != null) {
cnt = getObjectStore().countNamedQuery(queryType.getNamedQuery(), parameters);
} else {
cnt = getObjectStore().count(queryType.getQuery(), parameters);
}
} else {
// okay then the count is one more than the original maxresults
cnt = maxResults;
// remove the last result from the result
resultList.remove(resultList.size() - 1);
}
final Object responseObject;
if (queryType.isCountOperation()) {
responseObject = getResponse(Collections.emptyList(), 0, 0, (Long) resultList.get(0));
} else {
responseObject = getResponse(resultList, startRow, startRow + resultList.size() - 1, cnt);
}
getServiceContext().setResultInResponse(responseObject);
} else if (segments.length < 2 && getServiceContext().getRequestParameters().containsKey(ServiceConstants.PARAM_ID)) {
// an id which must be a uri
final URI uri = URI.createURI((String) getServiceContext().getRequestParameters().get(ServiceConstants.PARAM_ID));
final Object object = getObjectStore().fromUri(uri);
getServiceContext().setResultInResponse(object);
} else if (segments.length == 0) {
throw new IllegalArgumentException("Service path " + getServiceContext().getServiceRequestURI() //$NON-NLS-1$
+ " not supported, uri " + getServiceContext().getRequestURI()); //$NON-NLS-1$
} else if (segments.length == 1) {
// 2) there is a specific type without an id, return all instances
final EClass eClass = ModelUtils.getEClassFromQualifiedName(segments[0]);
final QueryBuilder queryBuilder = QueryBuilder.getQueryBuilder(getObjectStore().getEntityName(eClass), eClass,
getServiceContext().getRequestParameters());
final List<Object> resultList = (List<Object>) getObjectStore().query(queryBuilder.getSelectQuery(),
Collections.<String, Object> emptyMap(), getFirstResult(), getMaxResults());
int maxResults = getMaxResults();
int startRow = getFirstResult() == -1 ? 0 : getFirstResult();
final String noCountParam = (String) getServiceContext().getRequestParameters().get(
ServiceConstants.PARAM_NO_COUNT);
boolean doCount = maxResults != -1 && (noCountParam == null || FALSE.equals(noCountParam));
if (!doCount && maxResults != -1) {
// try to get one more than the requested result size
// if we should not do count
maxResults++;
}
// now do smart things, to prevent unnecessary count operations
long cnt;
if (resultList.size() < maxResults) {
// we did not get everything so we reached the end anyway
cnt = resultList.size() + startRow;
} else if (maxResults == -1) {
// if there were no paging limitations then this is the size
cnt = resultList.size() + startRow;
} else if (doCount) {
cnt = getObjectStore().count(queryBuilder.getCountQuery(), Collections.<String, Object> emptyMap());
} else {
// okay then the count is one more than the original maxresults
cnt = maxResults;
// remove the last result from the result
resultList.remove(resultList.size() - 1);
}
final Object responseObject = getResponse(resultList, startRow, startRow + resultList.size() - 1, cnt);
getServiceContext().setResultInResponse(responseObject);
} else if (segments.length == 2) {
// 3) there is specific type with an id, or
// 4) a model request: model/eclass?id= or model/eclassifier?id= or model/epackage?id=
if (ServiceConstants.SEGMENT_MODEL.equals(segments[0])) {
final EObject modelElement = retrieveModelInformation(segments[1]);
getServiceContext().setResultInResponse(modelElement);
} else {
final String idString = segments[1];
final EClass eClass = ModelUtils.getEClassFromQualifiedName(segments[0]);
final Object id = IdProvider.getInstance().convertIdStringToId(eClass, idString);
final Object object = getObjectStore().get(eClass, id);
if (object == null) {
getServiceContext().createResourceNotFoundResult();
} else {
getServiceContext().setResultInResponse(object);
}
}
} else {
throw new IllegalArgumentException("Service path " + getServiceContext().getServiceRequestURI() //$NON-NLS-1$
+ " not supported, uri " + getServiceContext().getRequestURI()); //$NON-NLS-1$
}
}
protected EObject retrieveModelInformation(String modelType) {
if (ServiceConstants.SEGMENT_ECLASS.equals(modelType) || ServiceConstants.SEGMENT_ECLASSIFIER.equals(modelType)) {
final boolean isRetrieveEClass = ServiceConstants.SEGMENT_ECLASS.equals(modelType);
// eclass of eclassifier
final String ePackageidentifier = (String) getServiceContext().getRequestParameters().get(
ServiceConstants.MODEL_EPACKAGE_PARAMETER);
final String name = (String) getServiceContext().getRequestParameters()
.get(ServiceConstants.MODEL_NAME_PARAMETER);
final String id = (String) getServiceContext().getRequestParameters().get(ServiceConstants.MODEL_ID_PARAMETER);
if (id != null) {
return ModelUtils.getEClassFromQualifiedName(id);
}
Check.isNotNull(name, "name parameter should be set when retrieving an eclass(ifier)"); //$NON-NLS-1$
Check.isNotNull(ePackageidentifier, "epackage parameter should be set when retrieving an eclass(ifier)"); //$NON-NLS-1$
final EPackage ePackage = ModelUtils.getEPackageFromNameUriOrPrefix(ePackageidentifier);
for (EClassifier eClassifier : ePackage.getEClassifiers()) {
if (name.equals(eClassifier.getName())) {
if (isRetrieveEClass) {
// force a cast to throw an exception if not correct
final EClass eClass = (EClass) eClassifier;
return eClass;
}
return eClassifier;
}
}
}
Check.isTrue(ServiceConstants.SEGMENT_EPACKAGE.equals(modelType),
"Excepted uri segment of eclass, eclassifier or epackage but found " + modelType); //$NON-NLS-1$
final String id = (String) getServiceContext().getRequestParameters().get(ServiceConstants.MODEL_ID_PARAMETER);
Check.isNotNull(id, "id parameter should be set when retrieving an epackage"); //$NON-NLS-1$
return ModelUtils.getEPackageFromNameUriOrPrefix(id);
}
protected ResponseType getResponse(List<Object> objects, int startRow, int endRow, long totalRows) {
final ResponseType responseType = ResponseModelPackage.INSTANCE.getModelFactory().createResponseType();
responseType.setEndRow(endRow);
responseType.setStartRow(startRow);
responseType.setTotalRows(totalRows);
responseType.setStatus(ServiceConstants.STATUS_SUCCESS);
responseType.setData(objects);
return responseType;
}
private boolean doCount(QueryType queryType, int maxResults, int firstResult) {
// if there is no limit on the max results and there is no first row then don't count
if (getMaxResults() == -1 && getFirstResult() == -1) {
return false;
}
final String noCountParam = (String) getServiceContext().getRequestParameters()
.get(ServiceConstants.PARAM_NO_COUNT);
return noCountParam == null || FALSE.equals(noCountParam);
}
}