/*
* 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.live;
import java.io.IOException;
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.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import org.musicmount.builder.MusicMountBuildConfig;
import org.musicmount.io.file.FileResource;
import org.musicmount.server.MusicMountServer;
import org.musicmount.server.MusicMountServer.AccessLog;
import org.musicmount.server.MusicMountServer.FolderContext;
import org.musicmount.server.MusicMountServer.MountContext;
import org.musicmount.server.MusicMountServerJetty;
import org.musicmount.util.LoggingProgressHandler;
import org.musicmount.util.ProgressHandler;
import org.musicmount.util.VersionUtil;
public class MusicMountLive {
protected static final Logger LOGGER = Logger.getLogger(MusicMountLive.class.getName());
/**
* prevent ImageIO from using file cache
*/
static {
ImageIO.setUseCache(false); // TODO not sure if this is really useful...
}
private static final String MOUNT_PATH = "/musicmount";
private static final String MUSIC_PATH = "/music";
/**
* API version string
*/
static final String API_VERSION = VersionUtil.getSpecificationVersion();
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 ProgressHandler progressHandler = new LoggingProgressHandler(LOGGER, Level.FINE);
private final MusicMountBuildConfig config;
private final MusicMountServer server;
private final LiveMountUpdater updater;
public MusicMountLive() {
this(new MusicMountBuildConfig());
}
public MusicMountLive(MusicMountBuildConfig config) {
this(config, new MusicMountServerJetty(LOGGER_ACCESS_LOG));
}
public MusicMountLive(MusicMountBuildConfig config, MusicMountServer server) {
this.config = config;
this.server = server;
this.updater = new LiveMountUpdater(60 * 1000L); // delay update for 60 seconds after change
}
public MusicMountBuildConfig getConfig() {
return config;
}
public ProgressHandler getProgressHandler() {
return progressHandler;
}
public void setProgressHandler(ProgressHandler progressHandler) {
this.progressHandler = progressHandler;
}
private String getMusicPath() {
return MUSIC_PATH;
}
private String getMountPath() {
return MOUNT_PATH;
}
public String getHostName(String defaultName) {
try {
return InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
return defaultName;
}
}
public String getSitePath() {
String path = getMountPath();
if (!path.startsWith("/")) {
path = "/" + path;
}
if (!path.endsWith("/")) {
path = path + "/";
}
return path;
}
public URL getSiteURL(String hostName, int port) throws MalformedURLException {
if (port == 80) {
return new URL("http", hostName, getSitePath());
} else {
return new URL("http", hostName, port, getSitePath());
}
}
public void start(FileResource musicFolder, int port, String user, String password) throws Exception {
LOGGER.info("Starting Server...");
LOGGER.info("Music folder: " + musicFolder.getPath());
LiveMountBuilder mountBuilder = new LiveMountBuilder(config);
LiveMountServlet servlet = new LiveMountServlet(mountBuilder.update(musicFolder, getMusicPath(), progressHandler));
FolderContext music = new FolderContext(getMusicPath(), musicFolder.getPath().toFile());
MountContext mount = new MountContext(getMountPath(), servlet);
server.start(music, mount, port, user, password);
LOGGER.info(String.format("Mount Settings"));
LOGGER.info(String.format("--------------"));
LOGGER.info(String.format("Site: %s", getSiteURL(getHostName("<hostName>"), port)));
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.");
LiveMountBuilder updateBuilder = new LiveMountBuilder(config.clone(), mountBuilder.getRepository());
updateBuilder.getConfig().setFull(false); // never do a full build when updating
try {
updater.start(musicFolder, getMusicPath(), updateBuilder, servlet);
LOGGER.info("Auto updater is ready.");
} catch (IOException e) {
LOGGER.log(Level.WARNING, "Auto updater could not be started", e);
}
}
public void await() {
server.await();
}
public boolean isStarted() {
return server.isStarted();
}
public void stop() throws Exception {
LOGGER.info("Stopping Server...");
if (updater.isStarted()) {
updater.stop();
}
server.stop();
LOGGER.info("Done.");
}
}