content: /**
   *  Copyright (c) 2013-2016 Angelo ZERR.
   *  All rights reserved. This program and the accompanying materials
   *  are made available under the terms of the Eclipse Public License v1.0
   *  which accompanies this distribution, and is available at
   *  http://www.eclipse.org/legal/epl-v10.html
   *
   *  Contributors:
   *  Angelo Zerr <angelo.zerr@gmail.com> - initial API and implementation
   */
  package tern.server.j2v8;
  
  import java.io.IOException;
  import java.util.List;
  
  import com.eclipsesource.json.Json;
  import com.eclipsesource.json.JsonObject;
  import com.eclipsesource.v8.V8;
  
  import tern.ITernProject;
  import tern.TernException;
  import tern.server.AbstractScriptEngineTernServer;
  import tern.server.IResponseHandler;
  import tern.server.protocol.IJSONObjectHelper;
  import tern.server.protocol.MinimalJSONHelper;
  import tern.server.protocol.TernDoc;
  import tern.server.protocol.html.ScriptTagRegion;
  import tern.utils.IOUtils;
  
  /**
   * Tern server implemented with J2V8
   * 
   */
  public class J2V8TernServer extends AbstractScriptEngineTernServer {
  
  	private V8 v8;
  
  	public J2V8TernServer(ITernProject project) {
  		super(project);
  	}
  
  	@Override
  	public void addFile(String name, String text, ScriptTagRegion[] tags) {
  		TernDoc doc = new TernDoc();
  		doc.addFile(name, text, tags, null);
  		try {
  			request(doc);
  		} catch (TernException e) {
  			e.printStackTrace();
  		}
  	}
  
  	@Override
  	public void request(TernDoc doc, IResponseHandler handler) {
  		try {
  			JsonObject data = request(doc);
  			handler.onSuccess(data, null);
  		} catch (Exception e) {
  			handler.onError(e.getMessage(), e);
  		}
  	}
  
  	private synchronized JsonObject request(TernDoc doc) throws TernException {
  		V8 v8 = getV8();
  		try {
  			v8.getLocker().acquire();
  			String script = new StringBuilder("server.request(")
  					.append(doc.toString()).append(");").toString();
  			String json = v8.executeStringScript(script);
  			return Json.parse(json).asObject();
  		} catch (Throwable e) {
  			throw new TernException(e);
  		} finally {
  			v8.getLocker().release();
  		}
  	}
  
  	@Override
  	public IJSONObjectHelper getJSONObjectHelper() {
  		return MinimalJSONHelper.INSTANCE;
  	}
  
  	@Override
  	protected void doDispose() {
  		if (v8 != null) {
  			try {
  				v8.getLocker().acquire();
  				v8.release();
  				if (V8.getActiveRuntimes() != 0) {
  					throw new IllegalStateException(
  							"V8Runtimes not properly released.");
  				}
  			} finally {
  				v8 = null;
  			}
  		}
  		fireEndServer();
  	}
  
  	public void log(String message, Integer level) {
  		if (level == 1) {
  			System.err.println(message);
  		} else {
  			System.out.println(message);
  		}
  	}
  
  	private synchronized V8 getV8() throws TernException {
  		if (v8 == null) {
  			v8 = loadV8();
  		}
  		return v8;
  	}
  
  	private V8 loadV8() throws TernException {
  		V8 v8 = null;
  		TernResources resources = loadTern();
  		try {
  			v8 = V8.createV8Runtime();
  			v8.getLocker().acquire();
  
  			// Load tern scripts (acorn + ternjs) + plugins scripts
  			List<TernResource> scripts = resources.getScripts();
  			for (TernResource script : scripts) {
  				v8.executeScript(script.getContent(), script.getFilename(), 0);
  			}
  			// Get defs
  			String defs = resources.getDefsAsString();
  
  			v8.registerJavaMethod(this, "log", "_javaConsole", new Class<?>[] {
  					String.class, Integer.class });
  			v8.executeScript(IOUtils.toString(J2V8TernServer.class
  					.getResourceAsStream("tern-j2v8.js")), "tern-j2v8.js", 0);
  
  			StringBuilder script = new StringBuilder(
  					"var server = new J2V8TernServer(");
  			script.append("[");
  			script.append(defs.toString());
  			script.append("],");
  			script.append(getProject().getPlugins() != null ? getProject()
  					.getPlugins().toString() : "");
  			script.append(");");
  			v8.executeScript(script.toString());
  			return v8;
  		} catch (IOException e) {
  			throw new TernException(e);
  		} finally {
  			if (v8 != null) {
  				v8.getLocker().release();
  			}
  		}
  	}
  
  }
  