/*******************************************************************************
* Copyright (c) 2012 Google, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Google, Inc. - initial API and implementation
*******************************************************************************/
package com.windowtester.runtime.internal.factory;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.eclipse.swt.SWT;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import com.windowtester.internal.runtime.ProductInfo;
/**
* A facade for an instance of {@link WTRuntimeFactory} when running outside the Eclipse
* infrastructure such as when testing a Swing application or an SWT application without
* the OSGi bundle framework.
*/
class WTRuntimeFactoryReferenceJava extends WTRuntimeFactoryReference
{
private static final String FACTORIES_FILE_NAME = "javaRuntimeFactories.xml";
private final String className;
/**
* Find the known widget factories as defined in the swingFactories.xml file.
*
* @return an array of references (not <code>null</code>, contains no
* <code>null</code>s)
*/
static WTRuntimeFactoryReference[] createFactoryReferences() {
Collection<WTRuntimeFactoryReference> result = new ArrayList<WTRuntimeFactoryReference>();
SAXParserFactory factory = SAXParserFactory.newInstance();
DefaultHandler handler = new FactoryDeclarationHandler(result);
InputStream stream = WTRuntimeFactoryReferenceJava.class.getResourceAsStream(FACTORIES_FILE_NAME);
try {
SAXParser parser = factory.newSAXParser();
parser.parse(stream, handler);
}
catch (Exception e) {
throw new RuntimeException("Failed to read " + FACTORIES_FILE_NAME, e);
}
finally {
try {
stream.close();
}
catch (IOException e) {
// Ignored
}
}
return result.toArray(new WTRuntimeFactoryReference[result.size()]);
}
/**
* A handler for reading the runtime factory declarations from
* javaRuntimeFactories.xml
*/
private static final class FactoryDeclarationHandler extends DefaultHandler
{
private final Collection<WTRuntimeFactoryReference> result;
private final String arch;
private final String os;
private final String ws;
public FactoryDeclarationHandler(Collection<WTRuntimeFactoryReference> result) {
this.result = result;
String osName = System.getProperty("os.name");
String osVersion = System.getProperty("os.version");
os = getOS(osName, osVersion);
ws = getWS(osName, osVersion);
arch = getArch();
String debugInfo = "WindowTester: " + ProductInfo.build + " - " + os + "," + ws + "," + arch;
// System.out.println(debugInfo);
WTRuntimeManager.setPlatformDebugInfo(debugInfo);
}
private String getArch() {
String arch = System.getProperty("os.arch");
//OSX returns "i386" which we want to normalize to x86
if (arch.equals("i386"))
arch = "x86";
return arch;
}
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
{
if (qName.equals(FACTORY_TAG)) {
String className = attributes.getValue(CLASS_TAG);
if (className == null)
throw new RuntimeException("Missing class attribute in " + FACTORIES_FILE_NAME);
if (className.length() == 0)
throw new RuntimeException("Invalid class attribute in " + FACTORIES_FILE_NAME);
if (!isFactoryFor(os, attributes.getValue(OS_TAG)))
return;
if (!isFactoryFor(ws, attributes.getValue(WS_TAG)))
return;
if (!isFactoryFor(arch, attributes.getValue(ARCH_TAG)))
return;
result.add(new WTRuntimeFactoryReferenceJava(className));
}
}
/**
* Translate the OS name and version into something that is Eclipse-like
*
* @param osName the OS name (e.g. "Windows Vista")
* @param osVersion the OS version
* @return the Eclipse friendly OS (e.g. "win32", "linux")
*/
private String getOS(String osName, String osVersion) {
try {
String ws = SWT.getPlatform();
if (ws.equals("win32"))
return "win32";
if (ws.equals("cocoa") || ws.equals("carbon"))
return "macosx";
if (ws.equals("gtk") || ws.equals("motif"))
return "linux";
// fall through to determine the WS another way
}
catch (NoClassDefFoundError e) {
// SWT must not be on the classpath,
// so fall through to determine the WS another way
}
if (osName.startsWith("Windows"))
return "win32";
// TODO Is this correct for Mac ?
if (osName.startsWith("Mac OS X"))
return "macosx";
if (osName.startsWith("Mac"))
return "mac";
return "linux";
}
/**
* Translate the OS name and version into something that is Eclipse-like
*
* @param osName the OS name (e.g. "Windows Vista")
* @param osVersion the OS version
* @return the Eclipse friendly windowing system name (e.g. "win32", "gtk")
*/
private String getWS(String osName, String osVersion) {
try {
return SWT.getPlatform();
}
catch (NoClassDefFoundError e) {
// SWT must not be on the classpath,
// so fall through to determine the WS another way
}
if (osName.startsWith("Windows"))
return "win32";
// TODO Is this correct for Mac ?
if (osName.startsWith("Mac OS X"))
return "cocoa";
if (osName.startsWith("Mac"))
return "carbon";
// Otherwise assume GTK
return "gtk";
}
}
/**
* Instantiate a reference to a factory with the specified class
*
* @param className the fully qualified name of the factory class
*/
public WTRuntimeFactoryReferenceJava(String className) {
this.className = className;
}
/**
* Instantiate the factory
*
* @return the factory (not <code>null</code>)
* @throws Exception if the factory could not be instantiated
*/
WTRuntimeFactory createFactory() throws Exception {
return (WTRuntimeFactory) getClass().getClassLoader().loadClass(className).newInstance();
}
}