ImportController.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. package de.tu_darmstadt.tk.SmartHomeNetworkSim.control;
  2. import java.io.BufferedReader;
  3. import java.io.File;
  4. import java.io.FileReader;
  5. import java.io.IOException;
  6. import java.net.MalformedURLException;
  7. import java.net.URL;
  8. import java.net.URLClassLoader;
  9. import java.util.LinkedList;
  10. import javax.tools.JavaCompiler;
  11. import javax.tools.ToolProvider;
  12. import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Link;
  13. import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Model;
  14. import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Connection;
  15. import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Protocol;
  16. import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.SmartDevice;
  17. /**
  18. * Controller which manages Imported Classes of the
  19. *
  20. * @author Andreas T. Meyer-Berg
  21. */
  22. public class ImportController {
  23. Model model;
  24. Controller controller;
  25. /**
  26. * Creates a new ImportController
  27. *
  28. * @param model
  29. * model to be edited
  30. * @param controller
  31. * parent controller
  32. */
  33. public ImportController(Model model, Controller controller) {
  34. this.model = model;
  35. this.controller = controller;
  36. }
  37. /**
  38. * Adds new Link to the model
  39. *
  40. * @param Link
  41. * Link to be added
  42. * @return true if it was added
  43. */
  44. public boolean addLink(Class<? extends Link> Link) {
  45. if (isValidLink(Link))
  46. model.addLinkClass(Link);
  47. else
  48. return false;
  49. return true;
  50. }
  51. /**
  52. * Removes Link from the model
  53. *
  54. * @param Link
  55. * Link to be removed
  56. */
  57. public void removeLink(Class<? extends Link> Link) {
  58. model.removeLinkClass(Link);
  59. }
  60. /**
  61. * Returns the available Links of the model
  62. *
  63. * @return available links
  64. */
  65. public LinkedList<Class<? extends Link>> getLinks() {
  66. return model.getLinkClasses();
  67. }
  68. /**
  69. * Returns true if it is a Valid Link, false if not
  70. *
  71. * @param link
  72. * Link to be checked
  73. * @return true if it is a valid Link
  74. */
  75. public boolean isValidLink(Class<? extends Link> link) {
  76. try {
  77. /**
  78. * Link to be tested
  79. */
  80. Link l = link.newInstance();
  81. // Empty constructor required, to create new instance
  82. if (l == null)
  83. throw new Exception("Link required an empty constructor");
  84. // Name shall not be null or empty string
  85. if (l.getName() == null || l.getName() == "")
  86. throw new Exception(
  87. "Link name shall not be null or empty string.");
  88. } catch (Exception e) {
  89. return false;
  90. }
  91. return true;
  92. }
  93. /**
  94. * Adds new Protocol to the model
  95. *
  96. * @param protocol
  97. * protocol to be added
  98. * @return true if it was added
  99. */
  100. public boolean addProtocol(Class<? extends Protocol> protocol) {
  101. if (isValidProtocol(protocol))
  102. model.addProtocolClass(protocol);
  103. else
  104. return false;
  105. return true;
  106. }
  107. /**
  108. * Removes protocol from the model
  109. *
  110. * @param protocol
  111. * protocol to be removed
  112. */
  113. public void removeProtocol(Class<? extends Protocol> protocol) {
  114. model.removeProtocolClass(protocol);
  115. }
  116. /**
  117. * Returns the available Protocols of the model
  118. *
  119. * @return available protocols
  120. */
  121. public LinkedList<Class<? extends Protocol>> getProtocols() {
  122. return model.getProtocolClasses();
  123. }
  124. /**
  125. * Returns true if it is a Valid Protocol, false if not
  126. *
  127. * @param protocol
  128. * protocol to be checked
  129. * @return true if it is a valid protocol
  130. */
  131. public boolean isValidProtocol(Class<? extends Protocol> protocol) {
  132. try {
  133. /**
  134. * Protocol to be tested
  135. */
  136. Protocol p = protocol.newInstance();
  137. // Empty constructor required, to create new instance
  138. if (p == null)
  139. throw new Exception("Protocol required an empty constructor");
  140. // Name shall not be null or empty string
  141. if (p.getName() == null || p.getName() == "")
  142. throw new Exception(
  143. "Protocol name shall not be null or empty string.");
  144. if (p.getRoles() == null || p.getRoles().length == 0)
  145. throw new Exception("Roles shall not be null or empty");
  146. // Number of roles have to match
  147. if (p.getNumberOfRoles() != p.getRoles().length)
  148. throw new Exception(
  149. "getNumberOfRoles() does not match getRoles().length");
  150. } catch (Exception e) {
  151. return false;
  152. }
  153. return true;
  154. }
  155. /**
  156. * Adds new Connection to the model
  157. *
  158. * @param connection
  159. * Connection to be added
  160. * @return true if it was added
  161. */
  162. public boolean addConnection(Class<? extends Connection> connection) {
  163. if (isValidConnection(connection))
  164. model.addConnectionClass(connection);
  165. else
  166. return false;
  167. return true;
  168. }
  169. /**
  170. * Removes Connection from the model
  171. *
  172. * @param connection
  173. * Connection to be removed
  174. */
  175. public void removeConnection(Class<? extends Connection> connection) {
  176. model.removeConnectionClass(connection);
  177. }
  178. /**
  179. * Returns the available Connections of the model
  180. *
  181. * @return available Connections
  182. */
  183. public LinkedList<Class<? extends Connection>> getConnections() {
  184. return model.getConnectionClasses();
  185. }
  186. /**
  187. * Returns true if it is a Valid Connection, false if not
  188. *
  189. * @param connection
  190. * Connection to be checked
  191. * @return true if it is a valid Connection
  192. */
  193. public boolean isValidConnection(Class<? extends Connection> connection) {
  194. try {
  195. /**
  196. * Connection to be tested
  197. */
  198. Connection p = connection.newInstance();
  199. // Empty constructor required, to create new instance
  200. if (p == null)
  201. throw new Exception("Connection required an empty constructor");
  202. // Name shall not be null or empty string
  203. if (p.getName() == null || p.getName() == "")
  204. throw new Exception(
  205. "Connection name shall not be null or empty string.");
  206. } catch (Exception e) {
  207. return false;
  208. }
  209. return true;
  210. }
  211. /**
  212. * Adds new SmartDevice to the model
  213. *
  214. * @param smartDevice
  215. * SmartDevice to be added
  216. * @return true if it was added
  217. */
  218. public boolean addSmartDevice(Class<? extends SmartDevice> smartDevice) {
  219. if (isValidSmartDevice(smartDevice))
  220. model.addSmartDeviceClass(smartDevice);
  221. else
  222. return false;
  223. return true;
  224. }
  225. /**
  226. * Removes SmartDevice from the model
  227. *
  228. * @param smartDevice
  229. * SmartDevice to be removed
  230. */
  231. public void removeSmartDevice(Class<? extends SmartDevice> smartDevice) {
  232. model.removeSmartDeviceClass(smartDevice);
  233. }
  234. /**
  235. * Returns the available SmartDevices of the model
  236. *
  237. * @return available SmartDevices
  238. */
  239. public LinkedList<Class<? extends SmartDevice>> getSmartDevices() {
  240. return model.getSmartDeviceClasses();
  241. }
  242. /**
  243. * Returns true if it is a Valid SmartDevice, false if not
  244. *
  245. * @param smartDevice
  246. * SmartDevice to be checked
  247. * @return true if it is a valid SmartDevice
  248. */
  249. public boolean isValidSmartDevice(Class<? extends SmartDevice> smartDevice) {
  250. try {
  251. /**
  252. * SmartDevice to be tested
  253. */
  254. SmartDevice p = smartDevice.newInstance();
  255. // Empty constructor required, to create new instance
  256. if (p == null)
  257. throw new Exception("SmartDevice required an empty constructor");
  258. // Name shall not be null or empty string
  259. if (p.getName() == null || p.getName() == "")
  260. throw new Exception(
  261. "SmartDevice name shall not be null or empty string.");
  262. } catch (Exception e) {
  263. return false;
  264. }
  265. return true;
  266. }
  267. /**
  268. * Imports the given .java File, compiles it and returns the
  269. *
  270. * @param javaFilenew File(path)
  271. * @return Class which was compiled
  272. * @throws ClassNotFoundException on invalid package declaration or invalid file name
  273. * @throws MalformedURLException if the URL was malformed
  274. * @throws ClassImportException
  275. */
  276. public static Class<?> importJavaClass(File javaFile) throws ClassImportException {
  277. /**
  278. * Package name
  279. */
  280. String packageName = getJavaPackageName(javaFile);
  281. if (packageName == null) {
  282. // if package null - try default package
  283. packageName = "";
  284. }
  285. /**
  286. * Name of the Class. File name "ClassName.java"
  287. */
  288. String className = javaFile.getName().substring(0,
  289. javaFile.getName().lastIndexOf('.'));
  290. /**
  291. * Compiler, to compile the File
  292. */
  293. JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
  294. compiler.run(null, null, null, javaFile.getPath());
  295. /**
  296. * Root File of the imported Protocol (if the Java File is inside a package)
  297. */
  298. File root = javaFile.getParentFile();
  299. if(!packageName.isEmpty()){
  300. /**
  301. * Array of all parent package names e.g. "pack1.pack2.pack3" -> {"pack1","pack2","pack3"}
  302. */
  303. String[] packageFolders = packageName.split("\\.");
  304. if(packageFolders.length<2){
  305. //A single level
  306. if(root.getName().compareTo(packageName)!=0){
  307. throw new ClassImportException("Invalid ParentFolderName: Expected \""+packageName+"\" but was \""+root.getName()+"\"");
  308. }
  309. root = root.getParentFile();
  310. }else{
  311. for(int i = packageFolders.length-1;i>=0;i--){
  312. if(root.getName().compareTo(packageFolders[i])!=0){
  313. throw new ClassImportException("Invalid ParentFolderName at level "+i+": Expected \""+packageFolders[i]+"\" but was \""+root.getName()+"\"");
  314. }
  315. root = root.getParentFile();
  316. }
  317. }
  318. }
  319. /**
  320. * ClassLoader to load the compiled class, given it's root
  321. */
  322. URLClassLoader classLoader;
  323. try {
  324. classLoader = URLClassLoader
  325. .newInstance(new URL[] { root.toURI().toURL() });
  326. } catch (MalformedURLException e1) {
  327. throw new ClassImportException("Invalid URL/File at the root of the imported Class");
  328. }
  329. // If packageName is not empty, and dot is required: e.g. "packagePath.ClassName"
  330. if (!packageName.isEmpty())
  331. packageName += ".";
  332. /**
  333. * Imported Class
  334. */
  335. Class<?> cls = null;
  336. try{
  337. cls = Class.forName(packageName + className, true, classLoader);
  338. }catch(Exception e){
  339. try{
  340. //Second try to load class
  341. cls = classLoader.loadClass(packageName + className);
  342. }catch(Exception e2){
  343. e2.printStackTrace();
  344. }
  345. }
  346. return cls;
  347. }
  348. /**
  349. * Returns the package path of a given Java File. Returns null if the
  350. * exception occurred and returns an empty string if no package declaration
  351. * was found. Package declaration should be in a single line.
  352. *
  353. * @param javaFile
  354. * File to be searched for the package path
  355. * @return PackagePath of the JavaFile, EmptyString, if no declaration was
  356. * found, null on errors
  357. */
  358. public static String getJavaPackageName(File javaFile) {
  359. /**
  360. * If javaFile null -> return null
  361. */
  362. if(javaFile==null)
  363. return null;
  364. /**
  365. * Package name
  366. */
  367. String packageName = "";
  368. /**
  369. * Reader to read the java File
  370. */
  371. BufferedReader reader = null;
  372. try {
  373. reader = new BufferedReader(new FileReader(javaFile.getPath()));
  374. /**
  375. * Current Line which is investigated
  376. */
  377. String currentLine = reader.readLine();
  378. // Search each line until a valid package is found
  379. while (currentLine != null) {
  380. currentLine = currentLine.trim();
  381. if (!currentLine.isEmpty()) {
  382. //Check if line begins with package
  383. if (currentLine.length() >= 7 && currentLine.startsWith("package")) {
  384. packageName = currentLine.substring(8, currentLine.length() - 1);
  385. }
  386. }
  387. if (packageName.isEmpty()) {
  388. currentLine = reader.readLine();
  389. } else {
  390. currentLine = null;
  391. }
  392. }
  393. } catch (Exception e) {
  394. } finally {
  395. try {
  396. reader.close();
  397. } catch (IOException e) {
  398. }
  399. }
  400. // Remove whitespace in cases like "import test.package ;"
  401. packageName = packageName.trim();
  402. return packageName;
  403. }
  404. }