osd-contiki/tools/cooja/java/org/contikios/cooja/CoreComm.java
Fredrik Osterlind b5c94910ac Renamed Java packages to match our contiki-os.org domain. Note that this commit does not affect external dependencies
like /tools/mspsim.

This is a very simple modification that affects a very large number of files in Contiki: Cooja,
/platform/cooja, Collect-view, Coffe-manager, and Cooja simulation files (.csc).

I've gone through Contiki to update all references I could find. Nevertheless, this commit will likely
break external dependencies, like saved Cooja simulation files.
2013-11-20 16:43:27 +01:00

387 lines
13 KiB
Java

/*
* Copyright (c) 2006, Swedish Institute of Computer Science. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. 2. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. 3. Neither the name of the
* Institute nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package org.contikios.cooja;
import java.io.*;
import java.lang.reflect.*;
import java.net.*;
import java.util.Vector;
import org.contikios.cooja.MoteType.MoteTypeCreationException;
import org.contikios.cooja.contikimote.ContikiMoteType;
import org.contikios.cooja.dialogs.MessageList;
/**
* The purpose of corecomm's is communicating with a compiled Contiki system
* using Java Native Interface (JNI). Each implemented class (named
* Lib[number]), loads a shared library which belongs to one mote type. The
* reason for this somewhat strange design is that once loaded, a native library
* cannot be unloaded in Java (in the current versions available). Therefore if
* we wish to load several libraries, the names and associated native functions
* must have unique names. And those names are defined via the calling class in
* JNI. For example, the corresponding function for a native tick method in
* class Lib1 will be named Java_org_contikios_cooja_corecomm_Lib1_tick. When creating
* a new mote type, the main Contiki source file is generated with function
* names compatible with the next available corecomm class. This also implies
* that even if a mote type is deleted, a new one cannot be created using the
* same corecomm class without restarting the JVM and thus the entire
* simulation.
*
* Each implemented CoreComm class needs read access to the following core
* variables:
* <ul>
* <li>referenceVar
* </ul>
* and the following native functions:
* <ul>
* <li>tick()
* <li>init()
* <li>getReferenceAbsAddr()
* <li>getMemory(int start, int length, byte[] mem)
* <li>setMemory(int start, int length, byte[] mem)
*
* @author Fredrik Osterlind
*/
public abstract class CoreComm {
// Static pointers to current libraries
private final static Vector<CoreComm> coreComms = new Vector<CoreComm>();
private final static Vector<File> coreCommFiles = new Vector<File>();
private static int fileCounter = 1;
/**
* Has any library been loaded? Since libraries can't be unloaded the entire
* simulator may have to be restarted.
*
* @return True if any library has been loaded this session
*/
public static boolean hasLibraryBeenLoaded() {
return coreComms.size() > 0;
}
/**
* Has given library file already been loaded during this session? A loaded
* library can be removed, but not unloaded during one session. And a new
* library file, named the same as an earlier loaded and removed file, can't
* be loaded either.
*
* @param libraryFile
* Library file
* @return True if a library has already been loaded from the given file's
* filename
*/
public static boolean hasLibraryFileBeenLoaded(File libraryFile) {
for (File loadedFile : coreCommFiles) {
if (loadedFile.getName().equals(libraryFile.getName())) {
return true;
}
}
return false;
}
/**
* Get the class name of next free core communicator class. If null is
* returned, no classes are available.
*
* @return Class name
*/
public static String getAvailableClassName() {
return "Lib" + fileCounter;
}
/**
* Generates new source file by reading default source template and replacing
* the class name field.
*
* @param className
* Java class name (without extension)
* @throws MoteTypeCreationException
* If error occurs
*/
public static void generateLibSourceFile(String className)
throws MoteTypeCreationException {
BufferedWriter sourceFileWriter = null;
BufferedReader templateFileReader = null;
String destFilename = null;
try {
Reader reader;
String mainTemplate = Cooja
.getExternalToolsSetting("CORECOMM_TEMPLATE_FILENAME");
if ((new File(mainTemplate)).exists()) {
reader = new FileReader(mainTemplate);
} else {
InputStream input = CoreComm.class
.getResourceAsStream('/' + mainTemplate);
if (input == null) {
throw new FileNotFoundException(mainTemplate + " not found");
}
reader = new InputStreamReader(input);
}
templateFileReader = new BufferedReader(reader);
destFilename = className + ".java";
File dir = new File("org/contikios/cooja/corecomm");
if (!dir.exists()) {
dir.mkdirs();
}
sourceFileWriter = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream("org/contikios/cooja/corecomm/" + destFilename)));
// Replace special fields in template
String line;
while ((line = templateFileReader.readLine()) != null) {
line = line.replaceFirst("\\[CLASSNAME\\]", className);
sourceFileWriter.write(line + "\n");
}
sourceFileWriter.close();
templateFileReader.close();
} catch (Exception e) {
try {
if (sourceFileWriter != null) {
sourceFileWriter.close();
}
if (templateFileReader != null) {
templateFileReader.close();
}
} catch (Exception e2) {
}
throw (MoteTypeCreationException) new MoteTypeCreationException(
"Could not generate corecomm source file: " + className + ".java")
.initCause(e);
}
File genFile = new File("org/contikios/cooja/corecomm/" + destFilename);
if (genFile.exists()) {
return;
}
throw new MoteTypeCreationException(
"Could not generate corecomm source file: " + className + ".java");
}
/**
* Compiles Java class.
*
* @param className
* Java class name (without extension)
* @throws MoteTypeCreationException
* If Java class compilation error occurs
*/
public static void compileSourceFile(String className)
throws MoteTypeCreationException {
MessageList compilationOutput = new MessageList();
OutputStream compilationStandardStream = compilationOutput
.getInputStream(MessageList.NORMAL);
OutputStream compilationErrorStream = compilationOutput
.getInputStream(MessageList.ERROR);
File classFile = new File("org/contikios/cooja/corecomm/" + className + ".class");
try {
int b;
String[] cmd = new String[] { Cooja.getExternalToolsSetting("PATH_JAVAC"),
"-version", "org/contikios/cooja/corecomm/" + className + ".java" };
Process p = Runtime.getRuntime().exec(cmd, null, null);
InputStream outputStream = p.getInputStream();
InputStream errorStream = p.getErrorStream();
while ((b = outputStream.read()) >= 0) {
compilationStandardStream.write(b);
}
while ((b = errorStream.read()) >= 0) {
compilationErrorStream.write(b);
}
p.waitFor();
if (classFile.exists()) {
return;
}
// Try including cooja.jar
cmd = new String[] {
Cooja.getExternalToolsSetting("PATH_JAVAC"),
"-version",
"org/contikios/cooja/corecomm/" + className + ".java",
"-cp",
Cooja.getExternalToolsSetting("PATH_CONTIKI")
+ "/tools/cooja/dist/cooja.jar" };
p = Runtime.getRuntime().exec(cmd, null, null);
outputStream = p.getInputStream();
errorStream = p.getErrorStream();
while ((b = outputStream.read()) >= 0) {
compilationStandardStream.write(b);
}
while ((b = errorStream.read()) >= 0) {
compilationErrorStream.write(b);
}
p.waitFor();
if (classFile.exists()) {
return;
}
} catch (IOException e) {
MoteTypeCreationException exception = (MoteTypeCreationException) new MoteTypeCreationException(
"Could not compile corecomm source file: " + className + ".java")
.initCause(e);
exception.setCompilationOutput(compilationOutput);
throw exception;
} catch (InterruptedException e) {
MoteTypeCreationException exception = (MoteTypeCreationException) new MoteTypeCreationException(
"Could not compile corecomm source file: " + className + ".java")
.initCause(e);
exception.setCompilationOutput(compilationOutput);
throw exception;
}
MoteTypeCreationException exception = new MoteTypeCreationException(
"Could not compile corecomm source file: " + className + ".java");
exception.setCompilationOutput(compilationOutput);
throw exception;
}
/**
* Loads given Java class file from disk.
*
* @param className Java class name
* @return Loaded class
* @throws MoteTypeCreationException If error occurs
*/
public static Class<?> loadClassFile(String className)
throws MoteTypeCreationException {
Class<?> loadedClass = null;
try {
ClassLoader urlClassLoader = new URLClassLoader(
new URL[] { new File(".").toURI().toURL() },
CoreComm.class.getClassLoader());
loadedClass = urlClassLoader.loadClass("org.contikios.cooja.corecomm."
+ className);
} catch (MalformedURLException e) {
throw (MoteTypeCreationException) new MoteTypeCreationException(
"Could not load corecomm class file: " + className + ".class")
.initCause(e);
} catch (ClassNotFoundException e) {
throw (MoteTypeCreationException) new MoteTypeCreationException(
"Could not load corecomm class file: " + className + ".class")
.initCause(e);
}
if (loadedClass == null) {
throw new MoteTypeCreationException(
"Could not load corecomm class file: " + className + ".class");
}
return loadedClass;
}
/**
* Create and return an instance of the core communicator identified by
* className. This core communicator will load the native library libFile.
*
* @param className
* Class name of core communicator
* @param libFile
* Native library file
* @return Core Communicator
*/
public static CoreComm createCoreComm(String className, File libFile)
throws MoteTypeCreationException {
generateLibSourceFile(className);
compileSourceFile(className);
Class newCoreCommClass = loadClassFile(className);
try {
Constructor constr = newCoreCommClass
.getConstructor(new Class[] { File.class });
CoreComm newCoreComm = (CoreComm) constr
.newInstance(new Object[] { libFile });
coreComms.add(newCoreComm);
coreCommFiles.add(libFile);
fileCounter++;
return newCoreComm;
} catch (Exception e) {
throw (MoteTypeCreationException) new MoteTypeCreationException(
"Error when creating corecomm instance: " + className).initCause(e);
}
}
/**
* Ticks a mote once. This should not be used directly, but instead via
* {@link ContikiMoteType#tick()}.
*/
public abstract void tick();
/**
* Initializes a mote by running a startup script in the core. (Should only be
* run once, at the same time as the library is loaded)
*/
protected abstract void init();
/**
* Sets the relative memory address of the reference variable.
* Is used by Contiki to map between absolute and relative memory addresses.
*
* @param addr Relative address
*/
public abstract void setReferenceAddress(int addr);
/**
* Fills an byte array with memory segment identified by start and length.
*
* @param relAddr Relative memory start address
* @param length Length of segment
* @param mem Array to fill with memory segment
*/
public abstract void getMemory(int relAddr, int length, byte[] mem);
/**
* Overwrites a memory segment identified by start and length.
*
* @param relAddr Relative memory start address
* @param length Length of segment
* @param mem New memory segment data
*/
public abstract void setMemory(int relAddr, int length, byte[] mem);
}