/*
* Copyright 2009 Alberto Gimeno <gimenete at gmail.com>
*
* 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 siena.remote;
import static siena.remote.Common.fillRequestElement;
import static siena.remote.Common.parseEntity;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import siena.ClassInfo;
import siena.Model;
import siena.Query;
import siena.SienaException;
import siena.Util;
public class RemoteStub {
private ClassLoader classLoader;
private Serializer serializer;
private String key;
public RemoteStub(Serializer serializer, ClassLoader classLoader) {
this.classLoader = classLoader;
this.serializer = serializer;
}
@SuppressWarnings("unchecked")
public Document process(Document doc) {
try {
Element root = doc.getRootElement();
if(key != null) {
// TODO: cutom exception message if time is null
long time = Long.parseLong(root.attributeValue("time"));
String hash = root.attributeValue("hash");
if(!Util.sha1(time+key).equals(hash)) {
throw new SienaException("Invalid hash");
}
long diff = Math.abs(time - System.currentTimeMillis());
if(diff > 10000) {
throw new SienaException("Invalid time");
}
}
String action = root.getName();
if("insert".equals(action)) {
Model obj = parseEntity(root, classLoader);
obj.insert();
return simpleResponse(obj, true);
} else if("update".equals(action)) {
parseEntity(root, classLoader).update();
} else if("delete".equals(action)) {
parseEntity(root, classLoader).delete();
} else if("get".equals(action)) {
Model obj = parseEntity(root, classLoader);
obj.get();
return simpleResponse(obj, false);
} else if("query".equals(action)) {
// TODO: convert document to QueryBase
String clazzName = root.attributeValue("class");
Class<? extends Model> clazz = (Class<? extends Model>) Common.classForName(clazzName, classLoader);
Query<? extends Model> query = Model.all(clazz);
List<Element> list = root.elements();
for (Element element : list) {
String name = element.getName();
String fieldName = element.attributeValue("field");
if("filter".equals(name)) {
// TODO: operator attribute
Field field = clazz.getField(fieldName);
Object value = null;
if(element.hasContent()) {
if(ClassInfo.isModel(field.getType())) {
value = Common.parseEntity(element, classLoader);
} else {
value = Util.fromString(field.getType(), element.getText());
}
}
query.filter(fieldName, value);
} else if("order".equals(name)) {
// TODO: ascending attribute
query.order(fieldName);
}
}
String limit = root.attributeValue("limit");
String offset = root.attributeValue("offset");
List<? extends Model> result = null;
if(limit != null && offset != null) {
result = query.fetch(Integer.parseInt(limit), Integer.parseInt(offset));
} else if(limit != null) {
result = query.fetch(Integer.parseInt(limit));
} else {
result = query.fetch();
}
Document response = DocumentHelper.createDocument();
Element r = response.addElement("result");
for (Model obj : result) {
Element object = r.addElement("object");
fillRequestElement(obj, object, false);
}
// TODO add nextOffset to response
return response;
}
} catch(Throwable e) {
return error(e);
}
return newDocument("ok");
}
private Document newDocument(String root) {
return DocumentHelper.createDocument().addElement(root).getDocument();
}
private Document simpleResponse(Model obj, boolean ids) {
Document response = newDocument("object");
fillRequestElement(obj, response.getRootElement(), ids);
return response;
}
private Document error(Throwable e) {
Document response = DocumentHelper.createDocument();
Element root = response.addElement("error");
root.addAttribute("class", e.getClass().getName());
root.setText(e.getMessage());
return response;
}
public void execute(InputStream in, OutputStream out) throws IOException {
Document request = serializer.deserialize(in);
Document response = process(request);
serializer.serialize(response, out);
}
public void setKey(String key) {
this.key = key;
}
}