Non-public constructor causing problems with Tomcat7? - java

I have Java app with Spring running on tomcat.
This class is causing a very strange problem for me:
#WebListener
public class ThreadPool extends ThreadPoolExecutor implements ServletContextListener {
private ThreadPool() {
super(MIN_ACTIVE_THREADS, MAX_ACTIVE_THREADS, DEACTIVATE_THREADS_AFTER_TIMEPERIOD, TimeUnit.SECONDS, taskQueue);
}
private static final ThreadPoolExecutor pool = new ThreadPool();
public synchronized static void submit(Task task) {
executingTasks.add(task);
pool.execute(task);
}
#Override
public synchronized void contextDestroyed(ServletContextEvent arg0) {
cancelWaitingTasks();
sendStopSignalsToExecutingTasks();
pool.shutdown();
}
...
}
If the constructor is private or default I get this exception during runtime (on first HTTP request to the app):
Error configuring application listener of class com.testApp.util.ThreadPool
java.lang.IllegalAccessException: Class org.apache.catalina.core.DefaultInstanceManager can not access a member of class com.testApp.util.ThreadPool with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
at java.lang.Class.newInstance(Class.java:436)
at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:140)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4888)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5467)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Skipped installing application listeners due to previous error(s)
Error listenerStart
Context [] startup failed due to previous errors
But if i set the constructor public then I get no exceptions and everything works fine. Can anyone tell me why is this default or private constructor causing runtime exceptions?

Tomcat uses Class.newInstance() to create an instance of your ThreadPool. This method obeys the access rules of Java.
Since your constructor is private it fails with a IllegalAccessException. This is the runtime equivalent of not being allowed to call a function to the compiler error which you see if you would try to write new ThreadPool() outside of ThreadPool,

Tomcat's org.apache.catalina.core.DefaultInstanceManager is trying to create an object of your ThreadPool which you have configured as context listener. Now, since this is outside of org.apache.catalina.core you have to use a public constructor else org.apache.catalina.core.DefaultInstanceManager will not be able to create its object.
From org.apache.catalina.core.DefaultInstanceManager
private Object newInstance(Object instance, Class<?> clazz) throws IllegalAccessException, InvocationTargetException, NamingException {
if (!ignoreAnnotations) {
Map<String, String> injections = injectionMap.get(clazz.getName());
processAnnotations(instance, injections);
postConstruct(instance, clazz);
}
return instance;
}

Through the error, it said clearly because it cannot access a member of class.
can not access a member of class com.testApp.util.ThreadPool with modifiers

I think I accidentally discovered the real reason I was getting exceptions. Currently I am using this class, no exceptions thrown, tested on GlassFish and Tomcat:
public class TrackingThreadPool extends ThreadPoolExecutor {
private static final int MAX_WAITING_TASKS = 4000;
private static final int MAX_ACTIVE_THREADS = 20;
private static final int MIN_ACTIVE_THREADS = 4;
private static final int DEACTIVATE_THREADS_AFTER_SECONDS = 60;
private TrackingThreadPool() {
super(MIN_ACTIVE_THREADS, MAX_ACTIVE_THREADS, DEACTIVATE_THREADS_AFTER_SECONDS,
TimeUnit.SECONDS, waitingTasks);
}
private static final BlockingQueue<Runnable> waitingTasks = new LinkedBlockingQueue<>(MAX_WAITING_TASKS);
private static final Map<Long, Task> executingTasks = new HashMap<>(MAX_ACTIVE_THREADS * 2);
private static final TrackingThreadPool instance = new TrackingThreadPool();
public synchronized static void submitAndTrack(Task task) {
executingTasks.put(task.getId(), task);
instance.execute(task);
}
public synchronized static void shutdownAndCancelAllTasks() {
cancelWaitingTasks();
sendStopSignalToExecutingTasks();
instance.shutdown();
}
#Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
if (r instanceof Task) {
executingTasks.remove(((Task) r).getId());
}
}
private static void cancelWaitingTasks() {
List<Runnable> waitingTaskListRunnables = new ArrayList<>(waitingTasks.size() + 10); //+10 to avoid resizing
waitingTasks.drainTo(waitingTaskListRunnables);
for (Runnable r : waitingTaskListRunnables) {
if (r instanceof Task) {
((Task) r).sendStopSignal(byShutdownMethod());
}
}
}
private static void sendStopSignalToExecutingTasks() {
for (long taskId : executingTasks.keySet()) {
Task executingTask = executingTasks.get(taskId);
executingTask.sendStopSignal(byShutdownMethod());
}
}
private static String byShutdownMethod() {
return TrackingThreadPool.class.getSimpleName() + "#shutdownAndCancelAllTasks()";
}
}
And if I swap the positions of BlockingQueue<Runnable> waitingTasks and TrackingThreadPool instance like this:
private static final TrackingThreadPool instance = new TrackingThreadPool();
private static final Map<Long, Task> executingTasks = new HashMap<>(MAX_ACTIVE_THREADS * 2);
private static final BlockingQueue<Runnable> waitingTasks = new LinkedBlockingQueue<>(MAX_WAITING_TASKS);
I get exceptions again because waitingTasks is not instantiated by the time I make a new TrackingThreadPool instance.
I guess you can have a subclass of ThreadPoolExecutor with a private constructor / singelton pattern.

Related

ExecutorService unchecked assignment

I'm learning about ExecutorService and Callables, but get a warning from intelij saying I'm doing an unchecked assignment for this line:
Future<OrderWorker<OfferType>> future = executorService.submit(new OrderWorker<OfferType>(anOfferSet));
I don't get how to assign correctly. Here's the code:
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<OrderWorker<OfferType>>> futures = new ArrayList<>();
for (OfferType anOfferSet : offerSet) {
// the next assignment is unchecked:
Future<OrderWorker<OfferType>> future = executorService.submit(new OrderWorker<OfferType>(anOfferSet));
futures.add(future);
}
Order Worker:
public class OrderWorker<I extends OfferType> implements DataWorker {
private Logger log = Logger.getLogger(OrderWorker.class);
private final OfferType offer;
public OrderWorker(I data) {
this.offer = data;
}
public OfferType getOffer() {
return offer;
}
#Override
public Object call() throws Exception {
Thread.sleep(5000);
log.info(offer.getListingPrice().getAmount());
return this;
}
}
DataWorker interface:
interface DataWorker<I extends OfferType> extends Callable<I> {}
OfferType is a simple POJO class.
EDIT
I also tried to give DataWorker a type when implementing it:
public class OrderWorker<I extends OfferType> implements DataWorker<I>
This gives an error saying call() in OrderWorker clashes with call() in Callable -> incompatible return type
What am I doing wrong, and what do I have to do to make the assignment checked?
What you need to change is the declaration of OrderWorker and the return type of call, as next:
public class OrderWorker<I extends OfferType> implements Callable<OrderWorker<I>> {
...
#Override
public OrderWorker<I> call() throws Exception {
...
}
}

Static Field as Null when mocking Enums with PowerMock

I have written a Thread Pool and I am not able to write the Junits(PowerMock) for that class.
public enum ThreadPool {
INSTANCE;
private static final String THREAD_POOL_SIZE = "threadpool.objectlevel.size";
private static TPropertyReader PROP_READER = new PropertyReader();
private final ExecutorService executorService;
private static final ILogger LOGGER = LoggerFactory
.getLogger(ReportExecutorObjectLevelThreadPool.class.getName());
ThreadPool() {
loadProperties();
int no_of_threads = getThreadPoolSize();
executorService = Executors.newFixedThreadPool(no_of_threads);
}
public void submitTask(Runnable task) {
executorService.execute(task);
}
private static void loadProperties() {
try {
PROP_READER.loadProperties("Dummy");
} catch (final OODSystemException e) {
LOGGER.severe("Loading properties for app failed!");
}
}
private int getThreadPoolSize() {
return Integer.valueOf(PROP_READER
.getProperty(THREAD_POOL_SIZE));
}
}
While Mocking this class I am getting NullPointerException in the line PROP_READER.loadProperties("DUMMY");
My Test Case is:-
PowerMockito.whenNew(PropertyReader.class).withNoArguments().thenReturn(mockPropertyReader);
PowerMockito.doNothing().when( mockPropertyReader,"loadProperties",anyString());
mockStatic(ThreadPool.class);
First you need to set your internal state of your enum as enum is final class
and the instance of an enum will be load on class loading
ThreadPool mockInstance = mock(ThreadPool .class);
Whitebox.setInternalState(ThreadPool.class, "INSTANCE", mockInstance);
then
PowerMockito.mockStatic(ThreadPool .class);
and then mocking
doNothing().when(mockInstance).loadProperties(any(String.class));
do not forget adding the following annotation to the test
#RunWith(PowerMockRunner.class)
#PrepareForTest({ThreadPool.class})
if it still not working you need to see which more member of the class you need to set in the internal state

Java RMI object static and not static field?

So I have this code:
public class RemoteImpl extends UnicastRemoteObject implements TestRemote {
private static final long serialVersionUID = 1L;
private static int counter = 0;
private int localizedCounter = 0;
protected RemoteImpl() throws RemoteException {
super();
}
#Override
public int getMeGlobalCounter() throws RemoteException {
counter++;
return counter;
}
#Override
public int getMeLocalizedCounter() throws RemoteException {
localizedCounter++;
return localizedCounter;
}
}
And with my Client I am trying:
public class TestClient {
public static void main(String[] args) throws Exception {
Registry registry = LocateRegistry.getRegistry("localhost", Constant.RMI_PORT);
TestRemote remote = (TestRemote) registry.lookup(Constant.RMI_ID);
System.out.println("Global counter:" + remote.getMeGlobalCounter());
System.out.println("Localized counter:" + remote.getMeLocalizedCounter());
}
}
After running this code for the 2 times I am expecting to see:
Global counter:3
Localized counter:1
however I see that
Localized counter:3
So why is the localized counter not reset everytime I invoke this method? Am I not getting a new object everytime?
Am I not getting a new object every time?
No you aren't. You're getting the same instance that was bound into the Registry. RMI doesn't just create remote objects willy-nilly.

thread from static method Java

What I want to do is, pass clientId to ClearSession() and use clientId in run() to call session.loadByLastAccessed(). But the error it throws is...
Service.java:117: non-static variable this cannot be referenced from a static context
at Thread t = new Thread(new ClearSession(clientId)) (since it is inner class)
If I change the class to be static, it will throw an error on session.loadByLastAccessed(entityManager, clientId); since entityManager is non-static.
Any ideas on how to start() a thread from a static method and pass a non-static variable?
This is my code...
private EntityManager entityManager; //declared within class along with code below.
public static void initClients()
throws SessionServiceException
{
Properties properties = ApplicationConfig.getInstance().getProperties();
Set<Object> keys = properties.keySet();
String clientId = null;
for (Object keyObject : keys)
{
String key = (String)keyObject;
if (key.startsWith(SessionFactory.CLIENT_PREFIX))
{
clientId = StringUtils.substringAfter(key, SessionFactory.CLIENT_PREFIX);
SessionFactory.getSessionIntf(clientId);
}
}
if(!StringUtils.equals("branch", clientId ))
{
Thread t = new Thread(new ClearSession(clientId));
t.start();
}
}
private class ClearSession implements Runnable
{
private String clientId = "";
public ClearSession(String clientId)
{
this.clientId = clientId;
}
public void run()
{
try
{
// Pause for 2 hours
Thread.sleep(7200000);
// get client session
AbstractImpl session = SessionFactory.getSessionIntf(clientId);
session.loadByLastAccessed(entityManager, clientId);
} catch (InterruptedException ie) {
throw ie;
}
}
}
I see now. You have private class, it means it is inner class. By default inner classes implicitly reference outer class's this. Just declare the class as private static class or just move it outside.

Problem while creating Singleton

I am trying to create a Singleton class, which will be accessed from two other classes.Can anyone please tell me whats wrong with the following code? I am just not able to figure out!
import java.util.LinkedList;
public class MessageQueue {
private static final LinkedList<ServerDataEvent> queue = new LinkedList<ServerDataEvent>();;
private static MessageQueue messageQueue = null;
/** A private Constructor prevents any other class from instantiating. */
private MessageQueue() {
}
/** Static 'instance' method */
public static MessageQueue getInstance() {
if (MessageQueue.messageQueue == null) {
System.out.println("Creating MessageQueue instance.");
MessageQueue.messageQueue = new MessageQueue();
}
return MessageQueue.messageQueue;
}
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
I am accessing the singleton object from other classes like this:
MessageQueue messageQueue = MessageQueue.getInstance();
There are no errors, but
System.out.println("Creating MessageQueue instance.");
is getting executed whenever I do
MessageQueue messageQueue = MessageQueue.getInstance();
EDIT 1
import java.util.LinkedList;
public class MessageQueue {
private static final LinkedList<ServerDataEvent> queue = new LinkedList<ServerDataEvent>();;
private static final MessageQueue messageQueue = new MessageQueue();
/** A private Constructor prevents any other class from instantiating. */
private MessageQueue() {
System.out.println("problem...");
}
/** Static 'instance' method */
public static MessageQueue getInstance() {
return MessageQueue.messageQueue;
}
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
First of all, you did not specify any errors you get. If you want to get help, you should give us as much information as you can.
Secondly, the best fool-proof way to create a singleton in Java is this:
public enum MySingleton {
INSTANCE;
//whatever methods you want to implement
}
and you access it like so: MySingleton.INSTANCE.whatever().
It is much better to define and instantiate your singleton object like this:
private static final MessageQueue messageQueue = new MessageQueue();
And then getInstance will be just:
public static MessageQueue getInstance() {
return MessageQueue.messageQueue;
}
This way your singleton object is instantiated and will be thread safe because it is created by the class loader.
A shorter version which is thread safe.
public enum MessageQueue {
INSTANCE;
private final Queue<ServerDataEvent> queue =
new ConcurrentLinkedQueue<ServerDataEvent>();
public void addEvent(ServerDataEvent event) { queue.add(event); }
}
or
public enum MessageQueue {
;
private static final Queue<ServerDataEvent> queue =
new ConcurrentLinkedQueue<ServerDataEvent>();
public static void addEvent(ServerDataEvent event) { queue.add(event); }
}
would be easier if you did it this way...
public class MessageQueue {
private static final MessageQueue INSTANCE= new MessageQueue();
public static MessageQueue getINSTANCE() {
return INSTANCE;
}
private MessageQueue() {
}
}
What's the error that occurs? All I can see from this is you have two semicolons here:
private static final LinkedList<ServerDataEvent> queue = new LinkedList<ServerDataEvent>();;
Simplest method:
private static final MessageQueue messageQueue = new MessageQueue();
public static MessageQueue getInstance() {
return MessageQueue.messageQueue;
}

Categories