/*
* Copyright (C) 2011 Artur Suilin
* 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 ru.metrika4j.impl;
import ru.metrika4j.*;
import ru.metrika4j.entity.*;
import ru.metrika4j.error.NoDataException;
import ru.metrika4j.error.ServerException;
import ru.metrika4j.http.HttpMethod;
import ru.metrika4j.http.HttpTransport;
import ru.metrika4j.json.JsonMapper;
import ru.metrika4j.json.JsonObject;
import java.lang.reflect.Array;
import java.util.Arrays;
public class MetrikaApiImpl implements MetrikaApi, ApiContext {
private final HttpTransport transport;
private final JsonMapper mapper;
private final GoalApi goalApi = new GoalApiImpl();
private final FilterApi filterApi = new FilterApiImpl();
private final OperationApi operationApi = new OperationApiImpl();
private final GrantApi grantApi = new GrantApiImpl();
private final DelegateApi delegateApi = new DelegateApiImpl();
private final AccountApi accountApi = new AccountApiImpl();
public MetrikaApiImpl(HttpTransport transport, JsonMapper mapper) {
this.transport = transport;
this.mapper = mapper;
}
private class QueryBuilder<T> {
private final String path;
private final String objectName;
private final Class<T> clazz;
private String query;
private HttpMethod httpMethod = HttpMethod.GET;
private String input;
private QueryBuilder(String path, Class<T> clazz, String objectName) {
this.path = path;
this.objectName = objectName;
this.clazz = clazz;
}
QueryBuilder<T> withQuery(String query) {
this.query = query;
return this;
}
QueryBuilder<T> withQueryParam(String name, String value) {
if (query == null) {
query = "";
}
query += name + "=" + value;
return this;
}
QueryBuilder<T> withMethod(HttpMethod httpMethod) {
this.httpMethod = httpMethod;
return this;
}
QueryBuilder<T> withInput(String input) {
this.input = input;
return this;
}
T get() {
String url = path + ".json";
if (query != null) {
url = url + "?" + query;
}
JsonObject responseNode = getResponseByPath(url, httpMethod, input);
if (clazz.isArray()) {
JsonObject[] objects = responseNode.getObjectArray(objectName);
Object[] result = (Object[]) Array.newInstance(clazz.getComponentType(), objects.length);
for (int i = 0; i < objects.length; i++) {
result[i] = mapper.jsonObjectToEntity(objects[i], clazz.getComponentType());
}
//noinspection unchecked
return (T) result;
} else {
JsonObject objectNode = responseNode.getObjectField(objectName);
return mapper.jsonObjectToEntity(objectNode, clazz);
}
}
}
<T> QueryBuilder<T> q(String path, Class<T> clazz, String objectName) {
return new QueryBuilder<T>(path, clazz, objectName);
}
private String makeCounterFields(CounterDetails... details) {
if (details.length > 0) {
String params = details[0].name();
for (int i = 1; i < details.length; i++) {
params = params + "," + details[i].name();
}
return "field=" + params;
} else {
return null;
}
}
public Counter[] getCounters(CounterDetails... details) {
return q("/counters", Counter[].class, "counters").withQuery(makeCounterFields(details)).get();
}
public Counter getCounter(int id, CounterDetails... details) {
return q("/counter/" + id, Counter.class, "counter").withQuery(makeCounterFields(details)).get();
}
public ReportBuilder makeReportBuilder(Reports report, int counterId) {
return new ReportBuilderImpl(report.url, counterId, this);
}
public JsonObject getResponseByUrl(String url) {
return getResponseByUrl(url, HttpMethod.GET, null);
}
public JsonObject getResponseByUrl(String url, HttpMethod method, String input) {
String content = transport.doRequest(url, method, input);
JsonObject result = mapper.stringToJsonObject(content);
JsonObject[] jsonErrors = result.getObjectArray("errors");
if (jsonErrors != null) {
MetrikaError errors[] = new MetrikaError[jsonErrors.length];
for (int i = 0; i < errors.length; i++) {
errors[i] = mapper.jsonObjectToEntity(jsonErrors[i], MetrikaError.class);
}
for (MetrikaError error : errors) {
if ("ERR_NO_DATA".equals(error.getCode())) {
throw new NoDataException(Arrays.asList(jsonErrors).toString(), errors);
}
}
throw new ServerException(Arrays.asList(jsonErrors).toString(), errors);
}
return result;
}
private String convertObjectToJson(Object obj) {
return mapper.entityToString(obj);
}
public Counter createCounter(Counter newCounter) {
String fields = makeCounterFields(CounterDetails.values());
String body = convertObjectToJson(newCounter);
return q("/counters", Counter.class, "counter").withQuery(fields)
.withMethod(HttpMethod.POST)
.withInput(body)
.get();
}
public Counter updateCounter(Counter counter) {
String fields = makeCounterFields(CounterDetails.values());
String body = convertObjectToJson(counter);
return q("/counter/" + counter.getId(), Counter.class, "counter").withQuery(fields)
.withMethod(HttpMethod.PUT)
.withInput(body)
.get();
}
public void deleteCounter(int id) {
q("/counter/" + id, Counter.class, "counter").withMethod(HttpMethod.DELETE).get();
}
public JsonObject getResponseByPath(String path) {
return getResponseByPath(path, HttpMethod.GET, null);
}
public JsonObject getResponseByPath(String path, HttpMethod method, String input) {
return getResponseByUrl("http://api-metrika.yandex.ru" + path, method, input);
}
public GoalApi getGoalApi() {
return goalApi;
}
public FilterApi getFilterApi() {
return filterApi;
}
public OperationApi getOperationApi() {
return operationApi;
}
public GrantApi getGrantApi() {
return grantApi;
}
public DelegateApi getDelegateApi() {
return delegateApi;
}
public AccountApi getAccountApi() {
return accountApi;
}
private class EntityApiImpl<T extends Entity<K>, K> implements EntityApi<T, K> {
private final Class<T> entityClass;
private final Class<T[]> entityArrayClass;
private final String entityName;
private final String entityPlural;
public EntityApiImpl(Class<T> entityClass, Class<T[]> entityArrayClass, String entityName) {
this.entityClass = entityClass;
this.entityArrayClass = entityArrayClass;
this.entityName = entityName;
entityPlural = entityName + "s";
}
private String path(int counterId, String entityId) {
return String.format("/counter/%d/%s/%s", counterId, entityName, entityId);
}
private String pluralPath(int counterId) {
return String.format("/counter/%d/%s", counterId, entityPlural);
}
public T[] getEntities(int counterId) {
return q(pluralPath(counterId), entityArrayClass, entityPlural).get();
}
public T getEntity(int counterId, K entityId) {
return q(path(counterId, entityId.toString()), entityClass, entityName).get();
}
public T createEntity(int counterId, T source) {
String body = convertObjectToJson(source);
return q(pluralPath(counterId), entityClass, entityName).withMethod(HttpMethod.POST).withInput(body).get();
}
public T updateEntity(int counterId, T entity) {
String body = "{'" + entityName + "':" + convertObjectToJson(entity) + "}";
return q(path(counterId, entity.getId().toString()), entityClass, entityName).withMethod(HttpMethod.PUT)
.withInput(body)
.get();
}
public void deleteEntity(int counterId, K entityId) {
q(path(counterId, entityId.toString()), entityClass, entityName).withMethod(HttpMethod.DELETE).get();
}
}
private class GoalApiImpl extends EntityApiImpl<Goal, Integer> implements GoalApi {
public GoalApiImpl() {
super(Goal.class, Goal[].class, "goal");
}
}
private class FilterApiImpl extends EntityApiImpl<Filter, Integer> implements FilterApi {
public FilterApiImpl() {
super(Filter.class, Filter[].class, "filter");
}
}
private class OperationApiImpl extends EntityApiImpl<Operation, Integer> implements OperationApi {
public OperationApiImpl() {
super(Operation.class, Operation[].class, "operation");
}
}
private class GrantApiImpl implements GrantApi {
private final EntityApi<Grant, String> entityApi = new MetrikaApiImpl.EntityApiImpl<Grant, String>(Grant.class,
Grant[].class, "grant");
public Grant[] getGrants(int counterId) {
return entityApi.getEntities(counterId);
}
public Grant getGrant(int counterId, String userLogin) {
return entityApi.getEntity(counterId, userLogin);
}
public Grant createGrant(int counterId, Grant.Permission permission, String userLogin, String comment) {
return entityApi.createEntity(counterId, new Grant(userLogin, permission, comment));
}
public Grant changeGrant(int counterId, Grant.Permission permission, String userLogin, String comment,
boolean removeComment) {
return entityApi.updateEntity(counterId,
new GrantRemoveComment(userLogin, permission, comment, removeComment));
}
public void deleteGrant(int counterId, String userLogin) {
entityApi.deleteEntity(counterId, userLogin);
}
private class GrantRemoveComment extends Grant {
private boolean commentRemove;
GrantRemoveComment(String userLogin, Permission perm, String comment, boolean commentRemove) {
super(userLogin, perm, comment);
this.commentRemove = commentRemove;
}
public boolean isCommentRemove() {
return commentRemove;
}
public void setCommentRemove(boolean commentRemove) {
this.commentRemove = commentRemove;
}
}
}
private class AccountApiImpl implements AccountApi {
public Account[] getAccounts() {
return q("/accounts", Account[].class, "accounts").get();
}
public void deleteAccount(String user_login) {
q("/account/" + user_login, Delegate.class, "delegate").withMethod(HttpMethod.DELETE).get();
}
public Account[] updateAccounts(Account[] accountList) {
String body = "{'accounts':" + convertObjectToJson(accountList) + "}";
return q("/accounts", Account[].class, "accounts").withMethod(HttpMethod.PUT).withInput(body).get();
}
}
private class DelegateApiImpl implements DelegateApi {
public Delegate[] getDelegates() {
return q("/delegates", Delegate[].class, "delegates").get();
}
public Delegate[] addDelegate(String userLogin, String comment) {
String body = "{'delegate':" + convertObjectToJson(new Delegate(userLogin, comment)) + "}";
return q("/delegates", Delegate[].class, "delegates").withMethod(HttpMethod.POST).withInput(body).get();
}
public Delegate[] updateDelegateList(Delegate[] delegates) {
String body = "{'delegates':" + convertObjectToJson(delegates) + "}";
return q("/delegates", Delegate[].class, "delegates").withMethod(HttpMethod.PUT).withInput(body).get();
}
public void deleteDelegate(String userLogin) {
q("/delegate/" + userLogin, Delegate.class, "delegate").withMethod(HttpMethod.DELETE).get();
}
}
}