/** * */ package xapi.server.model; import xapi.io.X_IO; import xapi.jre.model.ModelServiceJre; import xapi.log.X_Log; import xapi.model.X_Model; import xapi.model.api.Model; import xapi.model.api.ModelKey; import xapi.model.api.ModelManifest; import xapi.model.api.ModelModule; import xapi.model.api.ModelQuery; import xapi.model.api.ModelQueryResult; import xapi.model.api.PrimitiveSerializer; import xapi.model.service.ModelService; import xapi.source.api.CharIterator; import xapi.source.impl.StringCharIterator; import xapi.time.X_Time; import xapi.util.X_Properties; import xapi.util.X_String; import xapi.util.api.Pointer; import xapi.util.api.RemovalHandler; import xapi.util.api.SuccessHandler; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.URLDecoder; /** * @author James X. Nelson (james@wetheinter.net, @james) * */ public class ModelPersistServlet extends HttpServlet { private static final long serialVersionUID = -8873779568305155795L; protected ServletContext context; /** * @see javax.servlet.GenericServlet#init(javax.servlet.ServletConfig) */ @Override public void init(final ServletConfig config) throws ServletException { context = config.getServletContext(); final String modules = X_Properties.getProperty("gwt.modules"); if (modules != null) { for (String module : modules.split("\\s+")) { module = module.trim(); if (!module.isEmpty()) { final String moduleName = module; ModelModuleLoader.get().preloadModule(context, moduleName); } } } } @SuppressWarnings("unchecked") @Override protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException { final String moduleName = req.getHeader("X-Gwt-Module"); final ModelModule module = ModelModuleLoader.get().loadModule(context, moduleName); final RemovalHandler handler = ModelServiceJre.registerModule(module); try { final String encoding = X_String.firstNotEmpty(req.getCharacterEncoding(), "UTF-8"); final String[] keySections = URLDecoder.decode(req.getRequestURI(), encoding).split("/"); final String requestType = keySections[keySections.length-4]; final PrimitiveSerializer primitives = X_Model.getService().primitiveSerializer(); String namespace = keySections[keySections.length-3]; namespace = primitives.deserializeString(new StringCharIterator(namespace)); String kind = keySections[keySections.length-2]; final CharIterator ident = new StringCharIterator(keySections[keySections.length-1]); if (requestType.equals("query")) { kind = primitives.deserializeString(new StringCharIterator(kind)); runQuery(resp, module, primitives, namespace, kind, ident, encoding); return; } final String type = req.getHeader("X-Model-Type"); final ModelManifest manifest = module.getManifest(type); final int keyType = primitives.deserializeInt(ident); final String id = ident.consumeAll().toString(); final ModelKey key = X_Model.newKey(namespace, kind, id).setKeyType(keyType); final Pointer<Boolean> wait = new Pointer<>(true); final Class<Model> modelType = (Class<Model>) manifest.getModelType(); X_Model.load(modelType, key, new SuccessHandler<Model>() { @Override public void onSuccess(final Model m) { final String serialized = X_Model.serialize(manifest, m); try { X_IO.drain(resp.getOutputStream(), X_IO.toStream(serialized, encoding)); wait.set(false); } catch (final Exception e) { X_Log.error(getClass(), "Error saving model",e); } } }); blockUntilTrue(wait, key); } finally { handler.remove(); } } private void blockUntilTrue(final Pointer<Boolean> wait, final Object debugInfo) { final long deadline = System.currentTimeMillis() + 5000; while (wait.get()) { X_Time.trySleep(30, 0); if (X_Time.isPast(deadline)) { X_Log.error(getClass(), "Timeout while loading model(s)",debugInfo); return; } } } protected void runQuery(final HttpServletResponse resp, final ModelModule module, final PrimitiveSerializer primitives, final String namespace, final String kind, final CharIterator queryString, final String encoding) { final ModelService service = X_Model.getService(); final ModelQuery query = ModelQuery.deserialize(service, primitives, queryString); final Pointer<Boolean> wait = new Pointer<>(true); final SuccessHandler callback = new SuccessHandler<ModelQueryResult>() { @Override public void onSuccess(final ModelQueryResult t) { try { final String serialized = t.serialize(service, primitives); X_IO.drain(resp.getOutputStream(), X_IO.toStream(serialized, encoding)); wait.set(false); } catch (final Exception e) { X_Log.error(getClass(), "Error saving model",e); } } }; if ("".equals(kind)) { service.query(query, callback); } else { final Class<? extends Model> modelClass = service.typeToClass(kind); service.query(modelClass, query, callback); } blockUntilTrue(wait, query); } @Override protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException { final String asString = X_IO.toStringUtf8(req.getInputStream()); final String type = req.getHeader("X-Model-Type"); final String moduleName = req.getHeader("X-Gwt-Module"); final ModelModule module = ModelModuleLoader.get().loadModule(context, moduleName); final RemovalHandler handler = ModelServiceJre.registerModule(module); try { final ModelManifest manifest = module.getManifest(type); final Model model; try { model = X_Model.deserialize(manifest, asString); } catch (final Throwable e) { String moduleText, manifestText; try { moduleText = ModelModule.serialize(module); } catch (final Throwable e1) { moduleText = String.valueOf(module); } try { manifestText = ModelManifest.serialize(manifest); } catch (final Throwable e1) { manifestText = String.valueOf(manifest); } X_Log.error(getClass(), "Error trying to deserialize model; ",e,"source: ","|"+asString+"|" , "\nManifest: ","|"+manifestText+"|" , "\nModule: ","|"+moduleText+"|"); throw new ServletException(e); } final Pointer<Boolean> wait = new Pointer<>(true); X_Model.persist(model, new SuccessHandler<Model>() { @Override public void onSuccess(final Model m) { final String serialized = X_Model.serialize(manifest, m); try { X_IO.drain(resp.getOutputStream(), X_IO.toStreamUtf8(serialized)); wait.set(false); } catch (final Exception e) { X_Log.error(getClass(), "Error saving model",e); } } }); final long deadline = System.currentTimeMillis() + 5000; while (wait.get()) { X_Time.trySleep(30, 0); if (X_Time.isPast(deadline)) { X_Log.error(getClass(), "Timeout while saving model",model); return; } } } finally { handler.remove(); } } }