/*
* Copyright 2013-2014 Odysseus Software GmbH
*
* 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.musicmount.server;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.security.ConstraintMapping;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.security.authentication.BasicAuthenticator;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.GzipHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.RequestLogHandler;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.security.Constraint;
import org.eclipse.jetty.util.security.Credential;
import org.musicmount.util.LoggingUtil;
public class MusicMountServerJetty implements MusicMountServer {
static final Logger LOGGER = Logger.getLogger(MusicMountServerJetty.class.getName());
static {
System.setProperty("embedded.jetty.daemon", "true");
LoggingUtil.configure("org.eclipse.jetty", Level.INFO);
}
class ConsoleRequestLog extends AbstractLifeCycle implements RequestLog {
@Override
public void log(final Request request, final Response response) {
if (accessLog != null) {
final long responseTimestamp = System.currentTimeMillis();
accessLog.log(new AccessLog.Entry() {
@Override
public long getResponseTimestamp() {
return responseTimestamp;
}
@Override
public int getResponseStatus() {
return response.getStatus();
}
@Override
public String getResponseHeader(String header) {
return response.getHeader(header);
}
@Override
public String getRequestURI() {
return request.getRequestURI();
}
@Override
public long getRequestTimestamp() {
return request.getTimeStamp();
}
@Override
public String getRequestMethod() {
return request.getMethod();
}
});
}
}
}
static final SecurityHandler basicAuthentication(String realm, String username, String password) {
HashLoginService loginService = new HashLoginService();
loginService.setName(realm);
loginService.putUser(username, Credential.getCredential(password), new String[]{"user"});
Constraint constraint = new Constraint();
constraint.setName(Constraint.__BASIC_AUTH);
constraint.setRoles(new String[]{"user"});
constraint.setAuthenticate(true);
ConstraintMapping constraintMapping = new ConstraintMapping();
constraintMapping.setConstraint(constraint);
constraintMapping.setPathSpec("/*");
ConstraintSecurityHandler constraintSecurityHandler = new ConstraintSecurityHandler();
constraintSecurityHandler.setAuthenticator(new BasicAuthenticator());
constraintSecurityHandler.setRealmName(realm);
constraintSecurityHandler.addConstraintMapping(constraintMapping);
constraintSecurityHandler.setLoginService(loginService);
return constraintSecurityHandler;
}
private Server server;
private final AccessLog accessLog;
public MusicMountServerJetty(AccessLog accessLog) {
this.accessLog = accessLog;
}
@Override
public void start(FolderContext music, FolderContext mount, int port, String user, String password) throws Exception {
ServletContextHandler mountContext = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
mountContext.setContextPath(mount.getPath());
mountContext.setSecurityHandler(user == null ? null : basicAuthentication("MusicMount", user, password));
mountContext.setBaseResource(Resource.newResource(mount.getFolder()));
mountContext.setWelcomeFiles(new String[] { "index.json" });
MimeTypes mountTypes = new MimeTypes();
mountTypes.addMimeMapping("json", MimeTypes.TEXT_JSON_UTF_8);
mountContext.setMimeTypes(mountTypes);
ServletHolder mountServlet = new ServletHolder(new DefaultServlet());
mountServlet.setInitParameter("dirAllowed", "false");
mountContext.addServlet(mountServlet, "/*");
ServletContextHandler musicContext = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
musicContext.setContextPath(music.getPath());
musicContext.setSecurityHandler(user == null ? null : basicAuthentication("MusicMount", user, password));
musicContext.setBaseResource(Resource.newResource(music.getFolder()));
MimeTypes musicTypes = new MimeTypes();
musicTypes.addMimeMapping("m4a", "audio/mp4");
musicTypes.addMimeMapping("mp3", "audio/mpeg");
musicContext.setMimeTypes(musicTypes);
ServletHolder musicServlet = new ServletHolder(new DefaultServlet());
musicServlet.setInitParameter("dirAllowed", "false");
musicContext.addServlet(musicServlet, "/*");
GzipHandler gzipMountContext = new GzipHandler();
gzipMountContext.setMimeTypes(MimeTypes.TEXT_JSON);
gzipMountContext.setHandler(mountContext);
ContextHandlerCollection contexHandlers = new ContextHandlerCollection();
contexHandlers.setHandlers(new Handler[] { gzipMountContext, musicContext });
RequestLogHandler requestLogHandler = new RequestLogHandler();
requestLogHandler.setRequestLog(new ConsoleRequestLog());
HandlerCollection handlers = new HandlerCollection();
handlers.setHandlers(new Handler[]{ contexHandlers, new DefaultHandler(), requestLogHandler });
server = new Server(port);
server.setHandler(handlers);
server.setGracefulShutdown(1000);
server.setStopAtShutdown(true);
server.start();
}
@Override
public void start(FolderContext music, MountContext mount, int port, String user, String password) throws Exception {
ServletContextHandler mountContext = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
mountContext.setContextPath(mount.getPath());
mountContext.setSecurityHandler(user == null ? null : basicAuthentication("MusicMount", user, password));
ServletHolder mountServlet = new ServletHolder(mount.getServlet());
mountContext.addServlet(mountServlet, "/*");
ServletContextHandler musicContext = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
musicContext.setContextPath(music.getPath());
musicContext.setSecurityHandler(user == null ? null : basicAuthentication("MusicMount", user, password));
musicContext.setBaseResource(Resource.newResource(music.getFolder()));
MimeTypes musicTypes = new MimeTypes();
musicTypes.addMimeMapping("m4a", "audio/mp4");
musicTypes.addMimeMapping("mp3", "audio/mpeg");
musicContext.setMimeTypes(musicTypes);
ServletHolder musicServlet = new ServletHolder(new DefaultServlet());
musicServlet.setInitParameter("dirAllowed", "false");
musicContext.addServlet(musicServlet, "/*");
GzipHandler gzipMountContext = new GzipHandler();
gzipMountContext.setMimeTypes(MimeTypes.TEXT_JSON);
gzipMountContext.setHandler(mountContext);
ContextHandlerCollection contexHandlers = new ContextHandlerCollection();
contexHandlers.setHandlers(new Handler[] { gzipMountContext, musicContext });
RequestLogHandler requestLogHandler = new RequestLogHandler();
requestLogHandler.setRequestLog(new ConsoleRequestLog());
HandlerCollection handlers = new HandlerCollection();
handlers.setHandlers(new Handler[]{ contexHandlers, new DefaultHandler(), requestLogHandler });
server = new Server(port);
server.setHandler(handlers);
server.setGracefulShutdown(1000);
server.setStopAtShutdown(true);
server.start();
}
@Override
public void await() {
try {
server.join();
} catch (InterruptedException e) {
LOGGER.info("Interruped...");
}
}
@Override
public boolean isStarted() {
return server != null && server.isStarted();
}
@Override
public void stop() throws Exception {
server.stop();
server.destroy();
server = null;
}
}