/**
* 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.deephacks.confit.jaxrs;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import org.deephacks.confit.admin.AdminContext;
import org.deephacks.confit.admin.query.BeanQuery;
import org.deephacks.confit.admin.query.BeanQueryBuilder.BeanRestriction;
import org.deephacks.confit.admin.query.BeanQueryResult;
import org.deephacks.confit.internal.jaxrs.JaxrsBeans;
import org.deephacks.confit.internal.jaxrs.JaxrsBeans.JaxrsBean;
import org.deephacks.confit.internal.jaxrs.JaxrsConfigEndpoint;
import org.deephacks.confit.internal.jaxrs.JaxrsObjects;
import org.deephacks.confit.internal.jaxrs.JaxrsObjects.JaxrsObject;
import org.deephacks.confit.internal.jaxrs.JaxrsQuery;
import org.deephacks.confit.internal.jaxrs.JaxrsSchemas;
import org.deephacks.confit.internal.jaxrs.JaxrsSchemas.JaxrsSchema;
import org.deephacks.confit.model.AbortRuntimeException;
import org.deephacks.confit.model.Bean;
import org.deephacks.confit.model.BeanId;
import org.deephacks.confit.model.Events;
import org.deephacks.confit.model.Schema;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriBuilder;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE;
/**
* JAX-RS version of AdminContext that allow accessing configuration in a type-safe way
* without explicitly using HTTP or JAX-RS APIs.
*/
public class AdminContextJaxrsProxy extends AdminContext {
private final Client client;
private final String host;
private final int port;
private final String prefixUri;
private final AdminContext admin = AdminContext.lookup();
private AdminContextJaxrsProxy(String host, int port, String prefixUri) {
client = ClientBuilder.newBuilder().build();
this.host = host;
this.port = port;
this.prefixUri = prefixUri;
}
public static AdminContextJaxrsProxy get(String host, int port) {
return new AdminContextJaxrsProxy(host, port, "");
}
public static AdminContextJaxrsProxy get(String host, int port, String uriPrefix) {
return new AdminContextJaxrsProxy(host, port, uriPrefix);
}
@Override
public Optional<Bean> get(BeanId beanId) throws AbortRuntimeException {
UriBuilder builder = getUri("getBean");
URI uri = builder.build(beanId.getSchemaName(), beanId.getInstanceId());
Response response = get(uri);
try {
if (response.getStatus() == Status.NOT_FOUND.getStatusCode()) {
return Optional.absent();
}
handleReadResponse(response);
JaxrsBean jaxrsBean = response.readEntity(JaxrsBean.class);
Optional<Schema> schema = admin.getSchema(beanId.getSchemaName());
if (!schema.isPresent()) {
throw Events.CFG101_SCHEMA_NOT_EXIST(beanId.getSchemaName());
}
return Optional.of(jaxrsBean.toBean(schema.get()));
} finally {
response.close();
}
}
@Override
public <T> Optional<T> get(Class<T> configurable) throws AbortRuntimeException {
UriBuilder builder = getUri("getSingleton");
URI uri = builder.build(configurable.getName());
Response response = get(uri);
try {
if (response.getStatus() == Status.NOT_FOUND.getStatusCode()) {
return Optional.absent();
}
handleReadResponse(response);
JaxrsObject jaxrsObject = response.readEntity(JaxrsObject.class);
return Optional.of((T) jaxrsObject.toObject());
} finally {
response.close();
}
}
@Override
public <T> Optional<T> get(Class<T> configurable, String instanceId) throws AbortRuntimeException {
UriBuilder builder = getUri("getObject");
URI uri = builder.build(configurable.getName(), instanceId);
Response response = get(uri);
try {
if (response.getStatus() == Status.NOT_FOUND.getStatusCode()) {
return Optional.absent();
}
handleReadResponse(response);
JaxrsObject jaxrsObject = response.readEntity(JaxrsObject.class);
return Optional.of((T) jaxrsObject.toObject());
} finally {
response.close();
}
}
@Override
public List<Bean> list(String schemaName) throws AbortRuntimeException {
UriBuilder builder = getUri("listBean");
URI uri = builder.build(schemaName);
Response response = get(uri);
try {
if (response.getStatus() == Status.NOT_FOUND.getStatusCode()) {
throw Events.CFG101_SCHEMA_NOT_EXIST(schemaName);
}
handleReadResponse(response);
JaxrsBeans jaxrsBeans = response.readEntity(JaxrsBeans.class);
Map<String, Schema> schemas = admin.getSchemas();
return jaxrsBeans.toBeans(schemas);
} finally {
response.close();
}
}
@Override
public <T> Collection<T> list(Class<T> configurable) throws AbortRuntimeException {
UriBuilder builder = getUri("listObjects");
URI uri = builder.build(configurable.getName());
Response response = get(uri);
try {
if (response.getStatus() == Status.NOT_FOUND.getStatusCode()) {
throw Events.CFG101_SCHEMA_NOT_EXIST(configurable.getName());
}
handleReadResponse(response);
JaxrsObjects objects = response.readEntity(JaxrsObjects.class);
return (Collection<T>) objects.toObjects();
} finally {
response.close();
}
}
@Override
public List<Bean> list(String schemaName, Collection<String> instanceIds) throws AbortRuntimeException {
UriBuilder builder = getUri("listBeans");
URI uri = builder.queryParam("id", instanceIds.toArray(new String[instanceIds.size()])).build(schemaName);
Response response = get(uri);
try {
if (response.getStatus() == Status.NOT_FOUND.getStatusCode()) {
throw Events.CFG90_SCHEMA_OR_ID_NOT_EXIST();
}
handleReadResponse(response);
JaxrsBeans beans = response.readEntity(JaxrsBeans.class);
Map<String, Schema> schemas = admin.getSchemas();
return beans.toBeans(schemas);
} finally {
response.close();
}
}
@Override
public void create(Bean bean) throws AbortRuntimeException {
URI uri = getUri("createBean").build();
Entity entity = Entity.entity(new JaxrsBean(bean), APPLICATION_JSON_TYPE);
Response response = post(uri, entity);
handleResponse(response);
}
@Override
public void createObject(Object object) throws AbortRuntimeException {
URI uri = getUri("createObject").build();
Entity entity = Entity.entity(new JaxrsObject(object), APPLICATION_JSON_TYPE);
Response response = post(uri, entity);
handleResponse(response);
}
@Override
public void create(Collection<Bean> beans) throws AbortRuntimeException {
URI uri = getUri("createBeans").build();
JaxrsBeans jaxrsBeans = new JaxrsBeans();
jaxrsBeans.addAll(beans);
Entity entity = Entity.entity(jaxrsBeans, APPLICATION_JSON_TYPE);
Response response = post(uri, entity);
handleResponse(response);
}
@Override
public void createObjects(Collection<?> objects) throws AbortRuntimeException {
URI uri = getUri("createObjects").build();
JaxrsObjects jaxrsObjects = new JaxrsObjects();
jaxrsObjects.addAll(objects);
Entity entity = Entity.entity(jaxrsObjects, APPLICATION_JSON_TYPE);
Response response = post(uri, entity);
handleResponse(response);
}
@Override
public void set(Bean bean) throws AbortRuntimeException {
URI uri = getUri("setBean").build();
Entity entity = Entity.entity(new JaxrsBean(bean), APPLICATION_JSON_TYPE);
Response response = post(uri, entity);
handleResponse(response);
}
@Override
public void setObject(Object object) throws AbortRuntimeException {
URI uri = getUri("setObject").build();
Entity entity = Entity.entity(new JaxrsObject(object), APPLICATION_JSON_TYPE);
Response response = post(uri, entity);
handleResponse(response);
}
@Override
public void set(Collection<Bean> beans) throws AbortRuntimeException {
URI uri = getUri("setBeans").build();
JaxrsBeans jaxrsBeans = new JaxrsBeans();
jaxrsBeans.addAll(beans);
Entity entity = Entity.entity(jaxrsBeans, APPLICATION_JSON_TYPE);
Response response = post(uri, entity);
handleResponse(response);
}
@Override
public void setObjects(Collection<?> objects) throws AbortRuntimeException {
URI uri = getUri("setObjects").build();
JaxrsObjects jaxrsObjects = new JaxrsObjects();
jaxrsObjects.addAll(objects);
Entity entity = Entity.entity(jaxrsObjects, APPLICATION_JSON_TYPE);
Response response = post(uri, entity);
handleResponse(response);
}
@Override
public void merge(Bean bean) throws AbortRuntimeException {
URI uri = getUri("mergeBean").build();
Entity entity = Entity.entity(new JaxrsBean(bean), APPLICATION_JSON_TYPE);
Response response = post(uri, entity);
handleResponse(response);
}
@Override
public void mergeObject(Object object) throws AbortRuntimeException {
URI uri = getUri("mergeObject").build();
Entity entity = Entity.entity(new JaxrsObject(object), APPLICATION_JSON_TYPE);
Response response = post(uri, entity);
handleResponse(response);
}
@Override
public void merge(Collection<Bean> beans) throws AbortRuntimeException {
URI uri = getUri("mergeBeans").build();
JaxrsBeans jaxrsBeans = new JaxrsBeans();
jaxrsBeans.addAll(beans);
Entity entity = Entity.entity(jaxrsBeans, APPLICATION_JSON_TYPE);
Response response = post(uri, entity);
handleResponse(response);
}
@Override
public void mergeObjects(Collection<?> objects) throws AbortRuntimeException {
URI uri = getUri("mergeObjects").build();
JaxrsObjects jaxrsObjects = new JaxrsObjects();
jaxrsObjects.addAll(objects);
Entity entity = Entity.entity(jaxrsObjects, APPLICATION_JSON_TYPE);
Response response = post(uri, entity);
handleResponse(response);
}
@Override
public void delete(BeanId bean) throws AbortRuntimeException {
UriBuilder builder = getUri("deleteBean");
URI uri = builder.build(bean.getSchemaName(), bean.getInstanceId());
Response response = delete(uri);
handleResponse(response);
}
@Override
public void delete(String schemaName, Collection<String> instanceIds) throws AbortRuntimeException {
UriBuilder builder = getUri("deleteBeans");
URI uri = builder.queryParam("id", instanceIds.toArray(new String[instanceIds.size()])).build(schemaName);
Response response = delete(uri);
handleResponse(response);
}
@Override
public void deleteObject(Object instance) throws AbortRuntimeException {
throw new UnsupportedOperationException("not implemented yet");
}
@Override
public void deleteObjects(Class<?> configurable, Collection<String> instanceIds) throws AbortRuntimeException {
throw new UnsupportedOperationException("not implemented yet");
}
@Override
public Map<String, Schema> getSchemas() {
URI uri = getUri("getSchemas").build();
Response response = get(uri);
try {
handleReadResponse(response);
JaxrsSchemas schemas = response.readEntity(JaxrsSchemas.class);
return schemas.toSchema();
} finally {
response.close();
}
}
@Override
public Optional<Schema> getSchema(String schemaName) {
URI uri = getUri("getSchema").build(schemaName);
Response response = get(uri);
try {
if (response.getStatus() == Status.NOT_FOUND.getStatusCode()) {
return Optional.absent();
}
handleReadResponse(response);
JaxrsSchema jaxrsSchema = response.readEntity(JaxrsSchema.class);
return Optional.of(jaxrsSchema.toSchema());
} finally {
response.close();
}
}
@Override
public BeanQuery newQuery(final String schemaName) {
return new BeanQuery() {
private String first;
private int max = 0;
@Override
public BeanQuery add(BeanRestriction restriction) {
return null;
}
@Override
public BeanQuery setFirstResult(String firstResult) {
first = firstResult;
return this;
}
@Override
public BeanQuery setMaxResults(int maxResults) {
max = maxResults;
return this;
}
@Override
public BeanQueryResult retrieve() {
URI uri = getUri("query")
.queryParam("first", first)
.queryParam("max", max)
.build(schemaName);
JaxrsQuery query = new JaxrsQuery();
Response response = get(uri);
return new BeanQueryResult() {
@Override
public List<Bean> get() {
return new ArrayList<>();
}
@Override
public String nextFirstResult() {
return null;
}
};
}
};
}
private UriBuilder getUri(String method) {
if (Strings.isNullOrEmpty(prefixUri)) {
return UriBuilder.fromResource(JaxrsConfigEndpoint.class)
.scheme("http")
.path(JaxrsConfigEndpoint.class, method)
.host(host)
.port(port);
} else {
return UriBuilder.fromPath(prefixUri).path(JaxrsConfigEndpoint.class)
.scheme("http")
.path(JaxrsConfigEndpoint.class, method)
.host(host)
.port(port);
}
}
private Response get(URI uri) {
return client.target(uri).request().buildGet().invoke();
}
private Response post(URI uri, Entity<?> entity) {
return client.target(uri).request().buildPost(entity).invoke();
}
private Response delete(URI uri) {
return client.target(uri).request().buildDelete().invoke();
}
private void handleResponse(Response response) {
try {
if (response.getStatus() == Status.NOT_FOUND.getStatusCode()) {
throw Events.CFG90_SCHEMA_OR_ID_NOT_EXIST();
} else if (response.getStatus() == Status.CONFLICT.getStatusCode()) {
throw Events.CFG303_BEAN_ALREADY_EXIST();
} else if (response.getStatus() == Status.FORBIDDEN.getStatusCode()) {
throw Events.CFG089_MODIFICATION_CONFLICT();
} else if (response.getStatus() == Status.BAD_REQUEST.getStatusCode()) {
throw Events.CFG088_INVALID_DATA();
} else if (response.getStatus() == Status.INTERNAL_SERVER_ERROR.getStatusCode()) {
throw Events.CFG088_INVALID_DATA();
}
} finally {
response.close();
}
}
private void handleReadResponse(Response response) {
if (response.getStatus() == Status.NOT_FOUND.getStatusCode()) {
response.close();
throw Events.CFG90_SCHEMA_OR_ID_NOT_EXIST();
} else if (response.getStatus() == Status.CONFLICT.getStatusCode()) {
response.close();
throw Events.CFG303_BEAN_ALREADY_EXIST();
} else if (response.getStatus() == Status.FORBIDDEN.getStatusCode()) {
response.close();
throw Events.CFG089_MODIFICATION_CONFLICT();
} else if (response.getStatus() == Status.BAD_REQUEST.getStatusCode()) {
response.close();
throw Events.CFG088_INVALID_DATA();
} else if (response.getStatus() == Status.INTERNAL_SERVER_ERROR.getStatusCode()) {
response.close();
throw Events.CFG088_INVALID_DATA();
}
}
}