All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.semanticcms.core.servlet.OpenFile Maven / Gradle / Ivy

/*
 * semanticcms-core-servlet - Java API for modeling web page content and relationships in a Servlet environment.
 * Copyright (C) 2013, 2014, 2015, 2016  AO Industries, Inc.
 *     [email protected]
 *     7262 Bull Pen Cir
 *     Mobile, AL 36695
 *
 * This file is part of semanticcms-core-servlet.
 *
 * semanticcms-core-servlet is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * semanticcms-core-servlet is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with semanticcms-core-servlet.  If not, see .
 */
package com.semanticcms.core.servlet;

import com.aoindustries.io.FileUtils;
import com.aoindustries.lang.ProcessResult;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.SkipPageException;

final public class OpenFile {

	private static final Logger logger = Logger.getLogger(OpenFile.class.getName());

	private static final String ENABLE_INIT_PARAM = OpenFile.class.getName() + ".enabled";

	private static final String FILE_OPENERS_REQUEST_ATTRIBUTE_NAME = OpenFile.class.getName()+".fileOpeners";

	/**
	 * Checks if the given host address is allowed to open files on the server.
	 */
	private static boolean isAllowedAddr(String addr) {
		return "127.0.0.1".equals(addr);
	}

	/**
	 * Checks if the given request is allowed to open files on the server.
	 * The servlet init param must have it enabled, as well as be from an allowed IP.
	 */
	public static boolean isAllowed(ServletContext servletContext, ServletRequest request) {
		return
			Boolean.parseBoolean(servletContext.getInitParameter(ENABLE_INIT_PARAM))
			&& isAllowedAddr(request.getRemoteAddr())
		;
	}

	private static String getJdkPath() {
		try {
			String hostname = InetAddress.getLocalHost().getCanonicalHostName();
			if(
				"francis.aoindustries.com".equals(hostname)
				|| "freedom.aoindustries.com".equals(hostname)
			) return "/opt/jdk1.8.0-i686";
		} catch(UnknownHostException e) {
			// Fall-through to default 64-bit
		}
		return "/opt/jdk1.8.0";
	}

	public static boolean isWindows() {
		String osName = System.getProperty("os.name");
		return osName!=null && osName.toLowerCase(Locale.ROOT).contains("windows");
	}

	/**
	 * Additional file openers may be registered to the application context.
	 */
	public static interface FileOpener {
		/**
		 * Gets the command that will open the given file.
		 *
		 * @return  The command or null to fall-through to default behavior.
		 */
		String[] getCommand(java.io.File resourceFile) throws IOException;
	}

	private static final Object fileOpenersLock = new Object();

	/**
	 * Registers a file opener.
	 * 
	 * @param  extensions  The simple extensions, in lowercase, not including the dot, such as "dia"
	 */
	public static void addFileOpener(ServletContext servletContext, FileOpener fileOpener, String ... extensions) {
		synchronized(fileOpenersLock) {
			@SuppressWarnings("unchecked")
			Map fileOpeners = (Map)servletContext.getAttribute(FILE_OPENERS_REQUEST_ATTRIBUTE_NAME);
			if(fileOpeners == null) {
				fileOpeners = new HashMap();
				servletContext.setAttribute(FILE_OPENERS_REQUEST_ATTRIBUTE_NAME, fileOpeners);
			}
			for(String extension : extensions) {
				if(fileOpeners.containsKey(extension)) throw new IllegalStateException("File opener already registered: " + extension);
				fileOpeners.put(extension, fileOpener);
			}
		}
	}

	/**
	 * Removes file openers.
	 * 
	 * @param  extensions  The simple extensions, in lowercase, not including the dot, such as "dia"
	 */
	public static void removeFileOpener(ServletContext servletContext, String ... extensions) {
		synchronized(fileOpenersLock) {
			@SuppressWarnings("unchecked")
			Map fileOpeners = (Map)servletContext.getAttribute(FILE_OPENERS_REQUEST_ATTRIBUTE_NAME);
			if(fileOpeners != null) {
				for(String extension : extensions) {
					fileOpeners.remove(extension);
				}
				if(fileOpeners.isEmpty()) {
					servletContext.removeAttribute(FILE_OPENERS_REQUEST_ATTRIBUTE_NAME);
				}
			}
		}
	}

	public static void openFile(
		ServletContext servletContext,
		HttpServletRequest request,
		HttpServletResponse response,
		String book,
		final String path
	) throws ServletException, IOException, SkipPageException {
		// Only allow from localhost and when open enabled
		if(!isAllowed(servletContext, request)) {
			response.sendError(HttpServletResponse.SC_FORBIDDEN);
			throw new SkipPageException();
		} else {
			String[] command;
			java.io.File resourceFile = PageRefResolver.getPageRef(servletContext, request, book, path).getResourceFile(true, true);
			if(resourceFile.isDirectory()) {
				command = new String[] {
					// TODO: What is good windows path?
					//isWindows()
					//	? "C:\\Program Files (x86)\\OpenOffice 4\\program\\swriter.exe"
					"/usr/bin/konqueror",
					resourceFile.getCanonicalPath()
				};
			} else {
				// Open the file with the appropriate application based on extension
				String extension = FileUtils.getExtension(resourceFile.getName()).toLowerCase(Locale.ROOT);
				// Check registered file openers first
				FileOpener fileOpener;
				synchronized(fileOpenersLock) {
					@SuppressWarnings("unchecked")
					Map fileOpeners = (Map)servletContext.getAttribute(FILE_OPENERS_REQUEST_ATTRIBUTE_NAME);
					if(fileOpeners != null) {
						fileOpener = fileOpeners.get(extension);
					} else {
						fileOpener = null;
					}
				}
				if(fileOpener != null) {
					command = fileOpener.getCommand(resourceFile);
				} else {
					// Use default behavior
					// Java 1.7: switch(extension)
					if(
						"gif".equals(extension)
						|| "jpg".equals(extension)
						|| "jpeg".equals(extension)
						|| "png".equals(extension)
					) {
						command = new String[] {
							isWindows()
								? "C:\\Program Files (x86)\\OpenOffice 4\\program\\swriter.exe"
								: "/usr/bin/gwenview",
							resourceFile.getCanonicalPath()
						};
					} else if(
						"doc".equals(extension)
						|| "odt".equals(extension)
					) {
						command = new String[] {
							isWindows()
								? "C:\\Program Files (x86)\\OpenOffice 4\\program\\swriter.exe"
								: "/usr/bin/libreoffice",
							"--writer",
							resourceFile.getCanonicalPath()
						};
					} else if(
						"csv".equals(extension)
						|| "ods".equals(extension)
						|| "sxc".equals(extension)
						|| "xls".equals(extension)
					) {
						command = new String[] {
							isWindows()
								? "C:\\Program Files (x86)\\OpenOffice 4\\program\\scalc.exe"
								: "/usr/bin/libreoffice",
							"--calc",
							resourceFile.getCanonicalPath()
						};
					} else if(
						"pdf".equals(extension)
					) {
						command = new String[] {
							isWindows()
								? "C:\\Program Files (x86)\\Adobe\\Reader 11.0\\Reader\\AcroRd32.exe"
								: "/usr/bin/okular",
							resourceFile.getCanonicalPath()
						};
					//} else if(
					//	"sh".equals(extension)
					//) {
						//command = new String[] {
						//	"/usr/bin/kwrite",
						//	resourceFile.getCanonicalPath()
						//};
					} else if(
						"java".equals(extension)
						|| "jsp".equals(extension)
						|| "sh".equals(extension)
						|| "txt".equals(extension)
						|| "xml".equals(extension)
					) {
						if(isWindows()) {
							command = new String[] {
								"C:\\Program Files\\NetBeans 7.4\\bin\\netbeans64.exe",
								"--open",
								resourceFile.getCanonicalPath()
							};
						} else {
							command = new String[] {
								//"/usr/bin/kwrite",
								"/opt/netbeans-8.0.2/bin/netbeans",
								"--jdkhome",
								getJdkPath(),
								"--open",
								resourceFile.getCanonicalPath()
							};
						}
					} else if(
						"zip".equals(extension)
					) {
						if(isWindows()) {
							command = new String[] {
								resourceFile.getCanonicalPath()
							};
						} else {
							command = new String[] {
								"/usr/bin/konqueror",
								resourceFile.getCanonicalPath()
							};
						}
					} else if(
						"mp3".equals(extension)
						|| "wma".equals(extension)
					) {
						command = new String[] {
							isWindows()
								? "C:\\Program Files\\VideoLAN\\VLC.exe"
								: "/usr/bin/vlc",
							resourceFile.getCanonicalPath()
						};
					} else {
						throw new IllegalArgumentException("Unsupprted file type by extension: " + extension);
					}
				}
			}
			// Start the process
			final Process process = Runtime.getRuntime().exec(command);
			// Result is watched in the background only
			// Java 1.8: Lambda
			new Thread(
				new Runnable() {
					@Override
					public void run() {
						try {
							final ProcessResult result = ProcessResult.getProcessResult(process);
							int exitVal = result.getExitVal();
							if(exitVal != 0) {
								logger.log(Level.SEVERE, "Non-zero exit status from \"{0}\": {1}", new Object[]{path, exitVal});
							}
							String stdErr = result.getStderr();
							if(!stdErr.isEmpty()) {
								logger.log(Level.SEVERE, "Standard error from \"{0}\":\n{1}", new Object[]{path, stdErr});
							}
							if(logger.isLoggable(Level.INFO)) {
								String stdOut = result.getStdout();
								if(!stdOut.isEmpty()) {
									logger.log(Level.INFO, "Standard output from \"{0}\":\n{1}", new Object[]{path, stdOut});
								}
							}
						} catch(IOException e) {
							logger.log(Level.SEVERE, null, e);
						}
					}
				}
			).start();
		}
	}

	/**
	 * Make no instances.
	 */
	private OpenFile() {
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy