AprEndpoint.java

Index Score
org.apache.tomcat.util.net
Apache Tomcat

View: Reasons, Metrics, Source Code

These are the metrics that contribute to the Enerjy Score for this file, ranked by impact. So the metrics listed at the top influence the score to a greater extent that the metrics listed at the bottom.

MetricDescription
EXEC_COMMENTSComments in executable code
LINE_COMMENTNumber of line comments
DECL_COMMENTSComments in declarations
BLOCKSNumber of blocks
CYCLOMATICCyclomatic complexity
LOOPSNumber of loops
SIZESize of the file in bytes
FUNCTIONSNumber of function declarations
LINESNumber of lines in the source file
COMMENTSComment lines
RETURNSNumber of return points from functions
LOGICAL_LINESNumber of statements
JAVA0117JAVA0117 Missing javadoc: method 'method'
OPERATORSNumber of operators
PROGRAM_LENGTHHalstead program length
ELOCEffective lines of code
LOCLines of code
DOC_COMMENTNumber of javadoc comment lines
INTERFACE_COMPLEXITYInterface complexity
OPERANDSNumber of operands
COMPARISONSNumber of comparison operators
WHITESPACENumber of whitespace lines
UNIQUE_OPERANDSNumber of unique operands
PROGRAM_VOCABHalstead program vocabulary
JAVA0110JAVA0110 Incorrect javadoc: no @return tag
JAVA0049JAVA0049 Nested block at depth N (maximum: M)
EXITSProcedure exits
JAVA0076JAVA0076 Use of magic number
JAVA0166JAVA0166 Generic exception caught
PARAMSNumber of formal parameter declarations
JAVA0264JAVA0264 Integer math in long context - check for overflow
JAVA0034JAVA0034 Missing braces in if statement
JAVA0108JAVA0108 Incorrect javadoc: no @param tag for 'parameter'
JAVA0170JAVA0170 Caught exception not derived from java.lang.Exception
JAVA0143JAVA0143 Synchronized method
JAVA0270JAVA0270 Use Java 5.0 enhanced for loop construct to iterate over all elements in an array
JAVA0128JAVA0128 Public constructor in non-public class
JAVA0007JAVA0007 Should not declare public field
JAVA0116JAVA0116 Missing javadoc: field 'field'
JAVA0174JAVA0174 Assigned local variable never used
JAVA0075JAVA0075 Method parameter hides field
JAVA0087JAVA0087 Use of Thread.sleep()
UNIQUE_OPERATORSNumber of unique operators
JAVA0084JAVA0084 Should use compound assignment operator
NEST_DEPTHMaximum nesting depth
JAVA0115JAVA0115 Incorrect javadoc: no @throws or @exception tag for 'exception'
JAVA0137JAVA0137 Non-abstract class missing constructor
JAVA0179JAVA0179 Local variable hides visible field
JAVA0096JAVA0096 Field in nested class hides outer field
PROGRAM_VOLUMEHalstead program volume
JAVA0136JAVA0136 N methods defined in class (maximum: M)
JAVA0160JAVA0160 Method does not throw specified exception
JAVA0126JAVA0126 Method declares unchecked exception in throws
JAVA0043JAVA0043 Inner class does not use outer class
JAVA0066JAVA0066 Unnecessary modifier for interface nested type
JAVA0100JAVA0100 Class contains N non-final fields (maximum: M)
JAVA0145JAVA0145 Tab character used in source file
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.tomcat.util.net; import java.net.InetAddress; import java.util.ArrayList; import java.util.HashMap; import java.util.concurrent.Executor; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.jni.Address; import org.apache.tomcat.jni.Error; import org.apache.tomcat.jni.File; import org.apache.tomcat.jni.Library; import org.apache.tomcat.jni.OS; import org.apache.tomcat.jni.Poll; import org.apache.tomcat.jni.Pool; import org.apache.tomcat.jni.SSL; import org.apache.tomcat.jni.SSLContext; import org.apache.tomcat.jni.SSLSocket; import org.apache.tomcat.jni.Socket; import org.apache.tomcat.jni.Status; import org.apache.tomcat.util.res.StringManager; /** * APR tailored thread pool, providing the following services: * <ul> * <li>Socket acceptor thread</li> * <li>Socket poller thread</li> * <li>Sendfile thread</li> * <li>Worker threads pool</li> * </ul> * * When switching to Java 5, there's an opportunity to use the virtual * machine's thread pool. * * @author Mladen Turk * @author Remy Maucherat */ public class AprEndpoint { // -------------------------------------------------------------- Constants protected static Log log = LogFactory.getLog(AprEndpoint.class); protected static StringManager sm = StringManager.getManager("org.apache.tomcat.util.net.res"); /** * The Request attribute key for the cipher suite. */ public static final String CIPHER_SUITE_KEY = "javax.servlet.request.cipher_suite"; /** * The Request attribute key for the key size. */ public static final String KEY_SIZE_KEY = "javax.servlet.request.key_size"; /** * The Request attribute key for the client certificate chain. */ public static final String CERTIFICATE_KEY = "javax.servlet.request.X509Certificate"; /** * The Request attribute key for the session id. * This one is a Tomcat extension to the Servlet spec. */ public static final String SESSION_ID_KEY = "javax.servlet.request.ssl_session"; // ----------------------------------------------------------------- Fields /** * Available workers. */ protected WorkerStack workers = null; /** * Running state of the endpoint. */ protected volatile boolean running = false; /** * Will be set to true whenever the endpoint is paused. */ protected volatile boolean paused = false; /** * Track the initialization state of the endpoint. */ protected boolean initialized = false; /** * Current worker threads busy count. */ protected int curThreadsBusy = 0; /** * Current worker threads count. */ protected int curThreads = 0; /** * Sequence number used to generate thread names. */ protected int sequence = 0; /** * Root APR memory pool. */ protected long rootPool = 0; /** * Server socket "pointer". */ protected long serverSock = 0; /** * APR memory pool for the server socket. */ protected long serverSockPool = 0; /** * SSL context. */ protected long sslContext = 0; /** * Defer accept. */ protected boolean deferAccept = true; // ------------------------------------------------------------- Properties /** * External Executor based thread pool. */ protected Executor executor = null; public void setExecutor(Executor executor) { this.executor = executor; } public Executor getExecutor() { return executor; } /** * Maximum amount of worker threads. */ protected int maxThreads = 40; public void setMaxThreads(int maxThreads) { this.maxThreads = maxThreads; } public int getMaxThreads() { return maxThreads; } /** * Priority of the acceptor and poller threads. */ protected int threadPriority = Thread.NORM_PRIORITY; public void setThreadPriority(int threadPriority) { this.threadPriority = threadPriority; } public int getThreadPriority() { return threadPriority; } /** * Size of the socket poller. */ protected int pollerSize = 8 * 1024; public void setPollerSize(int pollerSize) { this.pollerSize = pollerSize; } public int getPollerSize() { return pollerSize; } /** * Size of the sendfile (= concurrent files which can be served). */ protected int sendfileSize = 1 * 1024; public void setSendfileSize(int sendfileSize) { this.sendfileSize = sendfileSize; } public int getSendfileSize() { return sendfileSize; } /** * Server socket port. */ protected int port; public int getPort() { return port; } public void setPort(int port ) { this.port=port; } /** * Address for the server socket. */ protected InetAddress address; public InetAddress getAddress() { return address; } public void setAddress(InetAddress address) { this.address = address; } /** * Handling of accepted sockets. */ protected Handler handler = null; public void setHandler(Handler handler ) { this.handler = handler; } public Handler getHandler() { return handler; } /** * Allows the server developer to specify the backlog that * should be used for server sockets. By default, this value * is 100. */ protected int backlog = 100; public void setBacklog(int backlog) { if (backlog > 0) this.backlog = backlog; } public int getBacklog() { return backlog; } /** * Socket TCP no delay. */ protected boolean tcpNoDelay = false; public boolean getTcpNoDelay() { return tcpNoDelay; } public void setTcpNoDelay(boolean tcpNoDelay) { this.tcpNoDelay = tcpNoDelay; } /** * Socket linger. */ protected int soLinger = 100; public int getSoLinger() { return soLinger; } public void setSoLinger(int soLinger) { this.soLinger = soLinger; } /** * Socket timeout. */ protected int soTimeout = -1; public int getSoTimeout() { return soTimeout; } public void setSoTimeout(int soTimeout) { this.soTimeout = soTimeout; } /** * Keep-Alive timeout. */ protected int keepAliveTimeout = -1; public int getKeepAliveTimeout() { return keepAliveTimeout; } public void setKeepAliveTimeout(int keepAliveTimeout) { this.keepAliveTimeout = keepAliveTimeout; } /** * Poll interval, in microseconds. The smaller the value, the more CPU the poller * will use, but the more responsive to activity it will be. */ protected int pollTime = 2000; public int getPollTime() { return pollTime; } public void setPollTime(int pollTime) { if (pollTime > 0) { this.pollTime = pollTime; } } /** * The default is true - the created threads will be * in daemon mode. If set to false, the control thread * will not be daemon - and will keep the process alive. */ protected boolean daemon = true; public void setDaemon(boolean b) { daemon = b; } public boolean getDaemon() { return daemon; } /** * Name of the thread pool, which will be used for naming child threads. */ protected String name = "TP"; public void setName(String name) { this.name = name; } public String getName() { return name; } /** * Use endfile for sending static files. */ protected boolean useSendfile = Library.APR_HAS_SENDFILE; public void setUseSendfile(boolean useSendfile) { this.useSendfile = useSendfile; } public boolean getUseSendfile() { return useSendfile; } /** * Allow comet request handling. */ protected boolean useComet = true; public void setUseComet(boolean useComet) { this.useComet = useComet; } public boolean getUseComet() { return useComet; } /** * Acceptor thread count. */ protected int acceptorThreadCount = 0; public void setAcceptorThreadCount(int acceptorThreadCount) { this.acceptorThreadCount = acceptorThreadCount; } public int getAcceptorThreadCount() { return acceptorThreadCount; } /** * Sendfile thread count. */ protected int sendfileThreadCount = 0; public void setSendfileThreadCount(int sendfileThreadCount) { this.sendfileThreadCount = sendfileThreadCount; } public int getSendfileThreadCount() { return sendfileThreadCount; } /** * Poller thread count. */ protected int pollerThreadCount = 0; public void setPollerThreadCount(int pollerThreadCount) { this.pollerThreadCount = pollerThreadCount; } public int getPollerThreadCount() { return pollerThreadCount; } /** * The socket poller. */ protected Poller[] pollers = null; protected int pollerRoundRobin = 0; public Poller getPoller() { pollerRoundRobin = (pollerRoundRobin + 1) % pollers.length; return pollers[pollerRoundRobin]; } /** * The socket poller used for Comet support. */ protected Poller[] cometPollers = null; protected int cometPollerRoundRobin = 0; public Poller getCometPoller() { cometPollerRoundRobin = (cometPollerRoundRobin + 1) % cometPollers.length; return cometPollers[cometPollerRoundRobin]; } /** * The static file sender. */ protected Sendfile[] sendfiles = null; protected int sendfileRoundRobin = 0; public Sendfile getSendfile() { sendfileRoundRobin = (sendfileRoundRobin + 1) % sendfiles.length; return sendfiles[sendfileRoundRobin]; } /** * Dummy maxSpareThreads property. */ public int getMaxSpareThreads() { return 0; } /** * Dummy minSpareThreads property. */ public int getMinSpareThreads() { return 0; } /** * SSL engine. */ protected boolean SSLEnabled = false; public boolean isSSLEnabled() { return SSLEnabled; } public void setSSLEnabled(boolean SSLEnabled) { this.SSLEnabled = SSLEnabled; } /** * SSL protocols. */ protected String SSLProtocol = "all"; public String getSSLProtocol() { return SSLProtocol; } public void setSSLProtocol(String SSLProtocol) { this.SSLProtocol = SSLProtocol; } /** * SSL password (if a cert is encrypted, and no password has been provided, a callback * will ask for a password). */ protected String SSLPassword = null; public String getSSLPassword() { return SSLPassword; } public void setSSLPassword(String SSLPassword) { this.SSLPassword = SSLPassword; } /** * SSL cipher suite. */ protected String SSLCipherSuite = "ALL"; public String getSSLCipherSuite() { return SSLCipherSuite; } public void setSSLCipherSuite(String SSLCipherSuite) { this.SSLCipherSuite = SSLCipherSuite; } /** * SSL certificate file. */ protected String SSLCertificateFile = null; public String getSSLCertificateFile() { return SSLCertificateFile; } public void setSSLCertificateFile(String SSLCertificateFile) { this.SSLCertificateFile = SSLCertificateFile; } /** * SSL certificate key file. */ protected String SSLCertificateKeyFile = null; public String getSSLCertificateKeyFile() { return SSLCertificateKeyFile; } public void setSSLCertificateKeyFile(String SSLCertificateKeyFile) { this.SSLCertificateKeyFile = SSLCertificateKeyFile; } /** * SSL certificate chain file. */ protected String SSLCertificateChainFile = null; public String getSSLCertificateChainFile() { return SSLCertificateChainFile; } public void setSSLCertificateChainFile(String SSLCertificateChainFile) { this.SSLCertificateChainFile = SSLCertificateChainFile; } /** * SSL CA certificate path. */ protected String SSLCACertificatePath = null; public String getSSLCACertificatePath() { return SSLCACertificatePath; } public void setSSLCACertificatePath(String SSLCACertificatePath) { this.SSLCACertificatePath = SSLCACertificatePath; } /** * SSL CA certificate file. */ protected String SSLCACertificateFile = null; public String getSSLCACertificateFile() { return SSLCACertificateFile; } public void setSSLCACertificateFile(String SSLCACertificateFile) { this.SSLCACertificateFile = SSLCACertificateFile; } /** * SSL CA revocation path. */ protected String SSLCARevocationPath = null; public String getSSLCARevocationPath() { return SSLCARevocationPath; } public void setSSLCARevocationPath(String SSLCARevocationPath) { this.SSLCARevocationPath = SSLCARevocationPath; } /** * SSL CA revocation file. */ protected String SSLCARevocationFile = null; public String getSSLCARevocationFile() { return SSLCARevocationFile; } public void setSSLCARevocationFile(String SSLCARevocationFile) { this.SSLCARevocationFile = SSLCARevocationFile; } /** * SSL verify client. */ protected String SSLVerifyClient = "none"; public String getSSLVerifyClient() { return SSLVerifyClient; } public void setSSLVerifyClient(String SSLVerifyClient) { this.SSLVerifyClient = SSLVerifyClient; } /** * SSL verify depth. */ protected int SSLVerifyDepth = 10; public int getSSLVerifyDepth() { return SSLVerifyDepth; } public void setSSLVerifyDepth(int SSLVerifyDepth) { this.SSLVerifyDepth = SSLVerifyDepth; } // --------------------------------------------------------- Public Methods /** * Number of keepalive sockets. */ public int getKeepAliveCount() { if (pollers == null) { return 0; } else { int keepAliveCount = 0; for (int i = 0; i < pollers.length; i++) { keepAliveCount += pollers[i].getKeepAliveCount(); } return keepAliveCount; } } /** * Number of sendfile sockets. */ public int getSendfileCount() { if (sendfiles == null) { return 0; } else { int sendfileCount = 0; for (int i = 0; i < sendfiles.length; i++) { sendfileCount += sendfiles[i].getSendfileCount(); } return sendfileCount; } } /** * Return the amount of threads that are managed by the pool. * * @return the amount of threads that are managed by the pool */ public int getCurrentThreadCount() { return curThreads; } /** * Return the amount of threads currently busy. * * @return the amount of threads currently busy */ public int getCurrentThreadsBusy() { return curThreadsBusy; } /** * Return the state of the endpoint. * * @return true if the endpoint is running, false otherwise */ public boolean isRunning() { return running; } /** * Return the state of the endpoint. * * @return true if the endpoint is paused, false otherwise */ public boolean isPaused() { return paused; } // ----------------------------------------------- Public Lifecycle Methods /** * Initialize the endpoint. */ public void init() throws Exception { if (initialized) return; // Create the root APR memory pool rootPool = Pool.create(0); // Create the pool for the server socket serverSockPool = Pool.create(rootPool); // Create the APR address that will be bound String addressStr = null; if (address == null) { addressStr = null; } else { addressStr = address.getHostAddress(); } int family = Socket.APR_INET; if (Library.APR_HAVE_IPV6) { if (addressStr == null) { if (!OS.IS_BSD && !OS.IS_WIN32 && !OS.IS_WIN64) family = Socket.APR_UNSPEC; } else if (addressStr.indexOf(':') >= 0) { family = Socket.APR_UNSPEC; } } long inetAddress = Address.info(addressStr, family, port, 0, rootPool); // Create the APR server socket serverSock = Socket.create(family, Socket.SOCK_STREAM, Socket.APR_PROTO_TCP, rootPool); if (OS.IS_UNIX) { Socket.optSet(serverSock, Socket.APR_SO_REUSEADDR, 1); } // Deal with the firewalls that tend to drop the inactive sockets Socket.optSet(serverSock, Socket.APR_SO_KEEPALIVE, 1); // Bind the server socket int ret = Socket.bind(serverSock, inetAddress); if (ret != 0) { throw new Exception(sm.getString("endpoint.init.bind", "" + ret, Error.strerror(ret))); } // Start listening on the server socket ret = Socket.listen(serverSock, backlog); if (ret != 0) { throw new Exception(sm.getString("endpoint.init.listen", "" + ret, Error.strerror(ret))); } if (OS.IS_WIN32 || OS.IS_WIN64) { // On Windows set the reuseaddr flag after the bind/listen Socket.optSet(serverSock, Socket.APR_SO_REUSEADDR, 1); } // Sendfile usage on systems which don't support it cause major problems if (useSendfile && !Library.APR_HAS_SENDFILE) { useSendfile = false; } // Initialize thread count defaults for acceptor, poller and sendfile if (acceptorThreadCount == 0) { // FIXME: Doesn't seem to work that well with multiple accept threads acceptorThreadCount = 1; } if (pollerThreadCount == 0) { if ((OS.IS_WIN32 || OS.IS_WIN64) && (pollerSize > 1024)) { // The maximum per poller to get reasonable performance is 1024 pollerThreadCount = pollerSize / 1024; // Adjust poller size so that it won't reach the limit pollerSize = pollerSize - (pollerSize % 1024); } else { // No explicit poller size limitation pollerThreadCount = 1; } } if (sendfileThreadCount == 0) { if ((OS.IS_WIN32 || OS.IS_WIN64) && (sendfileSize > 1024)) { // The maximum per poller to get reasonable performance is 1024 sendfileThreadCount = sendfileSize / 1024; // Adjust poller size so that it won't reach the limit sendfileSize = sendfileSize - (sendfileSize % 1024); } else { // No explicit poller size limitation // FIXME: Default to one per CPU ? sendfileThreadCount = 1; } } // Delay accepting of new connections until data is available // Only Linux kernels 2.4 + have that implemented // on other platforms this call is noop and will return APR_ENOTIMPL. if (Socket.optSet(serverSock, Socket.APR_TCP_DEFER_ACCEPT, 1) == Status.APR_ENOTIMPL) { deferAccept = false; } // Initialize SSL if needed if (SSLEnabled) { // SSL protocol int value = SSL.SSL_PROTOCOL_ALL; if ("SSLv2".equalsIgnoreCase(SSLProtocol)) { value = SSL.SSL_PROTOCOL_SSLV2; } else if ("SSLv3".equalsIgnoreCase(SSLProtocol)) { value = SSL.SSL_PROTOCOL_SSLV3; } else if ("TLSv1".equalsIgnoreCase(SSLProtocol)) { value = SSL.SSL_PROTOCOL_TLSV1; } else if ("SSLv2+SSLv3".equalsIgnoreCase(SSLProtocol)) { value = SSL.SSL_PROTOCOL_SSLV2 | SSL.SSL_PROTOCOL_SSLV3; } // Create SSL Context sslContext = SSLContext.make(rootPool, value, SSL.SSL_MODE_SERVER); // List the ciphers that the client is permitted to negotiate SSLContext.setCipherSuite(sslContext, SSLCipherSuite); // Load Server key and certificate SSLContext.setCertificate(sslContext, SSLCertificateFile, SSLCertificateKeyFile, SSLPassword, SSL.SSL_AIDX_RSA); // Set certificate chain file SSLContext.setCertificateChainFile(sslContext, SSLCertificateChainFile, false); // Support Client Certificates SSLContext.setCACertificate(sslContext, SSLCACertificateFile, SSLCACertificatePath); // Set revocation SSLContext.setCARevocation(sslContext, SSLCARevocationFile, SSLCARevocationPath); // Client certificate verification value = SSL.SSL_CVERIFY_NONE; if ("optional".equalsIgnoreCase(SSLVerifyClient)) { value = SSL.SSL_CVERIFY_OPTIONAL; } else if ("require".equalsIgnoreCase(SSLVerifyClient)) { value = SSL.SSL_CVERIFY_REQUIRE; } else if ("optionalNoCA".equalsIgnoreCase(SSLVerifyClient)) { value = SSL.SSL_CVERIFY_OPTIONAL_NO_CA; } SSLContext.setVerify(sslContext, value, SSLVerifyDepth); // For now, sendfile is not supported with SSL useSendfile = false; } initialized = true; } /** * Start the APR endpoint, creating acceptor, poller and sendfile threads. */ public void start() throws Exception { // Initialize socket if not done before if (!initialized) { init(); } if (!running) { running = true; paused = false; // Create worker collection if (executor == null) { workers = new WorkerStack(maxThreads); } // Start poller threads pollers = new Poller[pollerThreadCount]; for (int i = 0; i < pollerThreadCount; i++) { pollers[i] = new Poller(false); pollers[i].init(); Thread pollerThread = new Thread(pollers[i], getName() + "-Poller-" + i); pollerThread.setPriority(threadPriority); pollerThread.setDaemon(true); pollerThread.start(); } // Start comet poller threads cometPollers = new Poller[pollerThreadCount]; for (int i = 0; i < pollerThreadCount; i++) { cometPollers[i] = new Poller(true); cometPollers[i].init(); Thread pollerThread = new Thread(cometPollers[i], getName() + "-CometPoller-" + i); pollerThread.setPriority(threadPriority); pollerThread.setDaemon(true); pollerThread.start(); } // Start sendfile threads if (useSendfile) { sendfiles = new Sendfile[sendfileThreadCount]; for (int i = 0; i < sendfileThreadCount; i++) { sendfiles[i] = new Sendfile(); sendfiles[i].init(); Thread sendfileThread = new Thread(sendfiles[i], getName() + "-Sendfile-" + i); sendfileThread.setPriority(threadPriority); sendfileThread.setDaemon(true); sendfileThread.start(); } } // Start acceptor threads for (int i = 0; i < acceptorThreadCount; i++) { Thread acceptorThread = new Thread(new Acceptor(), getName() + "-Acceptor-" + i); acceptorThread.setPriority(threadPriority); acceptorThread.setDaemon(daemon); acceptorThread.start(); } } } /** * Pause the endpoint, which will make it stop accepting new sockets. */ public void pause() { if (running && !paused) { paused = true; unlockAccept(); } } /** * Resume the endpoint, which will make it start accepting new sockets * again. */ public void resume() { if (running) { paused = false; } } /** * Stop the endpoint. This will cause all processing threads to stop. */ public void stop() { if (running) { running = false; unlockAccept(); for (int i = 0; i < pollers.length; i++) { pollers[i].destroy(); } pollers = null; for (int i = 0; i < cometPollers.length; i++) { cometPollers[i].destroy(); } cometPollers = null; if (useSendfile) { for (int i = 0; i < sendfiles.length; i++) { sendfiles[i].destroy(); } sendfiles = null; } } } /** * Deallocate APR memory pools, and close server socket. */ public void destroy() throws Exception { if (running) { stop(); } Pool.destroy(serverSockPool); serverSockPool = 0; // Close server socket Socket.close(serverSock); serverSock = 0; sslContext = 0; // Close all APR memory pools and resources Pool.destroy(rootPool); rootPool = 0; initialized = false; } // ------------------------------------------------------ Protected Methods /** * Get a sequence number used for thread naming. */ protected int getSequence() { return sequence++; } /** * Unlock the server socket accept using a bugus connection. */ protected void unlockAccept() { java.net.Socket s = null; try { // Need to create a connection to unlock the accept(); if (address == null) { s = new java.net.Socket("127.0.0.1", port); } else { s = new java.net.Socket(address, port); // setting soLinger to a small value will help shutdown the // connection quicker s.setSoLinger(true, 0); } } catch(Exception e) { if (log.isDebugEnabled()) { log.debug(sm.getString("endpoint.debug.unlock", "" + port), e); } } finally { if (s != null) { try { s.close(); } catch (Exception e) { // Ignore } } } } /** * Process the specified connection. */ protected boolean setSocketOptions(long socket) { // Process the connection int step = 1; try { // 1: Set socket options: timeout, linger, etc if (soLinger >= 0) Socket.optSet(socket, Socket.APR_SO_LINGER, soLinger); if (tcpNoDelay) Socket.optSet(socket, Socket.APR_TCP_NODELAY, (tcpNoDelay ? 1 : 0)); if (soTimeout > 0) Socket.timeoutSet(socket, soTimeout * 1000); // 2: SSL handshake step = 2; if (sslContext != 0) { SSLSocket.attach(sslContext, socket); if (SSLSocket.handshake(socket) != 0) { if (log.isDebugEnabled()) { log.debug(sm.getString("endpoint.err.handshake") + ": " + SSL.getLastError()); } return false; } } } catch (Throwable t) { if (log.isDebugEnabled()) { if (step == 2) { log.debug(sm.getString("endpoint.err.handshake"), t); } else { log.debug(sm.getString("endpoint.err.unexpected"), t); } } // Tell to close the socket return false; } return true; } /** * Create (or allocate) and return an available processor for use in * processing a specific HTTP request, if possible. If the maximum * allowed processors have already been created and are in use, return * <code>null</code> instead. */ protected Worker createWorkerThread() { synchronized (workers) { if (workers.size() > 0) { curThreadsBusy++; return (workers.pop()); } if ((maxThreads > 0) && (curThreads < maxThreads)) { curThreadsBusy++; return (newWorkerThread()); } else { if (maxThreads < 0) { curThreadsBusy++; return (newWorkerThread()); } else { return (null); } } } } /** * Create and return a new processor suitable for processing HTTP * requests and returning the corresponding responses. */ protected Worker newWorkerThread() { Worker workerThread = new Worker(); workerThread.start(); return (workerThread); } /** * Return a new worker thread, and block while to worker is available. */ protected Worker getWorkerThread() { // Allocate a new worker thread Worker workerThread = createWorkerThread(); while (workerThread == null) { try { synchronized (workers) { workers.wait(); } } catch (InterruptedException e) { // Ignore } workerThread = createWorkerThread(); } return workerThread; } /** * Recycle the specified Processor so that it can be used again. * * @param workerThread The processor to be recycled */ protected void recycleWorkerThread(Worker workerThread) { synchronized (workers) { workers.push(workerThread); curThreadsBusy--; workers.notify(); } } /** * Allocate a new poller of the specified size. */ protected long allocatePoller(int size, long pool, int timeout) { try { return Poll.create(size, pool, 0, timeout * 1000); } catch (Error e) { if (Status.APR_STATUS_IS_EINVAL(e.getError())) { log.info(sm.getString("endpoint.poll.limitedpollsize", "" + size)); return 0; } else { log.error(sm.getString("endpoint.poll.initfail"), e); return -1; } } } /** * Process given socket. */ protected boolean processSocketWithOptions(long socket) { try { if (executor == null) { getWorkerThread().assignWithOptions(socket); } else { executor.execute(new SocketWithOptionsProcessor(socket)); } } catch (Throwable t) { // This means we got an OOM or similar creating a thread, or that // the pool and its queue are full log.error(sm.getString("endpoint.process.fail"), t); return false; } return true; } /** * Process given socket. */ protected boolean processSocket(long socket) { try { if (executor == null) { getWorkerThread().assign(socket); } else { executor.execute(new SocketProcessor(socket)); } } catch (Throwable t) { // This means we got an OOM or similar creating a thread, or that // the pool and its queue are full log.error(sm.getString("endpoint.process.fail"), t); return false; } return true; } /** * Process given socket for an event. */ protected boolean processSocket(long socket, SocketStatus status) { try { if (executor == null) { getWorkerThread().assign(socket, status); } else { executor.execute(new SocketEventProcessor(socket, status)); } } catch (Throwable t) { // This means we got an OOM or similar creating a thread, or that // the pool and its queue are full log.error(sm.getString("endpoint.process.fail"), t); return false; } return true; } // --------------------------------------------------- Acceptor Inner Class /** * Server socket acceptor thread. */ protected class Acceptor implements Runnable { /** * The background thread that listens for incoming TCP/IP connections and * hands them off to an appropriate processor. */ public void run() { // Loop until we receive a shutdown command while (running) { // Loop if endpoint is paused while (paused) { try { Thread.sleep(1000); } catch (InterruptedException e) { // Ignore } } try { // Accept the next incoming connection from the server socket long socket = Socket.accept(serverSock); // Hand this socket off to an appropriate processor if (!processSocketWithOptions(socket)) { // Close socket and pool right away Socket.destroy(socket); } } catch (Throwable t) { log.error(sm.getString("endpoint.accept.fail"), t); } // The processor will recycle itself when it finishes } } } // ----------------------------------------------------- Poller Inner Class /** * Poller class. */ public class Poller implements Runnable { protected long serverPollset = 0; protected long pool = 0; protected long[] desc; protected long[] addS; protected int addCount = 0; protected boolean comet = true; protected int keepAliveCount = 0; public int getKeepAliveCount() { return keepAliveCount; } public Poller(boolean comet) { this.comet = comet; } /** * Create the poller. With some versions of APR, the maximum poller size will * be 62 (recompiling APR is necessary to remove this limitation). */ protected void init() { pool = Pool.create(serverSockPool); int size = pollerSize / pollerThreadCount; int timeout = keepAliveTimeout; if (timeout < 0) { timeout = soTimeout; } serverPollset = allocatePoller(size, pool, timeout); if (serverPollset == 0 && size > 1024) { size = 1024; serverPollset = allocatePoller(size, pool, timeout); } if (serverPollset == 0) { size = 62; serverPollset = allocatePoller(size, pool, timeout); } desc = new long[size * 2]; keepAliveCount = 0; addS = new long[size]; addCount = 0; } /** * Destroy the poller. */ protected void destroy() { // Wait for polltime before doing anything, so that the poller threads // exit, otherwise parallel descturction of sockets which are still // in the poller can cause problems try { synchronized (this) { this.wait(pollTime / 1000); } } catch (InterruptedException e) { // Ignore } // Close all sockets in the add queue for (int i = 0; i < addCount; i++) { if (comet) { processSocket(addS[i], SocketStatus.STOP); } else { Socket.destroy(addS[i]); } } // Close all sockets still in the poller int rv = Poll.pollset(serverPollset, desc); if (rv > 0) { for (int n = 0; n < rv; n++) { if (comet) { processSocket(desc[n*2+1], SocketStatus.STOP); } else { Socket.destroy(desc[n*2+1]); } } } Pool.destroy(pool); keepAliveCount = 0; addCount = 0; } /** * Add specified socket and associated pool to the poller. The socket will * be added to a temporary array, and polled first after a maximum amount * of time equal to pollTime (in most cases, latency will be much lower, * however). * * @param socket to add to the poller */ public void add(long socket) { synchronized (this) { // Add socket to the list. Newly added sockets will wait // at most for pollTime before being polled if (addCount >= addS.length) { // Can't do anything: close the socket right away if (comet) { processSocket(socket, SocketStatus.ERROR); } else { Socket.destroy(socket); } return; } addS[addCount] = socket; addCount++; this.notify(); } } /** * The background thread that listens for incoming TCP/IP connections and * hands them off to an appropriate processor. */ public void run() { long maintainTime = 0; // Loop until we receive a shutdown command while (running) { // Loop if endpoint is paused while (paused) { try { Thread.sleep(1000); } catch (InterruptedException e) { // Ignore } } while (keepAliveCount < 1 && addCount < 1) { // Reset maintain time. maintainTime = 0; try { synchronized (this) { this.wait(); } } catch (InterruptedException e) { // Ignore } } try { // Add sockets which are waiting to the poller if (addCount > 0) { synchronized (this) { for (int i = (addCount - 1); i >= 0; i--) { int rv = Poll.add (serverPollset, addS[i], Poll.APR_POLLIN); if (rv == Status.APR_SUCCESS) { keepAliveCount++; } else { // Can't do anything: close the socket right away if (comet) { processSocket(addS[i], SocketStatus.ERROR); } else { Socket.destroy(addS[i]); } } } addCount = 0; } } maintainTime += pollTime; // Pool for the specified interval int rv = Poll.poll(serverPollset, pollTime, desc, true); if (rv > 0) { keepAliveCount -= rv; for (int n = 0; n < rv; n++) { // Check for failed sockets and hand this socket off to a worker if (((desc[n*2] & Poll.APR_POLLHUP) == Poll.APR_POLLHUP) || ((desc[n*2] & Poll.APR_POLLERR) == Poll.APR_POLLERR) || (comet && (!processSocket(desc[n*2+1], SocketStatus.OPEN))) || (!comet && (!processSocket(desc[n*2+1])))) { // Close socket and clear pool if (comet) { processSocket(desc[n*2+1], SocketStatus.DISCONNECT); } else { Socket.destroy(desc[n*2+1]); } continue; } } } else if (rv < 0) { int errn = -rv; /* Any non timeup or interrupted error is critical */ if ((errn != Status.TIMEUP) && (errn != Status.EINTR)) { if (errn > Status.APR_OS_START_USERERR) { errn -= Status.APR_OS_START_USERERR; } log.error(sm.getString("endpoint.poll.fail", "" + errn, Error.strerror(errn))); // Handle poll critical failure synchronized (this) { destroy(); init(); } continue; } } if (soTimeout > 0 && maintainTime > 1000000L && running) { rv = Poll.maintain(serverPollset, desc, true); maintainTime = 0; if (rv > 0) { keepAliveCount -= rv; for (int n = 0; n < rv; n++) { // Close socket and clear pool if (comet) { processSocket(desc[n], SocketStatus.TIMEOUT); } else { Socket.destroy(desc[n]); } } } } } catch (Throwable t) { log.error(sm.getString("endpoint.poll.error"), t); } } synchronized (this) { this.notifyAll(); } } } // ----------------------------------------------------- Worker Inner Class /** * Server processor class. */ protected class Worker implements Runnable { protected Thread thread = null; protected boolean available = false; protected long socket = 0; protected SocketStatus status = null; protected boolean options = false; /** * Process an incoming TCP/IP connection on the specified socket. Any * exception that occurs during processing must be logged and swallowed. * <b>NOTE</b>: This method is called from our Connector's thread. We * must assign it to our own thread so that multiple simultaneous * requests can be handled. * * @param socket TCP socket to process */ protected synchronized void assignWithOptions(long socket) { // Wait for the Processor to get the previous Socket while (available) { try { wait(); } catch (InterruptedException e) { } } // Store the newly available Socket and notify our thread this.socket = socket; status = null; options = true; available = true; notifyAll(); } /** * Process an incoming TCP/IP connection on the specified socket. Any * exception that occurs during processing must be logged and swallowed. * <b>NOTE</b>: This method is called from our Connector's thread. We * must assign it to our own thread so that multiple simultaneous * requests can be handled. * * @param socket TCP socket to process */ protected synchronized void assign(long socket) { // Wait for the Processor to get the previous Socket while (available) { try { wait(); } catch (InterruptedException e) { } } // Store the newly available Socket and notify our thread this.socket = socket; status = null; options = false; available = true; notifyAll(); } protected synchronized void assign(long socket, SocketStatus status) { // Wait for the Processor to get the previous Socket while (available) { try { wait(); } catch (InterruptedException e) { } } // Store the newly available Socket and notify our thread this.socket = socket; this.status = status; options = false; available = true; notifyAll(); } /** * Await a newly assigned Socket from our Connector, or <code>null</code> * if we are supposed to shut down. */ protected synchronized long await() { // Wait for the Connector to provide a new Socket while (!available) { try { wait(); } catch (InterruptedException e) { } } // Notify the Connector that we have received this Socket long socket = this.socket; available = false; notifyAll(); return (socket); } /** * The background thread that listens for incoming TCP/IP connections and * hands them off to an appropriate processor. */ public void run() { // Process requests until we receive a shutdown signal while (running) { // Wait for the next socket to be assigned long socket = await(); if (socket == 0) continue; if (!deferAccept && options) { if (setSocketOptions(socket)) { getPoller().add(socket); } else { // Close socket and pool Socket.destroy(socket); socket = 0; } } else { // Process the request from this socket if ((status != null) && (handler.event(socket, status) == Handler.SocketState.CLOSED)) { // Close socket and pool Socket.destroy(socket); socket = 0; } else if ((status == null) && ((options && !setSocketOptions(socket)) || handler.process(socket) == Handler.SocketState.CLOSED)) { // Close socket and pool Socket.destroy(socket); socket = 0; } } // Finish up this request recycleWorkerThread(this); } } /** * Start the background processing thread. */ public void start() { thread = new Thread(this); thread.setName(getName() + "-" + (++curThreads)); thread.setDaemon(true); thread.start(); } } // ----------------------------------------------- SendfileData Inner Class /** * SendfileData class. */ public static class SendfileData { // File public String fileName; public long fd; public long fdpool; // Range information public long start; public long end; // Socket and socket pool public long socket; // Position public long pos; // KeepAlive flag public boolean keepAlive; } // --------------------------------------------------- Sendfile Inner Class /** * Sendfile class. */ public class Sendfile implements Runnable { protected long sendfilePollset = 0; protected long pool = 0; protected long[] desc; protected HashMap<Long, SendfileData> sendfileData; protected int sendfileCount; public int getSendfileCount() { return sendfileCount; } protected ArrayList<SendfileData> addS; /** * Create the sendfile poller. With some versions of APR, the maximum poller size will * be 62 (reocmpiling APR is necessary to remove this limitation). */ protected void init() { pool = Pool.create(serverSockPool); int size = sendfileSize / sendfileThreadCount; sendfilePollset = allocatePoller(size, pool, soTimeout); if (sendfilePollset == 0 && size > 1024) { size = 1024; sendfilePollset = allocatePoller(size, pool, soTimeout); } if (sendfilePollset == 0) { size = 62; sendfilePollset = allocatePoller(size, pool, soTimeout); } desc = new long[size * 2]; sendfileData = new HashMap<Long, SendfileData>(size); addS = new ArrayList<SendfileData>(); } /** * Destroy the poller. */ protected void destroy() { // Wait for polltime before doing anything, so that the poller threads // exit, otherwise parallel descturction of sockets which are still // in the poller can cause problems try { synchronized (this) { this.wait(pollTime / 1000); } } catch (InterruptedException e) { // Ignore } // Close any socket remaining in the add queue for (int i = (addS.size() - 1); i >= 0; i--) { SendfileData data = addS.get(i); Socket.destroy(data.socket); } // Close all sockets still in the poller int rv = Poll.pollset(sendfilePollset, desc); if (rv > 0) { for (int n = 0; n < rv; n++) { Socket.destroy(desc[n*2+1]); } } Pool.destroy(pool); sendfileData.clear(); } /** * Add the sendfile data to the sendfile poller. Note that in most cases, * the initial non blocking calls to sendfile will return right away, and * will be handled asynchronously inside the kernel. As a result, * the poller will never be used. * * @param data containing the reference to the data which should be snet * @return true if all the data has been sent right away, and false * otherwise */ public boolean add(SendfileData data) { // Initialize fd from data given try { data.fdpool = Socket.pool(data.socket); data.fd = File.open (data.fileName, File.APR_FOPEN_READ | File.APR_FOPEN_SENDFILE_ENABLED | File.APR_FOPEN_BINARY, 0, data.fdpool); data.pos = data.start; // Set the socket to nonblocking mode Socket.timeoutSet(data.socket, 0); while (true) { long nw = Socket.sendfilen(data.socket, data.fd, data.pos, data.end - data.pos, 0); if (nw < 0) { if (!(-nw == Status.EAGAIN)) { Socket.destroy(data.socket); data.socket = 0; return false; } else { // Break the loop and add the socket to poller. break; } } else { data.pos = data.pos + nw; if (data.pos >= data.end) { // Entire file has been sent Pool.destroy(data.fdpool); // Set back socket to blocking mode Socket.timeoutSet(data.socket, soTimeout * 1000); return true; } } } } catch (Exception e) { log.error(sm.getString("endpoint.sendfile.error"), e); return false; } // Add socket to the list. Newly added sockets will wait // at most for pollTime before being polled synchronized (this) { addS.add(data); this.notify(); } return false; } /** * Remove socket from the poller. * * @param data the sendfile data which should be removed */ protected void remove(SendfileData data) { int rv = Poll.remove(sendfilePollset, data.socket); if (rv == Status.APR_SUCCESS) { sendfileCount--; } sendfileData.remove(new Long(data.socket)); } /** * The background thread that listens for incoming TCP/IP connections and * hands them off to an appropriate processor. */ public void run() { long maintainTime = 0; // Loop until we receive a shutdown command while (running) { // Loop if endpoint is paused while (paused) { try { Thread.sleep(1000); } catch (InterruptedException e) { // Ignore } } while (sendfileCount < 1 && addS.size() < 1) { // Reset maintain time. maintainTime = 0; try { synchronized (this) { this.wait(); } } catch (InterruptedException e) { // Ignore } } try { // Add socket to the poller if (addS.size() > 0) { synchronized (this) { for (int i = (addS.size() - 1); i >= 0; i--) { SendfileData data = addS.get(i); int rv = Poll.add(sendfilePollset, data.socket, Poll.APR_POLLOUT); if (rv == Status.APR_SUCCESS) { sendfileData.put(new Long(data.socket), data); sendfileCount++; } else { log.warn(sm.getString("endpoint.sendfile.addfail", "" + rv, Error.strerror(rv))); // Can't do anything: close the socket right away Socket.destroy(data.socket); } } addS.clear(); } } maintainTime += pollTime; // Pool for the specified interval int rv = Poll.poll(sendfilePollset, pollTime, desc, false); if (rv > 0) { for (int n = 0; n < rv; n++) { // Get the sendfile state SendfileData state = sendfileData.get(new Long(desc[n*2+1])); // Problem events if (((desc[n*2] & Poll.APR_POLLHUP) == Poll.APR_POLLHUP) || ((desc[n*2] & Poll.APR_POLLERR) == Poll.APR_POLLERR)) { // Close socket and clear pool remove(state); // Destroy file descriptor pool, which should close the file // Close the socket, as the reponse would be incomplete Socket.destroy(state.socket); continue; } // Write some data using sendfile long nw = Socket.sendfilen(state.socket, state.fd, state.pos, state.end - state.pos, 0); if (nw < 0) { // Close socket and clear pool remove(state); // Close the socket, as the reponse would be incomplete // This will close the file too. Socket.destroy(state.socket); continue; } state.pos = state.pos + nw; if (state.pos >= state.end) { remove(state); if (state.keepAlive) { // Destroy file descriptor pool, which should close the file Pool.destroy(state.fdpool); Socket.timeoutSet(state.socket, soTimeout * 1000); // If all done hand this socket off to a worker for // processing of further requests if (!processSocket(state.socket)) { Socket.destroy(state.socket); } } else { // Close the socket since this is // the end of not keep-alive request. Socket.destroy(state.socket); } } } } else if (rv < 0) { int errn = -rv; /* Any non timeup or interrupted error is critical */ if ((errn != Status.TIMEUP) && (errn != Status.EINTR)) { if (errn > Status.APR_OS_START_USERERR) { errn -= Status.APR_OS_START_USERERR; } log.error(sm.getString("endpoint.poll.fail", "" + errn, Error.strerror(errn))); // Handle poll critical failure synchronized (this) { destroy(); init(); } continue; } } // Call maintain for the sendfile poller if (soTimeout > 0 && maintainTime > 1000000L && running) { rv = Poll.maintain(sendfilePollset, desc, true); maintainTime = 0; if (rv > 0) { for (int n = 0; n < rv; n++) { // Get the sendfile state SendfileData state = sendfileData.get(new Long(desc[n])); // Close socket and clear pool remove(state); // Destroy file descriptor pool, which should close the file // Close the socket, as the response would be incomplete Socket.destroy(state.socket); } } } } catch (Throwable t) { log.error(sm.getString("endpoint.poll.error"), t); } } synchronized (this) { this.notifyAll(); } } } // ------------------------------------------------ Handler Inner Interface /** * Bare bones interface used for socket processing. Per thread data is to be * stored in the ThreadWithAttributes extra folders, or alternately in * thread local fields. */ public interface Handler { public enum SocketState { OPEN, CLOSED, LONG } public SocketState process(long socket); public SocketState event(long socket, SocketStatus status); } // ------------------------------------------------- WorkerStack Inner Class public class WorkerStack { protected Worker[] workers = null; protected int end = 0; public WorkerStack(int size) { workers = new Worker[size]; } /** * Put the object into the queue. * * @param object the object to be appended to the queue (first element). */ public void push(Worker worker) { workers[end++] = worker; } /** * Get the first object out of the queue. Return null if the queue * is empty. */ public Worker pop() { if (end > 0) { return workers[--end]; } return null; } /** * Get the first object out of the queue, Return null if the queue * is empty. */ public Worker peek() { return workers[end]; } /** * Is the queue empty? */ public boolean isEmpty() { return (end == 0); } /** * How many elements are there in this queue? */ public int size() { return (end); } } // ---------------------------------------------- SocketProcessor Inner Class /** * This class is the equivalent of the Worker, but will simply use in an * external Executor thread pool. This will also set the socket options * and do the handshake. */ protected class SocketWithOptionsProcessor implements Runnable { protected long socket = 0; public SocketWithOptionsProcessor(long socket) { this.socket = socket; } public void run() { if (!deferAccept) { if (setSocketOptions(socket)) { getPoller().add(socket); } else { // Close socket and pool Socket.destroy(socket); socket = 0; } } else { // Process the request from this socket if (!setSocketOptions(socket) || handler.process(socket) == Handler.SocketState.CLOSED) { // Close socket and pool Socket.destroy(socket); socket = 0; } } } } // ---------------------------------------------- SocketProcessor Inner Class /** * This class is the equivalent of the Worker, but will simply use in an * external Executor thread pool. */ protected class SocketProcessor implements Runnable { protected long socket = 0; public SocketProcessor(long socket) { this.socket = socket; } public void run() { // Process the request from this socket if (handler.process(socket) == Handler.SocketState.CLOSED) { // Close socket and pool Socket.destroy(socket); socket = 0; } } } // --------------------------------------- SocketEventProcessor Inner Class /** * This class is the equivalent of the Worker, but will simply use in an * external Executor thread pool. */ protected class SocketEventProcessor implements Runnable { protected long socket = 0; protected SocketStatus status = null; public SocketEventProcessor(long socket, SocketStatus status) { this.socket = socket; this.status = status; } public void run() { // Process the request from this socket if (handler.event(socket, status) == Handler.SocketState.CLOSED) { // Close socket and pool Socket.destroy(socket); socket = 0; } } } }

The table below shows all metrics for AprEndpoint.java.

MetricValueDescription
BLOCKS352.00Number of blocks
BLOCK_COMMENT18.00Number of block comment lines
COMMENTS586.00Comment lines
COMMENT_DENSITY 0.68Comment density
COMPARISONS132.00Number of comparison operators
CYCLOMATIC324.00Cyclomatic complexity
DECL_COMMENTS130.00Comments in declarations
DOC_COMMENT401.00Number of javadoc comment lines
ELOC865.00Effective lines of code
EXEC_COMMENTS130.00Comments in executable code
EXITS100.00Procedure exits
FUNCTIONS129.00Number of function declarations
HALSTEAD_DIFFICULTY125.18Halstead difficulty
HALSTEAD_EFFORT 0.00Halstead effort
INTERFACE_COMPLEXITY216.00Interface complexity
JAVA0001 0.00JAVA0001 Package name does not contain only lower case letters
JAVA0002 0.00JAVA0002 Package name does not begin with a top level domain name or country code
JAVA0003 0.00JAVA0003 Minimize use of on-demand (.*) imports
JAVA0004 0.00JAVA0004 Unnecessary import from java.lang
JAVA0005 0.00JAVA0005 Imports not in specified order
JAVA0006 0.00JAVA0006 Empty finally block
JAVA0007 8.00JAVA0007 Should not declare public field
JAVA0008 0.00JAVA0008 Empty catch block
JAVA0009 0.00JAVA0009 Protected member in final class
JAVA0010 0.00JAVA0010 Non-instantiable class does not contain a non-private static member
JAVA0011 0.00JAVA0011 Abstract class does not contain an abstract method
JAVA0012 0.00JAVA0012 Non-constructor method with same name as declaring class
JAVA0013 0.00JAVA0013 Non-blank final field is not static
JAVA0014 0.00JAVA0014 Class with only static members has non-private constructor
JAVA0015 0.00JAVA0015 Package class contains public nested type
JAVA0016 0.00JAVA0016 Abstract class contains public constructor
JAVA0017 0.00JAVA0017 Class name does not have required form
JAVA0018 0.00JAVA0018 Method name does not have required form
JAVA0019 0.00JAVA0019 Interface name does not have required form
JAVA0020 0.00JAVA0020 Field name does not have required form
JAVA0021 0.00JAVA0021 Interface method name does not have required form
JAVA0022 0.00JAVA0022 Static final field name does not have required form
JAVA0023 0.00JAVA0023 Empty finalize method
JAVA0024 0.00JAVA0024 Empty class
JAVA0025 0.00JAVA0025 Method override is empty
JAVA0026 0.00JAVA0026 Finalize method with parameters
JAVA0029 0.00JAVA0029 Private method not used
JAVA0030 0.00JAVA0030 Private field not used
JAVA0031 0.00JAVA0031 Case statement not properly closed
JAVA0032 0.00JAVA0032 Switch statement missing default
JAVA0033 0.00JAVA0033 default: not last case in switch statement
JAVA0034 7.00JAVA0034 Missing braces in if statement
JAVA0035 0.00JAVA0035 Missing braces in for statement
JAVA0036 0.00JAVA0036 Missing braces in while statement
JAVA0038 0.00JAVA0038 Non-case label in switch statement
JAVA0039 0.00JAVA0039 Break statement with label
JAVA0040 0.00JAVA0040 Switch statement contains N cases (maximum: M)
JAVA0041 0.00JAVA0041 Nested synchronized block
JAVA0042 0.00JAVA0042 Empty synchronized statement
JAVA0043 1.00JAVA0043 Inner class does not use outer class
JAVA0044 0.00JAVA0044 Serializable class with no instance variables
JAVA0045 0.00JAVA0045 Serializable class with only transient fields
JAVA0046 0.00JAVA0046 Name of class not derived from Exception ends with 'Exception'
JAVA0047 0.00JAVA0047 Serializable class derives from invalid base class
JAVA0048 0.00JAVA0048 Name of class derived from Exception does not end with 'Exception'
JAVA004912.00JAVA0049 Nested block at depth N (maximum: M)
JAVA0050 0.00JAVA0050 Class derives from java.lang.Error
JAVA0051 0.00JAVA0051 Class derives from java.lang.RuntimeException
JAVA0052 0.00JAVA0052 Class derives from java.lang.Throwable
JAVA0053 0.00JAVA0053 Unused label
JAVA0054 0.00JAVA0054 Inheritance depth N exceeds maximum M
JAVA0055 0.00JAVA0055 Class should be interface
JAVA0056 0.00JAVA0056 Unnecessary abstract modifier for interface or annotation
JAVA0057 0.00JAVA0057 Unnecessary default constructor
JAVA0058 0.00JAVA0058 Constructor calls super()
JAVA0059 0.00JAVA0059 Method override only calls super()
JAVA0061 0.00JAVA0061 Inaccessible member in anonymous class
JAVA0062 0.00JAVA0062 Public class missing public member or protected constructor
JAVA0063 0.00JAVA0063 Identifier name should not contain '$'
JAVA0064 0.00JAVA0064 N variations of identifier name (maximum: M)
JAVA0065 0.00JAVA0065 Unnecessary final modifier for method in final class
JAVA0066 1.00JAVA0066 Unnecessary modifier for interface nested type
JAVA0067 0.00JAVA0067 Array descriptor on identifier name
JAVA0068 0.00JAVA0068 Modifiers not declared in recommended order
JAVA0071 0.00JAVA0071 Strings compared with ==
JAVA0073 0.00JAVA0073 Integer division in floating-point context
JAVA0074 3.00JAVA0074 Use of Object.notify()
JAVA0075 4.00JAVA0075 Method parameter hides field
JAVA007627.00JAVA0076 Use of magic number
JAVA0077 0.00JAVA0077 Private field not used in declaring class
JAVA0078 0.00JAVA0078 Floating point values compared with ==
JAVA0079 0.00JAVA0079 Use of instance to reference static member
JAVA0080 0.00JAVA0080 Import declaration not used
JAVA0081 0.00JAVA0081 Boolean literal in comparison
JAVA0082 0.00JAVA0082 Unnecessary widening cast
JAVA0083 0.00JAVA0083 Unnecessary instanceof test
JAVA0084 4.00JAVA0084 Should use compound assignment operator
JAVA0085 0.00JAVA0085 Use of sun.* class
JAVA0087 3.00JAVA0087 Use of Thread.sleep()
JAVA0089 0.00JAVA0089 Use of restricted package
JAVA0092 0.00JAVA0092 Use of restricted type
JAVA0093 0.00JAVA0093 Redundant assignment
JAVA0094 0.00JAVA0094 Field hides a superclass field
JAVA0095 0.00JAVA0095 Uninitialized private field
JAVA0096 1.00JAVA0096 Field in nested class hides outer field
JAVA0098 1.00JAVA0098 Minimize use of implicit field initializers
JAVA0100 1.00JAVA0100 Class contains N non-final fields (maximum: M)
JAVA0101 0.00JAVA0101 Unnecessary modifier for field in interface
JAVA0102 0.00JAVA0102 Last statement in finalize() not super.finalize()
JAVA0103 0.00JAVA0103 Explicit call to finalize()
JAVA0104 0.00JAVA0104 finalize() only calls super.finalize()
JAVA0105 0.00JAVA0105 Duplicate import declaration
JAVA0106 0.00JAVA0106 Unnecessary import from current package
JAVA0108 9.00JAVA0108 Incorrect javadoc: no @param tag for 'parameter'
JAVA0109 1.00JAVA0109 Incorrect javadoc: no parameter 'parameter'
JAVA011018.00JAVA0110 Incorrect javadoc: no @return tag
JAVA0111 0.00JAVA0111 Incorrect javadoc: @return tag for void method
JAVA0112 0.00JAVA0112 Incorrect javadoc: no exception 'exception' in throws
JAVA0113 0.00JAVA0113 Incorrect javadoc: no @author tag
JAVA0114 1.00JAVA0114 Incorrect javadoc: no @version tag
JAVA0115 3.00JAVA0115 Incorrect javadoc: no @throws or @exception tag for 'exception'
JAVA0116 8.00JAVA0116 Missing javadoc: field 'field'
JAVA011781.00JAVA0117 Missing javadoc: method 'method'
JAVA0118 1.00JAVA0118 Missing javadoc: type 'type'
JAVA0119 0.00JAVA0119 Control variable changed within body of for loop
JAVA0123 0.00JAVA0123 Use all three components of for loop
JAVA0125 0.00JAVA0125 Continue statement with label
JAVA0126 0.00JAVA0126 Method declares unchecked exception in throws
JAVA0128 3.00JAVA0128 Public constructor in non-public class
JAVA0130 0.00JAVA0130 Non-static method does not use instance fields
JAVA0131 0.00JAVA0131 Compatible method does not override base
JAVA0132 0.00JAVA0132 Method overload with compatible signature
JAVA0133 0.00JAVA0133 Non-synchronized method overrides synchronized method
JAVA0135 0.00JAVA0135 Only one of Object.equals and Object.hashCode defined: missing 'method'
JAVA0136 1.00JAVA0136 N methods defined in class (maximum: M)
JAVA0137 3.00JAVA0137 Non-abstract class missing constructor
JAVA0138 0.00JAVA0138 N parameters defined for method (maximum: M)
JAVA0139 0.00JAVA0139 Definition of main other than public static void main(java.lang.String[])
JAVA0141 2.00JAVA0141 Unnecessary modifier for method in interface
JAVA0143 4.00JAVA0143 Synchronized method
JAVA0144 1.00JAVA0144 Line exceeds maximum M characters
JAVA0145 0.00JAVA0145 Tab character used in source file
JAVA0150 0.00JAVA0150 java.lang.Error (or subclass) thrown
JAVA0153 0.00JAVA0153 Inefficient conversion of integer to string
JAVA0159 0.00JAVA0159 Inefficient conversion of string to integer
JAVA0160 1.00JAVA0160 Method does not throw specified exception
JAVA0161 0.00JAVA0161 Conditional wait() not in loop
JAVA0163 0.00JAVA0163 Empty statement
JAVA0165 0.00JAVA0165 Conflicting return statement in finally block
JAVA016610.00JAVA0166 Generic exception caught
JAVA0167 0.00JAVA0167 ThreadDeath not rethrown
JAVA0169 0.00JAVA0169 Unnecessary catch block: exception 'exception'
JAVA0170 7.00JAVA0170 Caught exception not derived from java.lang.Exception
JAVA0171 0.00JAVA0171 Unused local variable
JAVA0173 0.00JAVA0173 Unused method parameter
JAVA0174 3.00JAVA0174 Assigned local variable never used
JAVA0175 0.00JAVA0175 Successive assignment to variable
JAVA0176 0.00JAVA0176 Local variable name does not have required form
JAVA0177 0.00JAVA0177 Variable declaration missing initializer
JAVA0179 2.00JAVA0179 Local variable hides visible field
JAVA0233 0.00JAVA0233 Definition of serialVersionUID other than 'private static final long serialVersionUID'
JAVA0234 0.00JAVA0234 Class is Serializable but does not define serialVersionUID
JAVA0235 0.00JAVA0235 Class defines serialVersionUID but does not implement Serializable
JAVA0236 0.00JAVA0236 Attempt to clone an object which does not implement Cloneable
JAVA0237 0.00JAVA0237 Class implements Cloneable but does not have public clone method
JAVA0238 0.00JAVA0238 Clone method does not call super.clone()
JAVA0239 0.00JAVA0239 Class declares 'readObject' or 'writeObject' but does not implement Serializable
JAVA0240 0.00JAVA0240 Serializable class which declares readObject or writeObject but not both
JAVA0241 0.00JAVA0241 'readObject' or 'writeObject' should be declared private in Serializable class
JAVA0242 0.00JAVA0242 Transient field in non-Serializable class
JAVA0243 0.00JAVA0243 'readResolve' or 'writeReplace' should be declared private or protected
JAVA0244 0.00JAVA0244 Field or method name in subclass differs only by case from inherited field or method
JAVA0245 0.00JAVA0245 JUnit TestCase with non-trivial constructor
JAVA0246 0.00JAVA0246 JUnit assertXXX statement missing message parameter
JAVA0247 0.00JAVA0247 JUnit 'setUp()' and 'tearDown()' should call super method
JAVA0248 0.00JAVA0248 JUnit method 'setUp' or 'tearDown' with incorrect signature
JAVA0249 0.00JAVA0249 JUnit TestCase 'suite()' should be declared static
JAVA0250 0.00JAVA0250 JUnit TestCase declares testXXX method with incorrect signature
JAVA0251 0.00JAVA0251 Use '%n' for line breaks in printf/format for platform independence
JAVA0252 0.00JAVA0252 'enum' is a Java 1.5 reserved word
JAVA0253 0.00JAVA0253 Not all enum constants consumed in switch statement
JAVA0254 0.00JAVA0254 Use enhanced for loop construct instead of Iterator
JAVA0255 0.00JAVA0255 Result of method invocation not used
JAVA0256 0.00JAVA0256 Assignment of external collection/array to field
JAVA0257 0.00JAVA0257 Use of 'Constant Interface' anti-pattern
JAVA0258 0.00JAVA0258 Implement Iterable for foreach compatibility
JAVA0259 0.00JAVA0259 Return of collection/array field
JAVA0260 0.00JAVA0260 Use 'enum' instead of Enumerated Type pattern
JAVA0261 0.00JAVA0261 Use specialized Enum collection types
JAVA0262 0.00JAVA0262 Use of char in integer context
JAVA0263 0.00JAVA0263 Long literal ends with 'l' instead of 'L'
JAVA0264 6.00JAVA0264 Integer math in long context - check for overflow
JAVA0265 0.00JAVA0265 Use of Throwable.printStackTrace()
JAVA0266 0.00JAVA0266 Use of System.out
JAVA0267 0.00JAVA0267 Use of System.err
JAVA0269 0.00JAVA0269 Contents of StringBuffer never used
JAVA0270 5.00JAVA0270 Use Java 5.0 enhanced for loop construct to iterate over all elements in an array
JAVA0271 0.00JAVA0271 Minimize use of on-demand (.*) static imports
JAVA0272 0.00JAVA0272 Thread.run() called
JAVA0273 0.00JAVA0273 Non-final derivative of Thread calls start() in constructor
JAVA0274 0.00JAVA0274 Serializable class has a synchronized readObject()
JAVA0275 0.00JAVA0275 Serializable class has a synchronized writeObject() and no other synchronized methods
JAVA0276 0.00JAVA0276 Unnecessary use of String constructor
JAVA0277 0.00JAVA0277 Iterator.next() implementation does not throw NoSuchElementException
JAVA0278 0.00JAVA0278 Unnecessary use of Boolean constructor
JAVA0279 0.00JAVA0279 Serialization method readObject or readObjectNoData calls an overridable method
JAVA0280 0.00JAVA0280 IllegalMonitorStateException caught
JAVA0281 0.00JAVA0281 Iterator.next() not called in loop
JAVA0282 0.00JAVA0282 Call to Iterator.next() in loop which does not test Iterator.hasNext()
JAVA0283 0.00JAVA0283 Control variable not updated in loop body
JAVA0284 0.00JAVA0284 Explicit garbage collection
JAVA0285 0.00JAVA0285 Dereference of potentially null variable
JAVA0286 0.00JAVA0286 Dereference of null variable
JAVA0287 0.00JAVA0287 Unnecessary null check
JAVA0288 0.00JAVA0288 Inconsistent null check
LINES2022.00Number of lines in the source file
LINE_COMMENT167.00Number of line comments
LOC1095.00Lines of code
LOGICAL_LINES586.00Number of statements
LOOPS34.00Number of loops
NEST_DEPTH 8.00Maximum nesting depth
OPERANDS2265.00Number of operands
OPERATORS4900.00Number of operators
PARAMS60.00Number of formal parameter declarations
PROGRAM_LENGTH7165.00Halstead program length
PROGRAM_VOCAB643.00Halstead program vocabulary
PROGRAM_VOLUME 0.00Halstead program volume
RETURNS156.00Number of return points from functions
SIZE66604.00Size of the file in bytes
UNIQUE_OPERANDS579.00Number of unique operands
UNIQUE_OPERATORS64.00Number of unique operators
WHITESPACE341.00Number of whitespace lines