/*
* Copyright 2009 NCHOVY
*
* 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 org.krakenapps.http.internal;
import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import org.apache.felix.ipojo.ComponentInstance;
import org.apache.felix.ipojo.ConfigurationException;
import org.apache.felix.ipojo.Factory;
import org.apache.felix.ipojo.IPojoFactory;
import org.apache.felix.ipojo.InstanceManager;
import org.apache.felix.ipojo.MissingHandlerException;
import org.apache.felix.ipojo.UnacceptableConfiguration;
import org.apache.felix.ipojo.architecture.Architecture;
import org.krakenapps.api.Script;
import org.krakenapps.api.ScriptArgument;
import org.krakenapps.api.ScriptContext;
import org.krakenapps.api.ScriptUsage;
import org.krakenapps.http.BundleHttpContext;
import org.krakenapps.http.FilesystemHttpContext;
import org.krakenapps.http.HttpServiceManager;
import org.krakenapps.http.KrakenHttpService;
import org.krakenapps.http.ServletLifecycleManager;
import org.krakenapps.http.FileUploadService;
import org.krakenapps.http.UploadToken;
import org.krakenapps.http.UploadedFile;
import org.krakenapps.http.internal.context.ServletContextImpl;
import org.krakenapps.http.internal.handler.ServletHandler;
import org.krakenapps.http.internal.service.ResourceServlet;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.http.HttpContext;
import org.osgi.service.http.NamespaceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HttpScript implements Script {
private Logger logger = LoggerFactory.getLogger(HttpScript.class);
private ScriptContext context;
private BundleContext bc;
private HttpServiceManager manager;
private FileUploadService upload;
public HttpScript(BundleContext bundleContext, HttpServiceManager manager, FileUploadService upload) {
this.bc = bundleContext;
this.manager = manager;
this.upload = upload;
}
@Override
public void setScriptContext(ScriptContext context) {
this.context = context;
}
@ScriptUsage(description = "set upload token", arguments = {
@ScriptArgument(name = "token", type = "string", description = "upload token guid"),
@ScriptArgument(name = "space id", type = "string", description = "the space id"),
@ScriptArgument(name = "file name", type = "string", description = "original file name"),
@ScriptArgument(name = "file size", type = "int", description = "original file size") })
public void setUploadToken(String[] args) {
UploadTokenImpl token = new UploadTokenImpl();
token.token = args[0];
token.spaceId = args[1];
token.fileName = args[2];
token.fileSize = Long.parseLong(args[3]);
try {
int resourceId = upload.setUploadToken(token, null);
context.println("new resource id = " + resourceId);
} catch (IllegalStateException e) {
context.println("upload token already exists");
}
}
@ScriptUsage(description = "set download token and associated spaces", arguments = {
@ScriptArgument(name = "token", type = "string", description = "download token"),
@ScriptArgument(name = "spaces", type = "string", description = "one or more space identifiers") })
public void setDownloadToken(String[] args) {
String token = args[0];
List<String> spaces = Arrays.asList(Arrays.copyOfRange(args, 1, args.length));
try {
upload.setDownloadToken(token, spaces);
context.println("download token added");
} catch (IllegalStateException e) {
context.println("download token already exists");
}
}
@ScriptUsage(description = "delete uploaded file", arguments = {
@ScriptArgument(name = "space id", type = "string", description = "the space id"),
@ScriptArgument(name = "resource id", type = "string", description = "the resource id") })
public void deleteFile(String[] args) {
try {
String spaceId = args[0];
int resourceId = Integer.parseInt(args[1]);
upload.deleteFile(spaceId, resourceId);
context.println("file deleted");
} catch (Exception e) {
context.println("error: " + e.getMessage());
}
}
private static class UploadTokenImpl implements UploadToken {
public String token;
public String spaceId;
public String fileName;
public long fileSize;
@Override
public String getToken() {
return token;
}
@Override
public String getSpaceId() {
return spaceId;
}
@Override
public String getFileName() {
return fileName;
}
@Override
public long getFileSize() {
return fileSize;
}
}
@ScriptUsage(description = "list all upload files in space", arguments = { @ScriptArgument(name = "space id", type = "string", description = "space id") })
public void listFiles(String[] args) {
String spaceId = args[0];
context.println("Uploaded Files");
context.println("--------------------");
for (UploadedFile f : upload.getFiles(spaceId)) {
context.println(f.toString());
}
}
@ScriptUsage(description = "list all iPOJO servlet factories")
public void servletFactories(String[] args) {
try {
ServiceReference[] refs = bc.getServiceReferences(Factory.class.getName(), null);
for (ServiceReference ref : refs) {
Factory factory = (Factory) bc.getService(ref);
if (isServletFactory(factory)) {
context.println(ref.getProperty("factory.name").toString());
}
}
} catch (InvalidSyntaxException e) {
// ignore
}
}
@ScriptUsage(description = "list all registered servlets. Usage: servlets [filter string]")
public void servlets(String[] args) {
String nameFilter = null;
if (args.length > 0)
nameFilter = args[0];
try {
ServiceReference[] refs = bc.getServiceReferences(Servlet.class.getName(), null);
context.println("Servlet Components");
context.println("==================");
if (refs == null)
return;
for (ServiceReference ref : refs) {
String instanceName = (String) ref.getProperty("instance.name");
if (nameFilter != null) {
if (!instanceName.contains(nameFilter))
continue;
}
context.println(instanceName);
}
} catch (InvalidSyntaxException e) {
// ignore
}
}
private boolean isServletFactory(Factory factory) {
String[] interfaces = factory.getComponentDescription().getprovidedServiceSpecification();
for (String inf : interfaces) {
if (inf.equals(Servlet.class.getName()))
return true;
}
return false;
}
private KrakenHttpService findHttpService(String httpServiceName) {
try {
String serviceNameFilter = "(httpservice.name=" + httpServiceName + ")";
String interfaceName = KrakenHttpService.class.getName();
ServiceReference[] refs = bc.getServiceReferences(interfaceName, serviceNameFilter);
if (refs == null) {
context.printf("http service [%s] not found\n", httpServiceName);
return null;
}
return (KrakenHttpService) bc.getService(refs[0]);
} catch (InvalidSyntaxException e) {
return null;
}
}
@ScriptUsage(description = "register upload servlet", arguments = {
@ScriptArgument(name = "http service name", type = "string", description = "the name of http service"),
@ScriptArgument(name = "path", type = "string", description = "url path") })
public void registerUploadServlet(String[] args) {
try {
String httpServiceName = args[0];
String path = args[1];
KrakenHttpService httpService = findHttpService(httpServiceName);
if (httpService == null) {
context.println("http service not found: " + httpServiceName);
return;
}
ServiceReference ref = bc.getServiceReference(FileUploadService.class.getName());
FileUploadServlet upload = (FileUploadServlet) bc.getService(ref);
httpService.registerServlet(path, upload, null, null);
context.println("upload servlet registered");
} catch (Exception e) {
context.println(e.getMessage());
}
}
@ScriptUsage(description = "create servlet and register it", arguments = {
@ScriptArgument(name = "http service name"), @ScriptArgument(name = "servlet factory name"),
@ScriptArgument(name = "servlet alias") })
public void createServlet(String[] args) {
ComponentInstance servletInstance = null;
try {
String httpServiceName = args[0];
String factoryName = args[1];
String alias = args[2];
KrakenHttpService httpService = findHttpService(httpServiceName);
if (httpService == null) {
context.println("http service not found: " + httpServiceName);
return;
}
String factoryNameFilter = "(factory.name=" + factoryName + ")";
ServiceReference[] refs = bc.getServiceReferences(Factory.class.getName(), factoryNameFilter);
if (refs == null) {
context.println("factory not found");
return;
}
Factory factory = (Factory) bc.getService(refs[0]);
servletInstance = factory.createComponentInstance(null);
servletInstance.start();
Servlet servlet = (Servlet) ((InstanceManager) servletInstance).getPojoObject();
// register servlet to http service
httpService.registerServlet(alias, servlet, null, null);
ServletLifecycleManager slm = getServletLifecycleManager();
if (slm != null) {
slm.registerServlet(httpService, alias, servletInstance);
} else {
context.println("warning: ServletLifecycleManager instance doesn't exists");
}
// to avoid exception handling routine
servletInstance = null;
} catch (InvalidSyntaxException e) {
context.println("invalid ldap filter exception");
} catch (UnacceptableConfiguration e) {
context.println("iPOJO unacceptable configuration exception: " + e.toString());
} catch (MissingHandlerException e) {
context.println("iPOJO missing handler exception: " + e.toString());
} catch (ConfigurationException e) {
context.println("iPOJO configuration exception: " + e.toString());
} catch (ServletException e) {
context.println("servlet exception: " + e.toString());
} catch (NamespaceException e) {
context.println("namespace exception: " + e.toString());
} finally {
if (servletInstance != null) {
System.err.println("trying to dispose orphaned servlet instance..(" + servletInstance.getInstanceName()
+ ")");
servletInstance.stop();
servletInstance.dispose();
}
}
}
private ServletLifecycleManager getServletLifecycleManager() {
ServiceReference svcRef = bc.getServiceReference(ServletLifecycleManager.class.getName());
if (svcRef == null)
return null;
else
return (ServletLifecycleManager) bc.getService(svcRef);
}
@ScriptUsage(description = "unregister servlet and remove it", arguments = {
@ScriptArgument(name = "http service name", type = "string", description = "the name of the http service component instance"),
@ScriptArgument(name = "servlet name", type = "string", description = "the name of servlet component instance") })
public void removeServlet(String[] args) {
String httpServiceName = args[0];
String servletName = args[1];
try {
// find http service
KrakenHttpService httpService = findHttpService(httpServiceName);
if (httpService == null) {
context.println("http service not found: " + httpServiceName);
return;
}
// find servlet
String instanceNameFilter = "(instance.name=" + servletName + ")";
ServiceReference[] refs = bc.getServiceReferences(Servlet.class.getName(), instanceNameFilter);
if (refs == null) {
context.println("servlet not found: " + servletName);
return;
}
Servlet servlet = (Servlet) bc.getService(refs[0]);
// unregister servlet
httpService.unregisterServlet(servlet);
// remove servlet
removeServletInstance(servletName);
} catch (InvalidSyntaxException e) {
// ignore
}
}
private void removeServletInstance(String servletName) throws InvalidSyntaxException {
ServiceReference[] archRefs = bc.getServiceReferences(Architecture.class.getName(), "(architecture.instance="
+ servletName + ")");
if (archRefs == null || archRefs.length == 0)
return;
Architecture arch = (Architecture) bc.getService(archRefs[0]);
IPojoFactory iPojoFactory = arch.getInstanceDescription().getComponentDescription().getFactory();
iPojoFactory.deleted(servletName);
}
@ScriptUsage(description = "list all http/https services")
public void list(String[] args) {
context.println("HTTP Service List");
context.println("=================");
for (String httpServiceName : manager.getHttpServiceList()) {
context.println(httpServiceName + "'s contexts:");
Map<String, String> config = manager.getConfig(httpServiceName);
if (config != null) {
context.println("\tConfigs:");
for (Entry<String, String> entry : config.entrySet()) {
context.printf("\t\t%s: %s\n", entry.getKey(), entry.getValue());
}
}
KrakenHttpService httpService = findHttpService(httpServiceName);
ServletHandler[] servlets = httpService.servlets();
for (ServletHandler servletHandler : servlets) {
context.println("\t" + servletHandler.toString());
try {
Servlet servlet = servletHandler.getServlet();
if (servlet instanceof ResourceServlet) {
ResourceServlet rs = (ResourceServlet) servlet;
ServletContextImpl servletContext = (ServletContextImpl) rs.getServletContext();
HttpContext httpContext = servletContext.getHttpContext();
if (httpContext instanceof FilesystemHttpContext) {
FilesystemHttpContext fhc = (FilesystemHttpContext) httpContext;
context.println("\t\tbasePath = " + fhc.getResourceBase());
}
}
} catch (Exception e) {
context.println("exception occured. refer to logfile");
}
}
}
}
@ScriptUsage(description = "open a new http service", arguments = { @ScriptArgument(name = "server name"),
@ScriptArgument(name = "port", type = "integer") })
public void open(String[] args) {
String serverName = args[0];
int port = Integer.parseInt(args[1]);
if (port < 0 || port > 65535) {
context.println("port out of range");
return;
}
Map<String, String> config = new HashMap<String, String>();
config.put("ssl", "false");
config.put("port", Integer.toString(port));
try {
manager.openHttpService(serverName, config);
context.println(port + " http service opened.");
} catch (Exception e) {
context.println(e.toString());
logger.warn("kraken-http: open failed. " + e);
}
}
@ScriptUsage(description = "open a new https service")
public void openSsl(String[] args) {
try {
context.println(System.getProperty("user.dir"));
context.print("Server ID: ");
String serverName = context.readLine();
context.print("Port: ");
String port = context.readLine();
int p = Integer.parseInt(port); // check number
if (p < 0 || p > 65535) {
context.println("port out of range");
return;
}
context.print("Resource Base: ");
String resourceBase = context.readLine();
context.print("KeyStore: ");
String keyStore = context.readLine();
context.print("Truststore: ");
String trustStore = context.readLine();
context.turnEchoOff();
context.print("Password: ");
String password = context.readLine();
context.print("KeyPassword: ");
String keyPassword = context.readLine();
context.print("TrustPassword: ");
String trustPassword = context.readLine();
Map<String, String> config = new HashMap<String, String>();
config.put("ssl", "true");
config.put("port", port);
config.put("resourceBase", resourceBase);
config.put("keyStore", System.getProperty("user.dir") + File.separatorChar + keyStore);
config.put("trustStore", System.getProperty("user.dir") + File.separatorChar + trustStore);
config.put("password", password);
config.put("keyPassword", keyPassword);
config.put("trustPassword", trustPassword);
try {
// create server with config
manager.openHttpService(serverName, config);
context.println(port + " https service opened.");
} catch (Exception e) {
context.println(e.toString());
logger.warn("kraken-http: open failed. " + e);
}
} catch (InterruptedException e) {
} catch (NumberFormatException e) {
}
}
@ScriptUsage(description = "close the http server", arguments = { @ScriptArgument(name = "name", type = "string", description = "http server name") })
public void close(String[] args) {
try {
String httpServiceName = args[0];
manager.closeHttpService(httpServiceName);
context.printf("[%s] service closed.\n", httpServiceName);
} catch (Exception e) {
context.println(e.getMessage());
}
}
@ScriptUsage(description = "add filesystem resources", arguments = { @ScriptArgument(name = "http service name"),
@ScriptArgument(name = "alias"), @ScriptArgument(name = "base path") })
public void addFilesystemResources(String[] args) {
String httpServiceName = args[0];
String alias = args[1];
String basePath = args[2];
KrakenHttpService httpService = findHttpService(httpServiceName);
if (httpService == null) {
context.println("http service not found");
return;
}
try {
httpService.registerResources(alias, "", new FilesystemHttpContext(basePath));
context.printf("base path [%s] is registered to alias [%s]\n", basePath, alias);
} catch (NamespaceException e) {
context.println("failed to register resources: " + e.toString());
}
}
@ScriptUsage(description = "add bundle resources", arguments = {
@ScriptArgument(name = "http service name", type = "string", description = "http service name"),
@ScriptArgument(name = "alias", type = "string", description = "servlet alias"),
@ScriptArgument(name = "resource name", type = "string", description = "resource path"),
@ScriptArgument(name = "bundle id", type = "int") })
public void addBundleResources(String[] args) {
try {
String httpServiceName = args[0];
String alias = args[1];
String resourceName = args[2];
long bundleId = Long.parseLong(args[3]);
Bundle bundle = bc.getBundle(bundleId);
KrakenHttpService httpService = findHttpService(httpServiceName);
if (httpService == null) {
context.println("http service not found.");
return;
}
httpService.registerResources(alias, resourceName, new BundleHttpContext(bundle));
context.printf("resource name [%s] in bundle [%d] is registered to alias [%s]\n", resourceName, bundleId,
alias);
} catch (Exception e) {
context.println(e.toString());
}
}
}