PageRenderTime 860ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/tomcat-7.0.2/java/org/apache/catalina/core/StandardServer.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 755 lines | 351 code | 172 blank | 232 comment | 41 complexity | bbddda3e0251b727f0c388c5e0e81215 MD5 | raw file
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package org.apache.catalina.core;
  18. import java.beans.PropertyChangeListener;
  19. import java.beans.PropertyChangeSupport;
  20. import java.io.IOException;
  21. import java.io.InputStream;
  22. import java.net.InetAddress;
  23. import java.net.ServerSocket;
  24. import java.net.Socket;
  25. import java.security.AccessControlException;
  26. import java.util.Random;
  27. import javax.management.ObjectName;
  28. import org.apache.catalina.Context;
  29. import org.apache.catalina.LifecycleException;
  30. import org.apache.catalina.LifecycleState;
  31. import org.apache.catalina.Engine;
  32. import org.apache.catalina.Server;
  33. import org.apache.catalina.Service;
  34. import org.apache.catalina.deploy.NamingResources;
  35. import org.apache.catalina.mbeans.MBeanFactory;
  36. import org.apache.catalina.mbeans.MBeanUtils;
  37. import org.apache.catalina.util.LifecycleBase;
  38. import org.apache.catalina.util.LifecycleMBeanBase;
  39. import org.apache.tomcat.util.res.StringManager;
  40. import org.apache.catalina.util.ServerInfo;
  41. import org.apache.juli.logging.Log;
  42. import org.apache.juli.logging.LogFactory;
  43. import org.apache.tomcat.util.buf.StringCache;
  44. /**
  45. * Standard implementation of the <b>Server</b> interface, available for use
  46. * (but not required) when deploying and starting Catalina.
  47. *
  48. * @author Craig R. McClanahan
  49. * @version $Id: StandardServer.java 981602 2010-08-02 17:05:03Z markt $
  50. */
  51. public final class StandardServer extends LifecycleMBeanBase
  52. implements Server {
  53. private static final Log log = LogFactory.getLog(StandardServer.class);
  54. // ------------------------------------------------------------ Constructor
  55. /**
  56. * Construct a default instance of this class.
  57. */
  58. public StandardServer() {
  59. super();
  60. globalNamingResources = new NamingResources();
  61. globalNamingResources.setContainer(this);
  62. if (isUseNaming()) {
  63. if (namingContextListener == null) {
  64. namingContextListener = new NamingContextListener();
  65. addLifecycleListener(namingContextListener);
  66. }
  67. }
  68. }
  69. // ----------------------------------------------------- Instance Variables
  70. /**
  71. * Global naming resources context.
  72. */
  73. private javax.naming.Context globalNamingContext = null;
  74. /**
  75. * Global naming resources.
  76. */
  77. private NamingResources globalNamingResources = null;
  78. /**
  79. * Descriptive information about this Server implementation.
  80. */
  81. private static final String info =
  82. "org.apache.catalina.core.StandardServer/1.0";
  83. /**
  84. * The naming context listener for this web application.
  85. */
  86. private NamingContextListener namingContextListener = null;
  87. /**
  88. * The port number on which we wait for shutdown commands.
  89. */
  90. private int port = 8005;
  91. /**
  92. * The address on which we wait for shutdown commands.
  93. */
  94. private String address = "localhost";
  95. /**
  96. * A random number generator that is <strong>only</strong> used if
  97. * the shutdown command string is longer than 1024 characters.
  98. */
  99. private Random random = null;
  100. /**
  101. * The set of Services associated with this Server.
  102. */
  103. private Service services[] = new Service[0];
  104. /**
  105. * The shutdown command string we are looking for.
  106. */
  107. private String shutdown = "SHUTDOWN";
  108. /**
  109. * The string manager for this package.
  110. */
  111. private static final StringManager sm =
  112. StringManager.getManager(Constants.Package);
  113. /**
  114. * The property change support for this component.
  115. */
  116. protected PropertyChangeSupport support = new PropertyChangeSupport(this);
  117. private boolean stopAwait = false;
  118. // ------------------------------------------------------------- Properties
  119. /**
  120. * Return the global naming resources context.
  121. */
  122. public javax.naming.Context getGlobalNamingContext() {
  123. return (this.globalNamingContext);
  124. }
  125. /**
  126. * Set the global naming resources context.
  127. *
  128. * @param globalNamingContext The new global naming resource context
  129. */
  130. public void setGlobalNamingContext
  131. (javax.naming.Context globalNamingContext) {
  132. this.globalNamingContext = globalNamingContext;
  133. }
  134. /**
  135. * Return the global naming resources.
  136. */
  137. public NamingResources getGlobalNamingResources() {
  138. return (this.globalNamingResources);
  139. }
  140. /**
  141. * Set the global naming resources.
  142. *
  143. * @param globalNamingResources The new global naming resources
  144. */
  145. public void setGlobalNamingResources
  146. (NamingResources globalNamingResources) {
  147. NamingResources oldGlobalNamingResources =
  148. this.globalNamingResources;
  149. this.globalNamingResources = globalNamingResources;
  150. this.globalNamingResources.setContainer(this);
  151. support.firePropertyChange("globalNamingResources",
  152. oldGlobalNamingResources,
  153. this.globalNamingResources);
  154. }
  155. /**
  156. * Return descriptive information about this Server implementation and
  157. * the corresponding version number, in the format
  158. * <code>&lt;description&gt;/&lt;version&gt;</code>.
  159. */
  160. public String getInfo() {
  161. return (info);
  162. }
  163. /**
  164. * Report the current Tomcat Server Release number
  165. * @return Tomcat release identifier
  166. */
  167. public String getServerInfo() {
  168. return ServerInfo.getServerInfo();
  169. }
  170. /**
  171. * Return the port number we listen to for shutdown commands.
  172. */
  173. public int getPort() {
  174. return (this.port);
  175. }
  176. /**
  177. * Set the port number we listen to for shutdown commands.
  178. *
  179. * @param port The new port number
  180. */
  181. public void setPort(int port) {
  182. this.port = port;
  183. }
  184. /**
  185. * Return the address on which we listen to for shutdown commands.
  186. */
  187. public String getAddress() {
  188. return (this.address);
  189. }
  190. /**
  191. * Set the address on which we listen to for shutdown commands.
  192. *
  193. * @param address The new address
  194. */
  195. public void setAddress(String address) {
  196. this.address = address;
  197. }
  198. /**
  199. * Return the shutdown command string we are waiting for.
  200. */
  201. public String getShutdown() {
  202. return (this.shutdown);
  203. }
  204. /**
  205. * Set the shutdown command we are waiting for.
  206. *
  207. * @param shutdown The new shutdown command
  208. */
  209. public void setShutdown(String shutdown) {
  210. this.shutdown = shutdown;
  211. }
  212. // --------------------------------------------------------- Server Methods
  213. /**
  214. * Add a new Service to the set of defined Services.
  215. *
  216. * @param service The Service to be added
  217. */
  218. public void addService(Service service) {
  219. service.setServer(this);
  220. synchronized (services) {
  221. Service results[] = new Service[services.length + 1];
  222. System.arraycopy(services, 0, results, 0, services.length);
  223. results[services.length] = service;
  224. services = results;
  225. if (getState().isAvailable()) {
  226. try {
  227. service.start();
  228. } catch (LifecycleException e) {
  229. // Ignore
  230. }
  231. }
  232. // Report this property change to interested listeners
  233. support.firePropertyChange("service", null, service);
  234. }
  235. }
  236. public void stopAwait() {
  237. stopAwait=true;
  238. }
  239. /**
  240. * Wait until a proper shutdown command is received, then return.
  241. * This keeps the main thread alive - the thread pool listening for http
  242. * connections is daemon threads.
  243. */
  244. public void await() {
  245. // Negative values - don't wait on port - tomcat is embedded or we just don't like ports
  246. if( port == -2 ) {
  247. // undocumented yet - for embedding apps that are around, alive.
  248. return;
  249. }
  250. if( port==-1 ) {
  251. while( true ) {
  252. try {
  253. Thread.sleep( 10000 );
  254. } catch( InterruptedException ex ) {
  255. }
  256. if( stopAwait ) return;
  257. }
  258. }
  259. // Set up a server socket to wait on
  260. ServerSocket serverSocket = null;
  261. try {
  262. serverSocket =
  263. new ServerSocket(port, 1,
  264. InetAddress.getByName(address));
  265. } catch (IOException e) {
  266. log.error("StandardServer.await: create[" + address
  267. + ":" + port
  268. + "]: ", e);
  269. System.exit(1);
  270. }
  271. // Loop waiting for a connection and a valid command
  272. while (true) {
  273. // Wait for the next connection
  274. Socket socket = null;
  275. InputStream stream = null;
  276. try {
  277. socket = serverSocket.accept();
  278. socket.setSoTimeout(10 * 1000); // Ten seconds
  279. stream = socket.getInputStream();
  280. } catch (AccessControlException ace) {
  281. log.warn("StandardServer.accept security exception: "
  282. + ace.getMessage(), ace);
  283. continue;
  284. } catch (IOException e) {
  285. log.error("StandardServer.await: accept: ", e);
  286. System.exit(1);
  287. }
  288. // Read a set of characters from the socket
  289. StringBuilder command = new StringBuilder();
  290. int expected = 1024; // Cut off to avoid DoS attack
  291. while (expected < shutdown.length()) {
  292. if (random == null)
  293. random = new Random();
  294. expected += (random.nextInt() % 1024);
  295. }
  296. while (expected > 0) {
  297. int ch = -1;
  298. try {
  299. ch = stream.read();
  300. } catch (IOException e) {
  301. log.warn("StandardServer.await: read: ", e);
  302. ch = -1;
  303. }
  304. if (ch < 32) // Control character or EOF terminates loop
  305. break;
  306. command.append((char) ch);
  307. expected--;
  308. }
  309. // Close the socket now that we are done with it
  310. try {
  311. socket.close();
  312. } catch (IOException e) {
  313. // Ignore
  314. }
  315. // Match against our command string
  316. boolean match = command.toString().equals(shutdown);
  317. if (match) {
  318. log.info(sm.getString("standardServer.shutdownViaPort"));
  319. break;
  320. } else
  321. log.warn("StandardServer.await: Invalid command '" +
  322. command.toString() + "' received");
  323. }
  324. // Close the server socket and return
  325. try {
  326. serverSocket.close();
  327. } catch (IOException e) {
  328. // Ignore
  329. }
  330. }
  331. /**
  332. * Return the specified Service (if it exists); otherwise return
  333. * <code>null</code>.
  334. *
  335. * @param name Name of the Service to be returned
  336. */
  337. public Service findService(String name) {
  338. if (name == null) {
  339. return (null);
  340. }
  341. synchronized (services) {
  342. for (int i = 0; i < services.length; i++) {
  343. if (name.equals(services[i].getName())) {
  344. return (services[i]);
  345. }
  346. }
  347. }
  348. return (null);
  349. }
  350. /**
  351. * Return the set of Services defined within this Server.
  352. */
  353. public Service[] findServices() {
  354. return (services);
  355. }
  356. /**
  357. * Return the JMX service names.
  358. */
  359. public ObjectName[] getServiceNames() {
  360. ObjectName onames[]=new ObjectName[ services.length ];
  361. for( int i=0; i<services.length; i++ ) {
  362. onames[i]=((StandardService)services[i]).getObjectName();
  363. }
  364. return onames;
  365. }
  366. /**
  367. * Remove the specified Service from the set associated from this
  368. * Server.
  369. *
  370. * @param service The Service to be removed
  371. */
  372. public void removeService(Service service) {
  373. synchronized (services) {
  374. int j = -1;
  375. for (int i = 0; i < services.length; i++) {
  376. if (service == services[i]) {
  377. j = i;
  378. break;
  379. }
  380. }
  381. if (j < 0)
  382. return;
  383. try {
  384. services[j].stop();
  385. } catch (LifecycleException e) {
  386. // Ignore
  387. }
  388. int k = 0;
  389. Service results[] = new Service[services.length - 1];
  390. for (int i = 0; i < services.length; i++) {
  391. if (i != j)
  392. results[k++] = services[i];
  393. }
  394. services = results;
  395. // Report this property change to interested listeners
  396. support.firePropertyChange("service", service, null);
  397. }
  398. }
  399. // --------------------------------------------------------- Public Methods
  400. /**
  401. * Add a property change listener to this component.
  402. *
  403. * @param listener The listener to add
  404. */
  405. public void addPropertyChangeListener(PropertyChangeListener listener) {
  406. support.addPropertyChangeListener(listener);
  407. }
  408. /**
  409. * Remove a property change listener from this component.
  410. *
  411. * @param listener The listener to remove
  412. */
  413. public void removePropertyChangeListener(PropertyChangeListener listener) {
  414. support.removePropertyChangeListener(listener);
  415. }
  416. /**
  417. * Return a String representation of this component.
  418. */
  419. @Override
  420. public String toString() {
  421. StringBuilder sb = new StringBuilder("StandardServer[");
  422. sb.append(getPort());
  423. sb.append("]");
  424. return (sb.toString());
  425. }
  426. /**
  427. * Write the configuration information for this entire <code>Server</code>
  428. * out to the server.xml configuration file.
  429. *
  430. * @exception javax.management.InstanceNotFoundException if the managed resource object
  431. * cannot be found
  432. * @exception javax.management.MBeanException if the initializer of the object throws
  433. * an exception, or persistence is not supported
  434. * @exception javax.management.RuntimeOperationsException if an exception is reported
  435. * by the persistence mechanism
  436. */
  437. public synchronized void storeConfig() throws Exception {
  438. ObjectName sname = null;
  439. try {
  440. sname = new ObjectName("Catalina:type=StoreConfig");
  441. if(mserver.isRegistered(sname)) {
  442. mserver.invoke(sname, "storeConfig", null, null);
  443. } else
  444. log.error("StoreConfig mbean not registered" + sname);
  445. } catch (Throwable t) {
  446. log.error(t);
  447. }
  448. }
  449. /**
  450. * Write the configuration information for <code>Context</code>
  451. * out to the specified configuration file.
  452. *
  453. * @exception javax.management.InstanceNotFoundException if the managed resource object
  454. * cannot be found
  455. * @exception javax.management.MBeanException if the initializer of the object throws
  456. * an exception, or persistence is not supported
  457. * @exception javax.management.RuntimeOperationsException if an exception is reported
  458. * by the persistence mechanism
  459. */
  460. public synchronized void storeContext(Context context) throws Exception {
  461. ObjectName sname = null;
  462. try {
  463. sname = new ObjectName("Catalina:type=StoreConfig");
  464. if(mserver.isRegistered(sname)) {
  465. mserver.invoke(sname, "store",
  466. new Object[] {context},
  467. new String [] { "java.lang.String"});
  468. } else
  469. log.error("StoreConfig mbean not registered" + sname);
  470. } catch (Throwable t) {
  471. log.error(t);
  472. }
  473. }
  474. /**
  475. * Return true if naming should be used.
  476. */
  477. private boolean isUseNaming() {
  478. boolean useNaming = true;
  479. // Reading the "catalina.useNaming" environment variable
  480. String useNamingProperty = System.getProperty("catalina.useNaming");
  481. if ((useNamingProperty != null)
  482. && (useNamingProperty.equals("false"))) {
  483. useNaming = false;
  484. }
  485. return useNaming;
  486. }
  487. /**
  488. * Start nested components ({@link Service}s) and implement the requirements
  489. * of {@link LifecycleBase#startInternal()}.
  490. *
  491. * @exception LifecycleException if this component detects a fatal error
  492. * that prevents this component from being used
  493. */
  494. @Override
  495. protected void startInternal() throws LifecycleException {
  496. fireLifecycleEvent(CONFIGURE_START_EVENT, null);
  497. setState(LifecycleState.STARTING);
  498. // Start our defined Services
  499. synchronized (services) {
  500. for (int i = 0; i < services.length; i++) {
  501. services[i].start();
  502. }
  503. }
  504. }
  505. /**
  506. * Stop nested components ({@link Service}s) and implement the requirements
  507. * of {@link LifecycleBase#stopInternal()}.
  508. *
  509. * @exception LifecycleException if this component detects a fatal error
  510. * that needs to be reported
  511. */
  512. @Override
  513. protected void stopInternal() throws LifecycleException {
  514. setState(LifecycleState.STOPPING);
  515. fireLifecycleEvent(CONFIGURE_STOP_EVENT, null);
  516. // Stop our defined Services
  517. for (int i = 0; i < services.length; i++) {
  518. services[i].stop();
  519. }
  520. if (port == -1)
  521. stopAwait();
  522. }
  523. /**
  524. * Invoke a pre-startup initialization. This is used to allow connectors
  525. * to bind to restricted ports under Unix operating environments.
  526. */
  527. @Override
  528. protected void initInternal() throws LifecycleException {
  529. super.initInternal();
  530. // Register global String cache
  531. // Note although the cache is global, if there are multiple Servers
  532. // present in the JVM (may happen when embedding) then the same cache
  533. // will be registered under multiple names
  534. onameStringCache = register(new StringCache(), "type=StringCache");
  535. // Register the MBeanFactory
  536. onameMBeanFactory = register(new MBeanFactory(), "type=MBeanFactory");
  537. // Register the naming resources
  538. onameNamingResoucres = register(globalNamingResources,
  539. "type=NamingResources");
  540. // Initialize our defined Services
  541. for (int i = 0; i < services.length; i++) {
  542. services[i].init();
  543. }
  544. }
  545. @Override
  546. protected void destroyInternal() throws LifecycleException {
  547. // Destroy our defined Services
  548. for (int i = 0; i < services.length; i++) {
  549. services[i].destroy();
  550. }
  551. unregister(onameMBeanFactory);
  552. unregister(onameStringCache);
  553. unregister(onameNamingResoucres);
  554. super.destroyInternal();
  555. }
  556. private ObjectName onameStringCache;
  557. private ObjectName onameMBeanFactory;
  558. private ObjectName onameNamingResoucres;
  559. /**
  560. * Obtain the MBean domain for this server. The domain is obtained using
  561. * the following search order:
  562. * <ol>
  563. * <li>Name of first {@link Engine}.</li>
  564. * <li>Name of first {@link Service}.</li>
  565. * </ol>
  566. */
  567. @Override
  568. protected String getDomainInternal() {
  569. String domain = null;
  570. Service[] services = findServices();
  571. if (services.length > 0) {
  572. Service service = services[0];
  573. if (service != null) {
  574. domain = MBeanUtils.getDomain(service);
  575. }
  576. }
  577. return domain;
  578. }
  579. @Override
  580. protected final String getObjectNameKeyProperties() {
  581. return "type=Server";
  582. }
  583. }