/*
* 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.tester;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystems;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.musicmount.io.file.FileResource;
import org.musicmount.server.MusicMountServer;
import org.musicmount.server.MusicMountServerJetty;
import org.musicmount.server.MusicMountServer.AccessLog;
import org.musicmount.server.MusicMountServer.FolderContext;
public class MusicMountTester {
protected static final Logger LOGGER = Logger.getLogger(MusicMountTester.class.getName());
public static final AccessLog LOGGER_ACCESS_LOG = new AccessLog() {
@Override
public void log(AccessLog.Entry entry) {
if (LOGGER.isLoggable(Level.FINE)) {
StringBuilder builder = new StringBuilder();
String uri = entry.getRequestURI();
try {
uri = URLDecoder.decode(uri, StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
// should not happen
}
final int methodAndURIFormatLength = 39; // magic... log line length = 100
int maxURILength = methodAndURIFormatLength - 1 - entry.getRequestMethod().length();
if (uri.length() > maxURILength) {
uri = "..." + uri.substring(uri.length() - maxURILength + 3);
}
String methodAndURI = String.format("%s %s", entry.getRequestMethod(), uri);
builder.append(String.format(String.format("%%-%ds", methodAndURIFormatLength), methodAndURI));
builder.append(String.format("%4d", entry.getResponseStatus()));
String contentLengthHeader = entry.getResponseHeader("Content-Length");
if (contentLengthHeader != null) {
builder.append(String.format(Locale.ENGLISH, "%,11dB", Long.valueOf(contentLengthHeader)));
} else {
builder.append(" ");
}
builder.append(String.format(Locale.ENGLISH, "%,7dms", entry.getResponseTimestamp() - entry.getRequestTimestamp()));
LOGGER.log(Level.FINE, builder.toString());
}
}
};
private final MusicMountServer engine;
public MusicMountTester() {
this(new MusicMountServerJetty(LOGGER_ACCESS_LOG));
}
public MusicMountTester(MusicMountServer engine) {
this.engine = engine;
}
public void start(
FileResource musicFolder,
FileResource mountFolder,
String musicPath,
int port,
final String user,
final String password) throws Exception {
if (!checkMusicPath(musicPath)) {
throw new IllegalArgumentException("Unsupported music path");
}
FolderContext musicContext = new FolderContext(musicContextPath(musicPath), musicFolder.getPath().toFile());
FolderContext mountContext = new FolderContext(mountContextPath(musicPath), mountFolder.getPath().toFile());
LOGGER.info("Starting Server...");
LOGGER.info("Music folder: " + musicFolder.getPath());
LOGGER.info("Mount folder: " + mountFolder.getPath());
LOGGER.info("Music path : " + musicPath);
engine.start(musicContext, mountContext, port, user, password);
LOGGER.info(String.format("Mount Settings"));
LOGGER.info(String.format("--------------"));
LOGGER.info(String.format("Site: %s", getSiteURL(getHostName("<hostName>"), port, musicPath)));
if (user != null) {
LOGGER.info(String.format("User: %s", user));
LOGGER.info(String.format("Pass: %s", "<not logged>"));
}
LOGGER.info(String.format("--------------"));
LOGGER.info("Done.");
}
public void await() {
engine.await();
}
public boolean isStarted() {
return engine.isStarted();
}
public void stop() throws Exception {
LOGGER.info("Stopping Server...");
engine.stop();
LOGGER.info("Done.");
}
private int upLevels(String[] segments) {
int upLevels = 0;
while (segments[upLevels].equals("..")) {
if (++upLevels == segments.length) {
break;
}
}
return upLevels;
}
String normalizeMusicPath(String musicPath) {
musicPath = musicPath.trim();
musicPath = musicPath.replace(FileSystems.getDefault().getSeparator(), "/");
musicPath = musicPath.replaceAll("/+", "/");
musicPath = musicPath.replaceAll("/\\./", "/");
musicPath = musicPath.replaceAll("^\\./|/\\.$", "");
if (musicPath.endsWith("/")) {
musicPath = musicPath.substring(0, musicPath.length() - 1);
}
return musicPath;
}
public boolean checkMusicPath(String musicPath) {
if (musicPath == null || musicPath.trim().isEmpty()) {
return false;
}
musicPath = normalizeMusicPath(musicPath);
String[] segments = musicPath.split("/");
int downStartIndex = upLevels(segments);
if (downStartIndex == segments.length) {
return false;
}
for (int i = downStartIndex; i < segments.length; i++) {
if (segments[i].equals("..")) {
return false;
}
}
return true;
}
protected String musicContextPath(String musicPath) {
musicPath = normalizeMusicPath(musicPath);
if (musicPath.startsWith("../")) { // up-down-path, e.g. "../../../music" -> "/music"
return musicPath.substring(3 * upLevels(musicPath.split("/")) - 1);
} else if (musicPath.startsWith("/")) { // absolute path, e.g. "/music" -> "/music"
return musicPath;
} else { // down-path, e.g. "music"
return "/musicmount/" + musicPath;
}
}
protected String mountContextPath(String musicPath) {
musicPath = normalizeMusicPath(musicPath);
int upLevels = upLevels(musicPath.split("/"));
StringBuilder builder = new StringBuilder("/musicmount");
for (int i = 1; i < upLevels; i++) {
builder.append("/").append(i + 1);
}
return builder.toString();
}
public String getHostName(String defaultName) {
try {
return InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
return defaultName;
}
}
public String getSitePath(String musicPath) {
if (!checkMusicPath(musicPath)) {
return null;
}
return String.format("%s/index.json", mountContextPath(musicPath));
}
public URL getSiteURL(String hostName, int port, String musicPath) throws MalformedURLException {
if (port == 80) {
return new URL("http", hostName, getSitePath(musicPath));
} else {
return new URL("http", hostName, port, getSitePath(musicPath));
}
}
}