/**
*
* Copyright (C) norad.fr
*
* 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 net.awired.ajsl.web.service.implementation;
import java.io.File;
import java.io.FileFilter;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.awired.ajsl.core.io.FileFlatTree;
import net.awired.ajsl.core.io.PathFileFilter;
import net.awired.ajsl.core.io.PathFileOrder;
import net.awired.ajsl.core.lang.StringUtils;
import net.awired.ajsl.web.domain.JsServiceMap;
import net.awired.ajsl.web.service.interfaces.JsService;
import net.awired.ajsl.web.service.interfaces.JsonService;
import org.apache.commons.lang.NotImplementedException;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ContextFactory;
import org.mozilla.javascript.ErrorReporter;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObjectUtils;
import org.mozilla.javascript.Undefined;
import org.mozilla.javascript.tools.ToolErrorReporter;
import org.mozilla.javascript.tools.shell.Global;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import com.yahoo.platform.yui.compressor.JavaScriptCompressor;
@Service
public class JsServiceImpl implements JsService {
private static final Logger LOG = LoggerFactory.getLogger(JsServiceImpl.class);
private static final String JS_DIRECTORY = "js";
@Autowired
private ApplicationContext context;
@Autowired
private JsonService jsonService;
@Override
public String getJsLinks(String prefix) throws Exception {
return getJsLinks(prefix, getJsFiles());
}
@Override
public String getJsLinks(String prefix, Map<File, String> jsMap) throws Exception {
StringBuilder result = new StringBuilder();
for (File file : jsMap.keySet()) {
// type="text/javascript"
result.append("<script src=\"");
result.append(prefix);
result.append(jsMap.get(file));
result.append("\"></script>\n");
}
return result.toString();
}
@Override
public JsServiceMap buildServiceMapFromJsMap(Map<File, String> jsMap) {
JsServiceMap jsServiceMap = new JsServiceMap();
Pattern pattern = Pattern.compile("[\\.]*([A-Za-z0-9\\-]*)\\.js");
// Pattern className = Pattern.compile("\\/([A-Za-z\\.]*)\\.js");
Pattern className = Pattern.compile("([^/]*)\\.js");
for (File file : jsMap.keySet()) {
String webPath = jsMap.get(file);
Matcher m = pattern.matcher(webPath);
m.find();
String beanName = m.group(1);
Matcher classNameMatcher = className.matcher(webPath);
classNameMatcher.find();
String res = classNameMatcher.group(1);
jsServiceMap.addService(beanName, res);
}
return jsServiceMap;
}
@Override
public String buildJsServiceMapString(JsServiceMap jsServiceMap) {
StringWriter writer = new StringWriter();
jsonService.serialize(jsServiceMap, writer);
return writer.toString();
}
@Override
public Map<String, List<String>> getServicesMethods(Map<File, String> jsFiles,
Map<String, List<String>> serviceMap) throws Exception {
Global global = new Global();
Context cx = ContextFactory.getGlobal().enter();
global.init(cx);
cx.setOptimizationLevel(-1);
cx.setLanguageVersion(Context.VERSION_1_5);
Scriptable scope = cx.initStandardObjects(global);
cx.evaluateReader(scope,
new InputStreamReader(getClass().getClassLoader().getResourceAsStream("env.rhino.1.2.js")),
"env.rhino.js", 1, null);
// import js files to interpreter
for (File jsFile : jsFiles.keySet()) {
FileReader reader = new FileReader(jsFile);
cx.evaluateReader(scope, reader, jsFiles.get(jsFile), 1, null);
}
Map<String, List<String>> result = new HashMap<String, List<String>>();
for (String serviceName : serviceMap.keySet()) {
List<String> value = new ArrayList<String>();
result.put(serviceName, value);
for (String className : serviceMap.get(serviceName)) {
Object o1 = cx.evaluateReader(scope, new StringReader("window." + className), "classReader", 1, null);
if (o1 instanceof Undefined) {
LOG.warn("js class file " + className + " found but class not found in context");
continue;
}
String[] stringTable = ScriptableObjectUtils.getMethodArrayFromJsObject(o1);
for (String element : stringTable) {
if (element.charAt(0) != '_') {
value.add(element);
}
}
}
}
return result;
}
@Override
public Map<File, String> getJsFiles() throws Exception {
Resource res = context.getResource(JS_DIRECTORY);
File file = res.getFile();
PathFileFilter pathfilter = new PathFileFilter();
pathfilter.setGlobalFilter(new FileFilter() {
@Override
public boolean accept(File pathname) {
if (pathname.isDirectory() && !pathname.getName().equals(".svn")) {
return true;
}
if (pathname.getName().endsWith(".js")) {
return true;
}
return false;
}
});
PathFileOrder pathOrder = new PathFileOrder();
pathOrder.setGlobalOrder(new Comparator<File>() {
@Override
public int compare(File o1, File o2) {
long o1l = o1.getName().length();
long o2l = o2.getName().length();
if (o1l == o2l) {
return 0;
}
if (o1l < o2l) {
return -1;
}
return 1;
}
});
pathOrder.addFileOrder("js", new Comparator<File>() {
List<String> order = new ArrayList<String>();
{
order.add("jquery");
order.add("ajsl");
order.add("visuwall");
}
@Override
public int compare(File o1, File o2) {
int o1pos = order.indexOf(o1.getName());
int o2pos = order.indexOf(o2.getName());
if (o1pos == -1 && o2pos != -1) {
return 1;
}
if (o1pos != -1 && o2pos == -1) {
return -1;
}
if (o1pos != -1 && o2pos != -1) {
if (o1pos > o2pos) {
return 1;
}
return -1;
}
return o1.compareTo(o2);
}
});
Map<File, String> jsFiles = FileFlatTree.getTree(file, JS_DIRECTORY, pathfilter, pathOrder);
return jsFiles;
}
@Override
public String getJsData() throws Exception {
Map<File, String> jsFiles = this.getJsFiles();
StringBuilder builder = new StringBuilder();
for (File file2 : jsFiles.keySet()) {
FileReader reader = new FileReader(file2);
StringUtils.inputStreamReaderToStringBuilder(reader, builder);
}
Reader reader = new StringReader(builder.toString());
StringWriter writer = new StringWriter();
ErrorReporter reporter = new ToolErrorReporter(true);
JavaScriptCompressor compressor = new JavaScriptCompressor(reader,
reporter);
compressor.compress(writer, -1, true, true, false, false);
return writer.toString();
}
}