Java tutorial
/** * Personium * Copyright 2014 - 2018 FUJITSU LIMITED * * 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 io.personium.engine; import io.personium.client.utils.PersoniumLoggerFactory; import io.personium.common.utils.PersoniumCoreUtils; import io.personium.engine.adapter.PersoniumEngineDao; import io.personium.engine.adapter.PersoniumRequestBodyStream; import io.personium.engine.adapter.Require; import io.personium.engine.extension.support.AbstractExtensionScriptableObject; import io.personium.engine.extension.support.ExtensionJarLoader; import io.personium.engine.extension.support.ExtensionLogger; import io.personium.engine.extension.support.IExtensionLogger; import io.personium.engine.extension.support.JavaClassRevealFilter; import io.personium.engine.jsgi.JSGIRequest; import io.personium.engine.jsgi.PersoniumResponse; import io.personium.engine.source.ISourceManager; import io.personium.engine.utils.PersoniumEngineConfig; import io.personium.engine.utils.PersoniumEngineLoggerFactory; import java.io.Closeable; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.Method; import java.net.URL; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Response; import org.apache.http.HttpStatus; import org.mozilla.javascript.ContextFactory; import org.mozilla.javascript.Function; import org.mozilla.javascript.NativeObject; import org.mozilla.javascript.Script; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; import org.mozilla.javascript.WrappedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Personium-Engine?. */ public class PersoniumEngineContext implements Closeable { /** . */ private static Logger log = LoggerFactory.getLogger(PersoniumEngineContext.class); private static final String PERSONIUM_SCOPE = "_p"; private static final String EXTENSION_SCOPE = "extension"; private static Map<String, Script> engineLibCache = new ConcurrentHashMap<String, Script>(); /** Cell??. */ private String currentCellName; /** Box??. */ private String currentBoxName; /** URI. */ private String currentSchemeUri; /** Rhino?Context. */ private org.mozilla.javascript.Context cx; /** Rhino?ContextFactory. */ private PersoniumJsContextFactory factory; /** Rhino?Scope. */ private Scriptable scope; /** URL. */ private String baseUrl; /** ?. */ private ISourceManager sourceManager; static { ContextFactory.initGlobal(new PersoniumJsContextFactory()); } /** * . * @throws PersoniumEngineException PersoniumEngine */ public PersoniumEngineContext() throws PersoniumEngineException { // Rhino??? this.factory = new PersoniumJsContextFactory(); this.cx = factory.enterContext(); this.scope = cx.initStandardObjects(); } /** * Extension JavaScript??. * ??? Extension??? * @throws PersoniumEngineException */ private void prepareExtensionClass() throws PersoniumEngineException { // Extension jar? ExtensionJarLoader extLoader = null; try { extLoader = ExtensionJarLoader.getInstance(this.cx.getApplicationClassLoader(), new JavaClassRevealFilter()); factory.initApplicationClassLoader(extLoader.getClassLoader()); } catch (IOException e) { throw new PersoniumEngineException("Server Error", PersoniumEngineException.STATUSCODE_SERVER_ERROR, e); } catch (PersoniumEngineException e) { throw e; } // Javascript?????? Java? // ? NativeObject pScope = (NativeObject) this.scope.get(PERSONIUM_SCOPE, this.scope); NativeObject declaringClass = (NativeObject) pScope.get(EXTENSION_SCOPE, pScope); for (Class<? extends Scriptable> clazz : extLoader.getPrototypeClassSet()) { try { if (AbstractExtensionScriptableObject.class.isAssignableFrom(clazz)) { // AbstractExtensionScriptableObject????? @SuppressWarnings("unchecked") Class<? extends AbstractExtensionScriptableObject> extensionClazz = (Class<? extends AbstractExtensionScriptableObject>) clazz; // Extension???? // ?????????????????????) try { Method setLoggerMethod = extensionClazz.getMethod("setLogger", new Class[] { Class.class, IExtensionLogger.class }); setLoggerMethod.setAccessible(true); setLoggerMethod.invoke(null, new Object[] { extensionClazz, new ExtensionLogger(extensionClazz) }); } catch (Exception e) { log.info("setLogger method cannot be called.", e); } } // ############################################################################3 // ????????????? extension?????? // ??? extension????? UserScript??????????????????????? // ???????Script??? // ############################################################################3 ScriptableObject.defineClass(declaringClass, clazz); } catch (RuntimeException e) { log.warn(String.format("Warn: Extension class(%s) could not be revealed to javascript.: %s", clazz.getCanonicalName(), e.getMessage())); } catch (Exception e) { log.warn(String.format("Warn: Extension class(%s) could not be revealed to javascript.: %s", clazz.getCanonicalName(), e.getMessage())); } } } /** * ?. * @param value the ISourceManager */ public final void setSourceManager(final ISourceManager value) { this.sourceManager = value; } /** * ?. ??????????????setter????? * @param url URL * @param cell Cell?? * @param schema URI * @param box Box?? * @param service ?? */ public final void loadGlobalObject(final String url, final String cell, final String schema, final String box, final String service) { this.baseUrl = url; this.currentCellName = cell; this.currentBoxName = box; this.currentSchemeUri = schema; } /** * JSGI. * @param source ? * @param req Request * @param res Response * @param is * @param serviceSubject * @return Response * @throws PersoniumEngineException PersoniumEngine */ public final Response runJsgi(final String source, final HttpServletRequest req, final HttpServletResponse res, final InputStream is, final String serviceSubject) throws PersoniumEngineException { // JSGI // DAO? PersoniumEngineDao ed = createDao(req, serviceSubject); // DAOJavaScript? javaToJs(ed, "pjvm"); // RequireJavaScript? javaToJs(createRequireObject(), "_require"); // personium-dao.js ?? try { loadJs("personium-dao"); } catch (IOException e1) { log.info("runJsgi error (DAO load io error) ", e1); throw new PersoniumEngineException("Server Error", PersoniumEngineException.STATUSCODE_SERVER_ERROR, e1); } // personium-lib.js ?? try { loadJs("personium-lib"); } catch (IOException e1) { log.info("runJsgi error (personium-lib load io error) ", e1); throw new PersoniumEngineException("Server Error", PersoniumEngineException.STATUSCODE_SERVER_ERROR, e1); } // jsgi-lib.js?? try { loadJs("jsgi-lib"); } catch (IOException e1) { log.info("runJsgi error (jsgi-lib load io error) ", e1); throw new PersoniumEngineException("Server Error", PersoniumEngineException.STATUSCODE_SERVER_ERROR, e1); } // p?????Extension?? prepareExtensionClass(); // RequestJavaScript? JSGIRequest jsReq = new JSGIRequest(req, new PersoniumRequestBodyStream(is)); // JSGI // (eval)? try { Object ret; log.info("eval user script : script size = " + source.length()); ret = evalUserScript(source, jsReq); log.info("[" + PersoniumEngineConfig.getVersion() + "] " + "<<< Request Ended "); PersoniumResponse pRes = PersoniumResponse.parseJsgiResponse(ret); return pRes.build(); } catch (Error e) { // ??INFO? log.info("UserScript TimeOut", e); throw new PersoniumEngineException("Script TimeOut", HttpStatus.SC_SERVICE_UNAVAILABLE); } catch (Exception e) { if (e instanceof WrappedException) { e = (Exception) ((WrappedException) e).getWrappedException(); } // ???INFO? log.info("User Script Evalucation Error : " + e.getMessage(), e); throw new PersoniumEngineException("Server Error : " + e.getMessage(), PersoniumEngineException.STATUSCODE_SERVER_ERROR, e); } } /** * UserScript. * @param source * @throws IOException IO * @throws PersoniumEngineException */ private Object evalUserScript(final String source, JSGIRequest jsReq) throws PersoniumEngineException { cx.evaluateString(scope, "fn_jsgi = " + source, null, 1, null); Object fObj = scope.get("fn_jsgi", scope); Object result = null; if (!(fObj instanceof Function)) { log.warn("fn_jsgi not found"); throw new PersoniumEngineException("Server Error", PersoniumEngineException.STATUSCODE_SERVER_ERROR); } Object[] functionArgs = { jsReq.getRequestObject() }; Function f = (Function) fObj; result = f.call(cx, scope, scope, functionArgs); return result; } /** * DAO?. * @param req Request * @param serviceSubject * @return DAO */ private PersoniumEngineDao createDao(final HttpServletRequest req, final String serviceSubject) { PersoniumEngineLoggerFactory engLogFactory = new PersoniumEngineLoggerFactory(); PersoniumLoggerFactory.setDefaultFactory(engLogFactory); PersoniumEngineDao pcx = new PersoniumEngineDao(baseUrl, currentCellName, currentSchemeUri, currentBoxName); pcx.setServiceSubject(serviceSubject); pcx.setBoxSchema(req.getHeader("X-Personium-Box-Schema")); String auth = req.getHeader(HttpHeaders.AUTHORIZATION); String version = req.getHeader(PersoniumEngineDao.PERSONIUM_VERSION); if (version != null && !(version.equals(""))) { pcx.setPersoniumVersion(version); } log.debug("auth : --------------------------------------------------------------------------"); log.debug(auth); if (auth != null && auth.length() > "Bearer".length()) { pcx.setClientToken(auth.substring("Bearer".length()).trim()); } // set defaultHeaders String requestKey = req.getHeader(PersoniumCoreUtils.HttpHeaders.X_PERSONIUM_REQUESTKEY); if (requestKey != null) { pcx.setDefaultHeader(PersoniumCoreUtils.HttpHeaders.X_PERSONIUM_REQUESTKEY, requestKey); } String eventId = req.getHeader(PersoniumCoreUtils.HttpHeaders.X_PERSONIUM_EVENTID); if (eventId != null) { pcx.setDefaultHeader(PersoniumCoreUtils.HttpHeaders.X_PERSONIUM_EVENTID, eventId); } String ruleChain = req.getHeader(PersoniumCoreUtils.HttpHeaders.X_PERSONIUM_RULECHAIN); if (ruleChain != null) { pcx.setDefaultHeader(PersoniumCoreUtils.HttpHeaders.X_PERSONIUM_RULECHAIN, ruleChain); } String via = req.getHeader(PersoniumCoreUtils.HttpHeaders.X_PERSONIUM_VIA); if (via != null) { pcx.setDefaultHeader(PersoniumCoreUtils.HttpHeaders.X_PERSONIUM_VIA, via); } return pcx; } /** * Require?. * @param localPath ? * @return ???Require */ private Require createRequireObject() { Require requireComp = new Require(this); requireComp.setSourceManager(this.sourceManager); log.debug("RequireObject created"); return requireComp; } /** * JavaScript????. * @param name JavaScript?? * @throws IOException IO */ private Object loadJs(final String name) throws IOException { URL path = getClass().getResource("/js-lib/" + name + ".js"); Script jsBuildObject = null; if (engineLibCache.containsKey(path.toString())) { jsBuildObject = engineLibCache.get(path.toString()); } else { FileInputStream fis = new FileInputStream(path.getFile()); InputStreamReader isr = new InputStreamReader(fis, "UTF-8"); jsBuildObject = cx.compileReader(isr, path.getPath(), 1, null); engineLibCache.put(path.toString(), jsBuildObject); } if (jsBuildObject == null) { return null; } Object ret = jsBuildObject.exec(cx, scope); log.debug("Load JavaScript from Local Resource : " + path); return ret; } /** * Java?JavaScript??. * @param obj Java * @param propertyName JavaScript??? */ private void javaToJs(final Object obj, final String propertyName) { log.debug("JavaObject to JavaScriptProperty " + propertyName); Object jObj = org.mozilla.javascript.Context.javaToJS(obj, scope); ScriptableObject.putProperty(scope, propertyName, jObj); } /** * JavaScript????. * @param source JavaScript? * @param path JavaScript?? * @return */ public Object requireJs(final String source, final String path) { Object ret = cx.evaluateString(scope, source, path, 1, null); log.debug("Load JavaScript from Require Resource : " + path); return ret; } @Override public void close() throws IOException { PersoniumJsContext.exit(); } }