AbstractModule.java 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811
  1. /* ========================================================================
  2. * JCommon : a free general purpose class library for the Java(tm) platform
  3. * ========================================================================
  4. *
  5. * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
  6. *
  7. * Project Info: http://www.jfree.org/jcommon/index.html
  8. *
  9. * This library is free software; you can redistribute it and/or modify it
  10. * under the terms of the GNU Lesser General Public License as published by
  11. * the Free Software Foundation; either version 2.1 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This library is distributed in the hope that it will be useful, but
  15. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  16. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  17. * License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
  22. * USA.
  23. *
  24. * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
  25. * in the United States and other countries.]
  26. *
  27. * -------------------
  28. * AbstractModule.java
  29. * -------------------
  30. * (C)opyright 2003, 2004, by Thomas Morgner and Contributors.
  31. *
  32. * Original Author: Thomas Morgner;
  33. * Contributor(s): David Gilbert (for Object Refinery Limited);
  34. *
  35. * $Id: AbstractModule.java,v 1.7 2008/09/10 09:16:54 mungady Exp $
  36. *
  37. * Changes
  38. * -------
  39. * 05-Jul-2003 : Initial version
  40. * 07-Jun-2004 : Added JCommon header (DG);
  41. *
  42. */
  43. package org.jfree.base.modules;
  44. import java.io.BufferedReader;
  45. import java.io.IOException;
  46. import java.io.InputStream;
  47. import java.io.InputStreamReader;
  48. import java.util.ArrayList;
  49. import org.jfree.util.ObjectUtilities;
  50. /**
  51. * The abstract module provides a default implementation of the module interface.
  52. * <p>
  53. * The module can be specified in an external property file. The file name of this
  54. * specification defaults to "module.properties". This file is no real property file,
  55. * it follows a more complex rule set.</p>
  56. * <p>
  57. * Lines starting with '#' are considered comments.
  58. * Section headers start at the beginning of the line, section properties
  59. * are indented with at least one whitespace.</p>
  60. * <p>
  61. * The first section is always the module info and contains the basic module
  62. * properties like name, version and a short description.</p>
  63. *
  64. * <pre>
  65. * module-info:
  66. * name: xls-export-gui
  67. * producer: The JFreeReport project - www.jfree.org/jfreereport
  68. * description: A dialog component for the Excel table export.
  69. * version.major: 0
  70. * version.minor: 84
  71. * version.patchlevel: 0
  72. * </pre>
  73. * The properties name, producer and description are simple strings. They may
  74. * span multiple lines, but may not contain a colon (':').
  75. * The version properties are integer values.
  76. * <p>
  77. * This section may be followed by one or more "depends" sections. These
  78. * sections describe the base modules that are required to be active to make this
  79. * module work. The package manager will enforce this policy and will deactivate this
  80. * module if one of the base modules is missing.</p>
  81. *
  82. * <pre>
  83. * depends:
  84. * module: org.jfree.report.modules.output.table.xls.XLSTableModule
  85. * version.major: 0
  86. * version.minor: 84
  87. * </pre>
  88. * <p>
  89. * The property module references to the module implementation of the module package.
  90. *
  91. * @author Thomas Morgner
  92. */
  93. public abstract class AbstractModule extends DefaultModuleInfo implements Module
  94. {
  95. /**
  96. * The reader helper provides a pushback interface for the reader to read and
  97. * buffer complete lines.
  98. * @author Thomas Morgner
  99. */
  100. private static class ReaderHelper
  101. {
  102. /** The line buffer containing the last line read. */
  103. private String buffer;
  104. /** The reader from which to read the text. */
  105. private final BufferedReader reader;
  106. /**
  107. * Creates a new reader helper for the given buffered reader.
  108. *
  109. * @param reader the buffered reader that is the source of the text.
  110. */
  111. protected ReaderHelper(final BufferedReader reader)
  112. {
  113. this.reader = reader;
  114. }
  115. /**
  116. * Checks, whether the reader contains a next line. Returns false if the end
  117. * of the stream has been reached.
  118. *
  119. * @return true, if there is a next line to read, false otherwise.
  120. * @throws IOException if an error occures.
  121. */
  122. public boolean hasNext() throws IOException
  123. {
  124. if (this.buffer == null)
  125. {
  126. this.buffer = readLine();
  127. }
  128. return this.buffer != null;
  129. }
  130. /**
  131. * Returns the next line.
  132. *
  133. * @return the next line.
  134. */
  135. public String next()
  136. {
  137. final String line = this.buffer;
  138. this.buffer = null;
  139. return line;
  140. }
  141. /**
  142. * Pushes the given line back into the buffer. Only one line can be contained in
  143. * the buffer at one time.
  144. *
  145. * @param line the line that should be pushed back into the buffer.
  146. */
  147. public void pushBack(final String line)
  148. {
  149. this.buffer = line;
  150. }
  151. /**
  152. * Reads the next line skipping all comment lines.
  153. *
  154. * @return the next line, or null if no line can be read.
  155. * @throws IOException if an IO error occures.
  156. */
  157. protected String readLine() throws IOException
  158. {
  159. String line = this.reader.readLine();
  160. while (line != null && (line.length() == 0 || line.startsWith("#")))
  161. {
  162. // empty line or comment is ignored
  163. line = this.reader.readLine();
  164. }
  165. return line;
  166. }
  167. /**
  168. * Closes the reader.
  169. *
  170. * @throws IOException if an IOError occurs.
  171. */
  172. public void close() throws IOException
  173. {
  174. this.reader.close();
  175. }
  176. }
  177. /** The list of required modules. */
  178. private ModuleInfo[] requiredModules;
  179. /** The list of optional modules. */
  180. private ModuleInfo[] optionalModules;
  181. /** The name of the module. */
  182. private String name;
  183. /** A short description of the module. */
  184. private String description;
  185. /** The name of the module producer. */
  186. private String producer;
  187. /** The modules subsystem. */
  188. private String subsystem;
  189. /**
  190. * Default Constructor.
  191. */
  192. public AbstractModule()
  193. {
  194. setModuleClass(this.getClass().getName());
  195. }
  196. /**
  197. * Loads the default module description from the file "module.properties". This file
  198. * must be in the same package as the implementing class.
  199. *
  200. * @throws ModuleInitializeException if an error occurs.
  201. */
  202. protected void loadModuleInfo() throws ModuleInitializeException
  203. {
  204. final InputStream in = ObjectUtilities.getResourceRelativeAsStream
  205. ("module.properties", getClass());
  206. if (in == null)
  207. {
  208. throw new ModuleInitializeException
  209. ("File 'module.properties' not found in module package.");
  210. }
  211. loadModuleInfo(in);
  212. }
  213. /**
  214. * Loads the module descriptiong from the given input stream. The module description
  215. * must conform to the rules define in the class description. The file must be encoded
  216. * with "ISO-8859-1" (like property files).
  217. *
  218. * @param in the input stream from where to read the file
  219. * @throws ModuleInitializeException if an error occurs.
  220. */
  221. protected void loadModuleInfo(final InputStream in) throws ModuleInitializeException
  222. {
  223. if (in == null)
  224. {
  225. throw new NullPointerException
  226. ("Given InputStream is null.");
  227. }
  228. try
  229. {
  230. final ArrayList optionalModules = new ArrayList();
  231. final ArrayList dependendModules = new ArrayList();
  232. final ReaderHelper rh = new ReaderHelper(new BufferedReader
  233. (new InputStreamReader(in, "ISO-8859-1")));
  234. try
  235. {
  236. while (rh.hasNext())
  237. {
  238. final String lastLineRead = rh.next();
  239. if (lastLineRead.startsWith("module-info:"))
  240. {
  241. readModuleInfo(rh);
  242. }
  243. else if (lastLineRead.startsWith("depends:"))
  244. {
  245. dependendModules.add(readExternalModule(rh));
  246. }
  247. else if (lastLineRead.startsWith("optional:"))
  248. {
  249. optionalModules.add(readExternalModule(rh));
  250. }
  251. else
  252. {
  253. // we dont understand the current line, so we skip it ...
  254. // should we throw a parse exception instead?
  255. }
  256. }
  257. }
  258. finally
  259. {
  260. rh.close();
  261. }
  262. this.optionalModules = (ModuleInfo[])
  263. optionalModules.toArray(new ModuleInfo[optionalModules.size()]);
  264. this.requiredModules = (ModuleInfo[])
  265. dependendModules.toArray(new ModuleInfo[dependendModules.size()]);
  266. }
  267. catch (IOException ioe)
  268. {
  269. throw new ModuleInitializeException("Failed to load properties", ioe);
  270. }
  271. }
  272. /**
  273. * Reads a multiline value the stream. This will read the stream until
  274. * a new key is found or the end of the file is reached.
  275. *
  276. * @param reader the reader from where to read.
  277. * @param firstLine the first line (which was read elsewhere).
  278. * @return the complete value, never null
  279. * @throws IOException if an IO error occurs.
  280. */
  281. private String readValue(final ReaderHelper reader, String firstLine) throws IOException
  282. {
  283. final StringBuffer b = new StringBuffer(firstLine.trim());
  284. boolean newLine = true;
  285. while (isNextLineValueLine(reader))
  286. {
  287. firstLine = reader.next();
  288. final String trimedLine = firstLine.trim();
  289. if (trimedLine.length() == 0 && (newLine == false))
  290. {
  291. b.append ("\n");
  292. newLine = true;
  293. }
  294. else
  295. {
  296. if (newLine == false)
  297. {
  298. b.append(" ");
  299. }
  300. b.append(parseValue(trimedLine));
  301. newLine = false;
  302. }
  303. }
  304. return b.toString();
  305. }
  306. /**
  307. * Checks, whether the next line in the reader is a value line.
  308. *
  309. * @param reader from where to read the lines.
  310. * @return true, if the next line is a value line, false otherwise.
  311. * @throws IOException if an IO error occurs.
  312. */
  313. private boolean isNextLineValueLine (final ReaderHelper reader) throws IOException
  314. {
  315. if (reader.hasNext() == false)
  316. {
  317. return false;
  318. }
  319. final String firstLine = reader.next();
  320. if (firstLine == null)
  321. {
  322. return false;
  323. }
  324. if (parseKey(firstLine) != null)
  325. {
  326. reader.pushBack(firstLine);
  327. return false;
  328. }
  329. reader.pushBack(firstLine);
  330. return true;
  331. }
  332. /**
  333. * Reads the module definition header. This header contains information about
  334. * the module itself.
  335. *
  336. * @param reader the reader from where to read the content.
  337. * @throws IOException if an error occures
  338. */
  339. private void readModuleInfo(final ReaderHelper reader) throws IOException
  340. {
  341. while (reader.hasNext())
  342. {
  343. final String lastLineRead = reader.next();
  344. if (Character.isWhitespace(lastLineRead.charAt(0)) == false)
  345. {
  346. // break if the current character is no whitespace ...
  347. reader.pushBack(lastLineRead);
  348. return;
  349. }
  350. final String line = lastLineRead.trim();
  351. final String key = parseKey(line);
  352. if (key != null)
  353. {
  354. // parse error: Non data line does not contain a colon
  355. final String b = readValue(reader, parseValue(line.trim()));
  356. if ("name".equals(key))
  357. {
  358. setName(b);
  359. }
  360. else if ("producer".equals(key))
  361. {
  362. setProducer(b);
  363. }
  364. else if ("description".equals(key))
  365. {
  366. setDescription(b);
  367. }
  368. else if ("subsystem".equals(key))
  369. {
  370. setSubSystem(b);
  371. }
  372. else if ("version.major".equals(key))
  373. {
  374. setMajorVersion(b);
  375. }
  376. else if ("version.minor".equals(key))
  377. {
  378. setMinorVersion(b);
  379. }
  380. else if ("version.patchlevel".equals(key))
  381. {
  382. setPatchLevel(b);
  383. }
  384. }
  385. }
  386. }
  387. /**
  388. * Parses an string to find the key section of the line. This section ends with
  389. * an colon.
  390. *
  391. * @param line the line which to parse
  392. * @return the key or null if no key is found.
  393. */
  394. private String parseKey(final String line)
  395. {
  396. final int idx = line.indexOf(':');
  397. if (idx == -1)
  398. {
  399. return null;
  400. }
  401. return line.substring(0, idx);
  402. }
  403. /**
  404. * Parses the value section of the given line.
  405. *
  406. * @param line the line that should be parsed
  407. * @return the value, never null
  408. */
  409. private String parseValue(final String line)
  410. {
  411. final int idx = line.indexOf(':');
  412. if (idx == -1)
  413. {
  414. return line;
  415. }
  416. if ((idx + 1) == line.length())
  417. {
  418. return "";
  419. }
  420. return line.substring(idx + 1);
  421. }
  422. /**
  423. * Reads an external module description. This describes either an optional or
  424. * a required module.
  425. *
  426. * @param reader the reader from where to read the module
  427. * @return the read module, never null
  428. * @throws IOException if an error occures.
  429. */
  430. private DefaultModuleInfo readExternalModule(final ReaderHelper reader)
  431. throws IOException
  432. {
  433. final DefaultModuleInfo mi = new DefaultModuleInfo();
  434. while (reader.hasNext())
  435. {
  436. final String lastLineRead = reader.next();
  437. if (Character.isWhitespace(lastLineRead.charAt(0)) == false)
  438. {
  439. // break if the current character is no whitespace ...
  440. reader.pushBack(lastLineRead);
  441. return mi;
  442. }
  443. final String line = lastLineRead.trim();
  444. final String key = parseKey(line);
  445. if (key != null)
  446. {
  447. final String b = readValue(reader, parseValue(line));
  448. if ("module".equals(key))
  449. {
  450. mi.setModuleClass(b);
  451. }
  452. else if ("version.major".equals(key))
  453. {
  454. mi.setMajorVersion(b);
  455. }
  456. else if ("version.minor".equals(key))
  457. {
  458. mi.setMinorVersion(b);
  459. }
  460. else if ("version.patchlevel".equals(key))
  461. {
  462. mi.setPatchLevel(b);
  463. }
  464. }
  465. }
  466. return mi;
  467. }
  468. /**
  469. * Returns the name of this module.
  470. *
  471. * @see Module#getName()
  472. *
  473. * @return the module name
  474. */
  475. public String getName()
  476. {
  477. return this.name;
  478. }
  479. /**
  480. * Defines the name of the module.
  481. *
  482. * @param name the module name.
  483. */
  484. protected void setName(final String name)
  485. {
  486. this.name = name;
  487. }
  488. /**
  489. * Returns the module description.
  490. * @see Module#getDescription()
  491. *
  492. * @return the description of the module.
  493. */
  494. public String getDescription()
  495. {
  496. return this.description;
  497. }
  498. /**
  499. * Defines the description of the module.
  500. *
  501. * @param description the module's desciption.
  502. */
  503. protected void setDescription(final String description)
  504. {
  505. this.description = description;
  506. }
  507. /**
  508. * Returns the producer of the module.
  509. *
  510. * @see Module#getProducer()
  511. *
  512. * @return the producer.
  513. */
  514. public String getProducer()
  515. {
  516. return this.producer;
  517. }
  518. /**
  519. * Defines the producer of the module.
  520. *
  521. * @param producer the producer.
  522. */
  523. protected void setProducer(final String producer)
  524. {
  525. this.producer = producer;
  526. }
  527. /**
  528. * Returns a copy of the required modules array. This array contains all
  529. * description of the modules that need to be present to make this module work.
  530. * @see Module#getRequiredModules()
  531. *
  532. * @return an array of all required modules.
  533. */
  534. public ModuleInfo[] getRequiredModules()
  535. {
  536. final ModuleInfo[] retval = new ModuleInfo[this.requiredModules.length];
  537. System.arraycopy(this.requiredModules, 0, retval, 0, this.requiredModules.length);
  538. return retval;
  539. }
  540. /**
  541. * Returns a copy of the required modules array. This array contains all
  542. * description of the optional modules that may improve the modules functonality.
  543. * @see Module#getRequiredModules()
  544. *
  545. * @return an array of all required modules.
  546. */
  547. public ModuleInfo[] getOptionalModules()
  548. {
  549. final ModuleInfo[] retval = new ModuleInfo[this.optionalModules.length];
  550. System.arraycopy(this.optionalModules, 0, retval, 0, this.optionalModules.length);
  551. return retval;
  552. }
  553. /**
  554. * Defines the required module descriptions for this module.
  555. *
  556. * @param requiredModules the required modules.
  557. */
  558. protected void setRequiredModules(final ModuleInfo[] requiredModules)
  559. {
  560. this.requiredModules = new ModuleInfo[requiredModules.length];
  561. System.arraycopy(requiredModules, 0, this.requiredModules, 0, requiredModules.length);
  562. }
  563. /**
  564. * Defines the optional module descriptions for this module.
  565. *
  566. * @param optionalModules the optional modules.
  567. */
  568. public void setOptionalModules(final ModuleInfo[] optionalModules)
  569. {
  570. this.optionalModules = new ModuleInfo[optionalModules.length];
  571. System.arraycopy(optionalModules, 0, this.optionalModules, 0, optionalModules.length);
  572. }
  573. /**
  574. * Returns a string representation of this module.
  575. * @see java.lang.Object#toString()
  576. *
  577. * @return the string representation of this module for debugging purposes.
  578. */
  579. public String toString()
  580. {
  581. final StringBuffer buffer = new StringBuffer();
  582. buffer.append("Module : ");
  583. buffer.append(getName());
  584. buffer.append("\n");
  585. buffer.append("ModuleClass : ");
  586. buffer.append(getModuleClass());
  587. buffer.append("\n");
  588. buffer.append("Version: ");
  589. buffer.append(getMajorVersion());
  590. buffer.append(".");
  591. buffer.append(getMinorVersion());
  592. buffer.append(".");
  593. buffer.append(getPatchLevel());
  594. buffer.append("\n");
  595. buffer.append("Producer: ");
  596. buffer.append(getProducer());
  597. buffer.append("\n");
  598. buffer.append("Description: ");
  599. buffer.append(getDescription());
  600. buffer.append("\n");
  601. return buffer.toString();
  602. }
  603. /**
  604. * Tries to load a class to indirectly check for the existence
  605. * of a certain library.
  606. *
  607. * @param name the name of the library class.
  608. * @return true, if the class could be loaded, false otherwise.
  609. * @deprecated use the method that passes in a context-class.
  610. */
  611. protected static boolean isClassLoadable(final String name)
  612. {
  613. try
  614. {
  615. final ClassLoader loader = ObjectUtilities.getClassLoader(AbstractModule.class);
  616. if (loader == null)
  617. {
  618. // this should not happen .. If it happens, it measn we dont even have a system-classloader.
  619. return false;
  620. }
  621. loader.loadClass(name);
  622. return true;
  623. }
  624. catch (Exception e)
  625. {
  626. return false;
  627. }
  628. }
  629. /**
  630. * Tries to load a class to indirectly check for the existence
  631. * of a certain library.
  632. *
  633. * @param name the name of the library class.
  634. * @param context the context class to get a classloader from.
  635. * @return true, if the class could be loaded, false otherwise.
  636. */
  637. protected static boolean isClassLoadable(final String name, final Class context)
  638. {
  639. try
  640. {
  641. ObjectUtilities.getClassLoader(context).loadClass(name);
  642. return true;
  643. }
  644. catch (Exception e)
  645. {
  646. return false;
  647. }
  648. }
  649. /**
  650. * Configures the module by loading the configuration properties and
  651. * adding them to the package configuration.
  652. *
  653. * @param subSystem the subsystem.
  654. */
  655. public void configure(final SubSystem subSystem)
  656. {
  657. final InputStream in = ObjectUtilities.getResourceRelativeAsStream
  658. ("configuration.properties", getClass());
  659. if (in == null)
  660. {
  661. return;
  662. }
  663. try
  664. {
  665. subSystem.getPackageManager().getPackageConfiguration().load(in);
  666. }
  667. finally
  668. {
  669. try
  670. {
  671. in.close();
  672. }
  673. catch (IOException e)
  674. {
  675. // can be ignored ...
  676. }
  677. }
  678. }
  679. /**
  680. * Tries to load an module initializer and uses this initializer to initialize
  681. * the module.
  682. *
  683. * @param classname the class name of the initializer.
  684. * @throws ModuleInitializeException if an error occures
  685. * @deprecated Use the method that provides a class-context instead.
  686. */
  687. protected void performExternalInitialize(final String classname)
  688. throws ModuleInitializeException
  689. {
  690. try
  691. {
  692. final ModuleInitializer mi =
  693. (ModuleInitializer) ObjectUtilities.loadAndInstantiate(classname, AbstractModule.class, ModuleInitializer.class);
  694. if (mi == null)
  695. {
  696. throw new ModuleInitializeException("Failed to load specified initializer class.");
  697. }
  698. mi.performInit();
  699. }
  700. catch (ModuleInitializeException mie)
  701. {
  702. throw mie;
  703. }
  704. catch (Exception e)
  705. {
  706. throw new ModuleInitializeException("Failed to load specified initializer class.", e);
  707. }
  708. }
  709. /**
  710. * ???.
  711. *
  712. * @param classname ?
  713. * @param context ?
  714. * @throws ModuleInitializeException if there is an initialisation error.
  715. */
  716. protected void performExternalInitialize(final String classname, final Class context)
  717. throws ModuleInitializeException
  718. {
  719. try
  720. {
  721. final ModuleInitializer mi =
  722. (ModuleInitializer) ObjectUtilities.loadAndInstantiate(classname, context, ModuleInitializer.class);
  723. if (mi == null)
  724. {
  725. throw new ModuleInitializeException("Failed to load specified initializer class.");
  726. }
  727. mi.performInit();
  728. }
  729. catch (ModuleInitializeException mie)
  730. {
  731. throw mie;
  732. }
  733. catch (Exception e)
  734. {
  735. throw new ModuleInitializeException("Failed to load specified initializer class.", e);
  736. }
  737. }
  738. /**
  739. * Returns the modules subsystem. If this module is not part of an subsystem
  740. * then return the modules name, but never null.
  741. *
  742. * @return the name of the subsystem.
  743. */
  744. public String getSubSystem()
  745. {
  746. if (this.subsystem == null)
  747. {
  748. return getName();
  749. }
  750. return this.subsystem;
  751. }
  752. /**
  753. * Defines the subsystem name for this module.
  754. *
  755. * @param name the new name of the subsystem.
  756. */
  757. protected void setSubSystem (final String name)
  758. {
  759. this.subsystem = name;
  760. }
  761. }