PageRenderTime 49ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/projects/tomcat-7.0.2/java/org/apache/coyote/ajp/AjpAprProtocol.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 554 lines | 363 code | 99 blank | 92 comment | 41 complexity | 22472d35c824d43269ed133322e7cb8a 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.coyote.ajp;
  18. import java.net.InetAddress;
  19. import java.net.URLEncoder;
  20. import java.util.Hashtable;
  21. import java.util.Iterator;
  22. import java.util.concurrent.ConcurrentHashMap;
  23. import java.util.concurrent.ConcurrentLinkedQueue;
  24. import java.util.concurrent.Executor;
  25. import java.util.concurrent.atomic.AtomicInteger;
  26. import java.util.concurrent.atomic.AtomicLong;
  27. import javax.management.MBeanRegistration;
  28. import javax.management.MBeanServer;
  29. import javax.management.ObjectName;
  30. import org.apache.coyote.ActionCode;
  31. import org.apache.coyote.Adapter;
  32. import org.apache.coyote.ProtocolHandler;
  33. import org.apache.coyote.RequestGroupInfo;
  34. import org.apache.coyote.RequestInfo;
  35. import org.apache.juli.logging.Log;
  36. import org.apache.juli.logging.LogFactory;
  37. import org.apache.tomcat.util.modeler.Registry;
  38. import org.apache.tomcat.util.net.AprEndpoint;
  39. import org.apache.tomcat.util.net.SocketStatus;
  40. import org.apache.tomcat.util.net.AprEndpoint.Handler;
  41. import org.apache.tomcat.util.res.StringManager;
  42. /**
  43. * Abstract the protocol implementation, including threading, etc.
  44. * Processor is single threaded and specific to stream-based protocols,
  45. * will not fit Jk protocols like JNI.
  46. *
  47. * @author Remy Maucherat
  48. * @author Costin Manolache
  49. */
  50. public class AjpAprProtocol
  51. implements ProtocolHandler, MBeanRegistration {
  52. private static final Log log = LogFactory.getLog(AjpAprProtocol.class);
  53. /**
  54. * The string manager for this package.
  55. */
  56. protected static final StringManager sm =
  57. StringManager.getManager(Constants.Package);
  58. // ------------------------------------------------------------ Constructor
  59. public AjpAprProtocol() {
  60. cHandler = new AjpConnectionHandler(this);
  61. setSoLinger(Constants.DEFAULT_CONNECTION_LINGER);
  62. setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
  63. //setServerSoTimeout(Constants.DEFAULT_SERVER_SOCKET_TIMEOUT);
  64. setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY);
  65. }
  66. // ----------------------------------------------------- Instance Variables
  67. protected ObjectName tpOname;
  68. protected ObjectName rgOname;
  69. /**
  70. * Associated APR endpoint.
  71. */
  72. protected AprEndpoint endpoint = new AprEndpoint();
  73. /**
  74. * Configuration attributes.
  75. */
  76. protected Hashtable<String,Object> attributes =
  77. new Hashtable<String,Object>();
  78. /**
  79. * Adapter which will process the requests received by this endpoint.
  80. */
  81. private Adapter adapter;
  82. /**
  83. * Connection handler for AJP.
  84. */
  85. private AjpConnectionHandler cHandler;
  86. // --------------------------------------------------------- Public Methods
  87. /**
  88. * Pass config info
  89. */
  90. public void setAttribute(String name, Object value) {
  91. if (log.isTraceEnabled()) {
  92. log.trace(sm.getString("ajpprotocol.setattribute", name, value));
  93. }
  94. attributes.put(name, value);
  95. }
  96. public Object getAttribute(String key) {
  97. if (log.isTraceEnabled()) {
  98. log.trace(sm.getString("ajpprotocol.getattribute", key));
  99. }
  100. return attributes.get(key);
  101. }
  102. public Iterator<String> getAttributeNames() {
  103. return attributes.keySet().iterator();
  104. }
  105. /**
  106. * The adapter, used to call the connector
  107. */
  108. public void setAdapter(Adapter adapter) {
  109. this.adapter = adapter;
  110. }
  111. public Adapter getAdapter() {
  112. return adapter;
  113. }
  114. /** Start the protocol
  115. */
  116. public void init() throws Exception {
  117. endpoint.setName(getName());
  118. endpoint.setHandler(cHandler);
  119. endpoint.setUseSendfile(false);
  120. try {
  121. endpoint.init();
  122. } catch (Exception ex) {
  123. log.error(sm.getString("ajpprotocol.endpoint.initerror"), ex);
  124. throw ex;
  125. }
  126. if (log.isInfoEnabled()) {
  127. log.info(sm.getString("ajpprotocol.init", getName()));
  128. }
  129. }
  130. public void start() throws Exception {
  131. if (this.domain != null ) {
  132. try {
  133. tpOname = new ObjectName
  134. (domain + ":" + "type=ThreadPool,name=" + getName());
  135. Registry.getRegistry(null, null)
  136. .registerComponent(endpoint, tpOname, null );
  137. } catch (Exception e) {
  138. log.error("Can't register threadpool" );
  139. }
  140. rgOname = new ObjectName
  141. (domain + ":type=GlobalRequestProcessor,name=" + getName());
  142. Registry.getRegistry(null, null).registerComponent
  143. (cHandler.global, rgOname, null);
  144. }
  145. try {
  146. endpoint.start();
  147. } catch (Exception ex) {
  148. log.error(sm.getString("ajpprotocol.endpoint.starterror"), ex);
  149. throw ex;
  150. }
  151. if (log.isInfoEnabled())
  152. log.info(sm.getString("ajpprotocol.start", getName()));
  153. }
  154. public void pause() throws Exception {
  155. try {
  156. endpoint.pause();
  157. } catch (Exception ex) {
  158. log.error(sm.getString("ajpprotocol.endpoint.pauseerror"), ex);
  159. throw ex;
  160. }
  161. if (log.isInfoEnabled())
  162. log.info(sm.getString("ajpprotocol.pause", getName()));
  163. }
  164. public void resume() throws Exception {
  165. try {
  166. endpoint.resume();
  167. } catch (Exception ex) {
  168. log.error(sm.getString("ajpprotocol.endpoint.resumeerror"), ex);
  169. throw ex;
  170. }
  171. if (log.isInfoEnabled())
  172. log.info(sm.getString("ajpprotocol.resume", getName()));
  173. }
  174. public void destroy() throws Exception {
  175. if (log.isInfoEnabled())
  176. log.info(sm.getString("ajpprotocol.stop", getName()));
  177. endpoint.destroy();
  178. if (tpOname!=null)
  179. Registry.getRegistry(null, null).unregisterComponent(tpOname);
  180. if (rgOname != null)
  181. Registry.getRegistry(null, null).unregisterComponent(rgOname);
  182. }
  183. // *
  184. public String getName() {
  185. String encodedAddr = "";
  186. if (getAddress() != null) {
  187. encodedAddr = "" + getAddress();
  188. if (encodedAddr.startsWith("/"))
  189. encodedAddr = encodedAddr.substring(1);
  190. encodedAddr = URLEncoder.encode(encodedAddr) + "-";
  191. }
  192. return ("ajp-" + encodedAddr + endpoint.getPort());
  193. }
  194. /**
  195. * Processor cache.
  196. */
  197. protected int processorCache = -1;
  198. public int getProcessorCache() { return this.processorCache; }
  199. public void setProcessorCache(int processorCache) { this.processorCache = processorCache; }
  200. public Executor getExecutor() { return endpoint.getExecutor(); }
  201. public void setExecutor(Executor executor) { endpoint.setExecutor(executor); }
  202. public int getMaxThreads() { return endpoint.getMaxThreads(); }
  203. public void setMaxThreads(int maxThreads) { endpoint.setMaxThreads(maxThreads); }
  204. public int getThreadPriority() { return endpoint.getThreadPriority(); }
  205. public void setThreadPriority(int threadPriority) { endpoint.setThreadPriority(threadPriority); }
  206. public int getBacklog() { return endpoint.getBacklog(); }
  207. public void setBacklog(int backlog) { endpoint.setBacklog(backlog); }
  208. public int getPort() { return endpoint.getPort(); }
  209. public void setPort(int port) { endpoint.setPort(port); }
  210. public InetAddress getAddress() { return endpoint.getAddress(); }
  211. public void setAddress(InetAddress ia) { endpoint.setAddress(ia); }
  212. public boolean getTcpNoDelay() { return endpoint.getTcpNoDelay(); }
  213. public void setTcpNoDelay(boolean tcpNoDelay) { endpoint.setTcpNoDelay(tcpNoDelay); }
  214. public int getSoLinger() { return endpoint.getSoLinger(); }
  215. public void setSoLinger(int soLinger) { endpoint.setSoLinger(soLinger); }
  216. public int getSoTimeout() { return endpoint.getSoTimeout(); }
  217. public void setSoTimeout(int soTimeout) { endpoint.setSoTimeout(soTimeout); }
  218. /**
  219. * Should authentication be done in the native webserver layer,
  220. * or in the Servlet container ?
  221. */
  222. protected boolean tomcatAuthentication = true;
  223. public boolean getTomcatAuthentication() { return tomcatAuthentication; }
  224. public void setTomcatAuthentication(boolean tomcatAuthentication) { this.tomcatAuthentication = tomcatAuthentication; }
  225. /**
  226. * Required secret.
  227. */
  228. protected String requiredSecret = null;
  229. public void setRequiredSecret(String requiredSecret) { this.requiredSecret = requiredSecret; }
  230. /**
  231. * AJP packet size.
  232. */
  233. protected int packetSize = Constants.MAX_PACKET_SIZE;
  234. public int getPacketSize() { return packetSize; }
  235. public void setPacketSize(int packetSize) {
  236. if(packetSize < Constants.MAX_PACKET_SIZE) {
  237. this.packetSize = Constants.MAX_PACKET_SIZE;
  238. } else {
  239. this.packetSize = packetSize;
  240. }
  241. }
  242. /**
  243. * The number of seconds Tomcat will wait for a subsequent request
  244. * before closing the connection.
  245. */
  246. public int getKeepAliveTimeout() { return endpoint.getKeepAliveTimeout(); }
  247. public void setKeepAliveTimeout(int timeout) { endpoint.setKeepAliveTimeout(timeout); }
  248. public boolean getUseSendfile() { return endpoint.getUseSendfile(); }
  249. public void setUseSendfile(boolean useSendfile) { /* No sendfile for AJP */ }
  250. public int getPollTime() { return endpoint.getPollTime(); }
  251. public void setPollTime(int pollTime) { endpoint.setPollTime(pollTime); }
  252. public void setPollerSize(int pollerSize) { endpoint.setPollerSize(pollerSize); }
  253. public int getPollerSize() { return endpoint.getPollerSize(); }
  254. // -------------------------------------- AjpConnectionHandler Inner Class
  255. protected static class AjpConnectionHandler implements Handler {
  256. protected AjpAprProtocol proto;
  257. protected AtomicLong registerCount = new AtomicLong(0);
  258. protected RequestGroupInfo global = new RequestGroupInfo();
  259. protected ConcurrentHashMap<Long, AjpAprProcessor> connections =
  260. new ConcurrentHashMap<Long, AjpAprProcessor>();
  261. protected ConcurrentLinkedQueue<AjpAprProcessor> recycledProcessors =
  262. new ConcurrentLinkedQueue<AjpAprProcessor>() {
  263. protected AtomicInteger size = new AtomicInteger(0);
  264. @Override
  265. public boolean offer(AjpAprProcessor processor) {
  266. boolean offer = (proto.processorCache == -1) ? true : (size.get() < proto.processorCache);
  267. //avoid over growing our cache or add after we have stopped
  268. boolean result = false;
  269. if ( offer ) {
  270. result = super.offer(processor);
  271. if ( result ) {
  272. size.incrementAndGet();
  273. }
  274. }
  275. if (!result) unregister(processor);
  276. return result;
  277. }
  278. @Override
  279. public AjpAprProcessor poll() {
  280. AjpAprProcessor result = super.poll();
  281. if ( result != null ) {
  282. size.decrementAndGet();
  283. }
  284. return result;
  285. }
  286. @Override
  287. public void clear() {
  288. AjpAprProcessor next = poll();
  289. while ( next != null ) {
  290. unregister(next);
  291. next = poll();
  292. }
  293. super.clear();
  294. size.set(0);
  295. }
  296. };
  297. public AjpConnectionHandler(AjpAprProtocol proto) {
  298. this.proto = proto;
  299. }
  300. // FIXME: Support for this could be added in AJP as well
  301. public SocketState event(long socket, SocketStatus status) {
  302. return SocketState.CLOSED;
  303. }
  304. public SocketState process(long socket) {
  305. AjpAprProcessor processor = recycledProcessors.poll();
  306. try {
  307. if (processor == null) {
  308. processor = createProcessor();
  309. }
  310. processor.action(ActionCode.ACTION_START, null);
  311. if (processor.process(socket)) {
  312. connections.put(Long.valueOf(socket), processor);
  313. return SocketState.OPEN;
  314. } else {
  315. // recycledProcessors.offer(processor);
  316. return SocketState.CLOSED;
  317. }
  318. } catch(java.net.SocketException e) {
  319. // SocketExceptions are normal
  320. AjpAprProtocol.log.debug
  321. (sm.getString
  322. ("ajpprotocol.proto.socketexception.debug"), e);
  323. } catch (java.io.IOException e) {
  324. // IOExceptions are normal
  325. AjpAprProtocol.log.debug
  326. (sm.getString
  327. ("ajpprotocol.proto.ioexception.debug"), e);
  328. }
  329. // Future developers: if you discover any other
  330. // rare-but-nonfatal exceptions, catch them here, and log as
  331. // above.
  332. catch (Throwable e) {
  333. // any other exception or error is odd. Here we log it
  334. // with "ERROR" level, so it will show up even on
  335. // less-than-verbose logs.
  336. AjpAprProtocol.log.error
  337. (sm.getString("ajpprotocol.proto.error"), e);
  338. } finally {
  339. processor.action(ActionCode.ACTION_STOP, null);
  340. recycledProcessors.offer(processor);
  341. }
  342. return SocketState.CLOSED;
  343. }
  344. // FIXME: Support for this could be added in AJP as well
  345. public SocketState asyncDispatch(long socket, SocketStatus status) {
  346. AjpAprProcessor result = connections.get(Long.valueOf(socket));
  347. SocketState state = SocketState.CLOSED;
  348. if (result != null) {
  349. // Call the appropriate event
  350. try {
  351. state = result.asyncDispatch(socket, status);
  352. } catch (java.net.SocketException e) {
  353. // SocketExceptions are normal
  354. AjpAprProtocol.log.debug
  355. (sm.getString
  356. ("ajpprotocol.proto.socketexception.debug"), e);
  357. } catch (java.io.IOException e) {
  358. // IOExceptions are normal
  359. AjpAprProtocol.log.debug
  360. (sm.getString
  361. ("ajpprotocol.proto.ioexception.debug"), e);
  362. }
  363. // Future developers: if you discover any other
  364. // rare-but-nonfatal exceptions, catch them here, and log as
  365. // above.
  366. catch (Throwable e) {
  367. // any other exception or error is odd. Here we log it
  368. // with "ERROR" level, so it will show up even on
  369. // less-than-verbose logs.
  370. AjpAprProtocol.log.error
  371. (sm.getString("ajpprotocol.proto.error"), e);
  372. } finally {
  373. if (state != SocketState.LONG) {
  374. connections.remove(Long.valueOf(socket));
  375. recycledProcessors.offer(result);
  376. if (state == SocketState.OPEN) {
  377. proto.endpoint.getPoller().add(socket);
  378. }
  379. }
  380. }
  381. }
  382. return state;
  383. }
  384. protected AjpAprProcessor createProcessor() {
  385. AjpAprProcessor processor = new AjpAprProcessor(proto.packetSize, proto.endpoint);
  386. processor.setAdapter(proto.adapter);
  387. processor.setTomcatAuthentication(proto.tomcatAuthentication);
  388. processor.setRequiredSecret(proto.requiredSecret);
  389. register(processor);
  390. return processor;
  391. }
  392. protected void register(AjpAprProcessor processor) {
  393. if (proto.getDomain() != null) {
  394. synchronized (this) {
  395. try {
  396. long count = registerCount.incrementAndGet();
  397. RequestInfo rp = processor.getRequest().getRequestProcessor();
  398. rp.setGlobalProcessor(global);
  399. ObjectName rpName = new ObjectName
  400. (proto.getDomain() + ":type=RequestProcessor,worker="
  401. + proto.getName() + ",name=AjpRequest" + count);
  402. if (log.isDebugEnabled()) {
  403. log.debug("Register " + rpName);
  404. }
  405. Registry.getRegistry(null, null).registerComponent(rp, rpName, null);
  406. rp.setRpName(rpName);
  407. } catch (Exception e) {
  408. log.warn("Error registering request");
  409. }
  410. }
  411. }
  412. }
  413. protected void unregister(AjpAprProcessor processor) {
  414. if (proto.getDomain() != null) {
  415. synchronized (this) {
  416. try {
  417. RequestInfo rp = processor.getRequest().getRequestProcessor();
  418. rp.setGlobalProcessor(null);
  419. ObjectName rpName = rp.getRpName();
  420. if (log.isDebugEnabled()) {
  421. log.debug("Unregister " + rpName);
  422. }
  423. Registry.getRegistry(null, null).unregisterComponent(rpName);
  424. rp.setRpName(null);
  425. } catch (Exception e) {
  426. log.warn("Error unregistering request", e);
  427. }
  428. }
  429. }
  430. }
  431. }
  432. // -------------------- Various implementation classes --------------------
  433. protected String domain;
  434. protected ObjectName oname;
  435. protected MBeanServer mserver;
  436. public ObjectName getObjectName() {
  437. return oname;
  438. }
  439. public String getDomain() {
  440. return domain;
  441. }
  442. public ObjectName preRegister(MBeanServer server,
  443. ObjectName name) throws Exception {
  444. oname=name;
  445. mserver=server;
  446. domain=name.getDomain();
  447. return name;
  448. }
  449. public void postRegister(Boolean registrationDone) {
  450. }
  451. public void preDeregister() throws Exception {
  452. }
  453. public void postDeregister() {
  454. }
  455. }