Spring AOP logging thread method - java

Is there any way to implement AOP logging to public method of class that implements Runnable and ran by ExecutorService?
Thread class
#Component
#Scope("prototype")
public class FileProcessor implements Runnable {
private final LinkedBlockingQueue<File> filesQueue;
private final GiftCertificateMapper certificateMapper;
private final File errorFolder;
private static final ReentrantLock LOCK = new ReentrantLock();
private static final Logger LOGGER = LoggerFactory.getLogger(FileProcessor.class);
public FileProcessor(LinkedBlockingQueue<File> filesQueue, GiftCertificateMapper certificateMapper,
File errorFolder) {
this.filesQueue = filesQueue;
this.certificateMapper = certificateMapper;
this.errorFolder = errorFolder;
}
#Override
public void run() {
File file = null;
try {
while ((file = filesQueue.poll(100, TimeUnit.MILLISECONDS)) != null) {
processFile(file);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LOGGER.warn("File thread was interrupted");
} catch (IOException e) {
LOGGER.error("Error processing file {} \n{}", file.getAbsolutePath(), e);
}
}
public void processFile(File file) throws IOException {
if (file != null) {
try {
ObjectMapper objectMapper = new ObjectMapper();
List<GiftCertificate> certificates = Arrays.asList(objectMapper.readValue(file, GiftCertificate[].class));
certificateMapper.insertList(certificates);
file.delete();
} catch (JsonParseException | UnrecognizedPropertyException | InvalidFormatException | DataIntegrityViolationException e) {
moveFileToErrorFolder(file);
}
}
}
private void moveFileToErrorFolder(File file) throws IOException {
try {
LOCK.lock();
Files.move(Paths.get(file.getAbsolutePath()), getPathForMovingFile(file), StandardCopyOption.ATOMIC_MOVE);
} finally {
LOCK.unlock();
}
}
private Path getPathForMovingFile(File fileForMove) {
File fileList[] = errorFolder.listFiles();
int filesWithSameNameCounter = 0;
if (fileList != null && fileList.length > 0) {
for (File file : fileList) {
if (file.getName().contains(fileForMove.getName())) {
filesWithSameNameCounter++;
}
}
}
return filesWithSameNameCounter > 0 ?
Paths.get(errorFolder.getAbsolutePath(), "(" + filesWithSameNameCounter + ")" + fileForMove.getName()) :
Paths.get(errorFolder.getAbsolutePath(), fileForMove.getName());
}
}
Aspect
#Aspect
#Component
#ConditionalOnProperty(
value = "file-processing.logging.enabled",
havingValue = "true",
matchIfMissing = true)
public class FileProcessingLoggingAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(FileProcessingLoggingAspect.class);
#Pointcut("execution(* com.epam.esm.processor.FileProcessor.processFile(java.io.File))")
public void processFilePointcut() {
}
#Around("processFilePointcut()")
public Object logFileProcessing(ProceedingJoinPoint joinPoint) throws Throwable {
// File file = (File) joinPoint.getArgs()[0];
// long time = System.currentTimeMillis();
Object object = joinPoint.proceed();
// long resultTime = System.currentTimeMillis() - time;
LOGGER.info("Processing of file took milliseconds");
return object;
}
}

In Spring AOP , internal method calls cannot be intercepted.
In the code shared , even though the method processFile() is public , it gets called from run(). This is a self reference / internal method call , which cannot be intercepted.
Details can be read in the documentation
Due to the proxy-based nature of Spring’s AOP framework, calls within
the target object are, by definition, not intercepted. For JDK
proxies, only public interface method calls on the proxy can be
intercepted
A pointcut expression to intercept all external method calls to a class implementing Runnable would be as follows
#Around("this(java.lang.Runnable) && within(com.epam.esm.processor..*)")
public Object logFileProcessing(ProceedingJoinPoint pjp) throws Throwable {
try {
return pjp.proceed();
} finally {
//log
System.out.println("****Logged");
}
}
Scoping designator within() limits the scope to apply the advice.
The point cut #Pointcut("execution(* com.epam.esm.processor.FileProcessor.processFile(java.io.File))") is valid and would work if an external method call happens to it.
Hope this helps.

Related

Spring Batch - Not Shutting down - Due to Static Method call

I have completed a spring batch (Standalone Jar) in Spring Boot + CommandLineRunner. But the JVM is not getting shutdown after completion. After doing some research initially I thought its not shutting down because of below reasons.
1 . I am not closing the spring application context at the end ofcommandline runner.
2 . Executor service is not shutdown properly which might have caused the JVM from shutting down.
I dont want to call system.exit which is a forceful shutdown.
I tried closing the application context and also verified executor service is shutdown using isShutdown method (returns true).
Then I found out the root cause, it is because I am calling a static method which is the culprit. When I commented the static method call, the job was shutting down gracefully even if I dont close the application context explicitly.
I am not sure why this behavior and do I need to convert everything to objects or is there something else I am missing here. Can someone please throw some light.
Main Class
#SpringBootApplication
#ComponentScan(basePackages = "com.acn.abp.printbatch")
#EnableTransactionManagement
#ImportResource({ "ABPBatchInfrastructure.xml", "financeBillPayAppConfig.xml" })
public class financeBillPayFileUploadApplication extends PrintBatchConstants implements CommandLineRunner {
#Autowired
private NotifyConfig notify;
#Autowired
private ApplicationContext ctx;
static final Logger logger = LoggerFactory.getLogger(financeBillPayFileUploadApplication.class);
public static void main(String[] args) {
SpringApplication application = new SpringApplication(financeBillPayFileUploadApplication.class);
application.setBannerMode(Banner.Mode.OFF);
application.run(args);
}
#Override
public void run(String... args) throws Exception {
logger.info(notify.getEnvironment());
JobLauncher jobLauncher = ctx.getBean(JobLauncher.class);
Job job = ctx.getBean(Job.class);
jobLauncher.run(job,
new JobParametersBuilder()
.addString(batchDocumentClass, "InvoiceStatementDocumentation")
.addString(batchType, "2020-06-04")
.addString(batchEmailID, notify.getSupportEmailId())
.addString(batchEnvironment, notify.getEnvironment())
.toJobParameters());
System.out.println("Here cxf");
((ConfigurableApplicationContext)ctx).close();
}
}
Below Class which is causing the problem. If I comment out below code then everything works perfectly.
populateItemDocuments(job, printConfig.geteCMObjectStore(), printConfig.geteCMUserId());
Class file where this method is called
#Component
public class DuplexWorker implements Callable {
static final Logger logger = LoggerFactory.getLogger(DuplexWorker.class);
#Autowired
private ManageFormService formgmtClient;
#Autowired
private PostScriptService postScriptService;
#Autowired
private BarcodeService barcodeService;
private static CfBatchPrintConfiguration printConfig;
private static CfPersistenceUtil dbUtilService;
private static FilenetDocumentRetrieval docmgmtClient;
#Autowired
public DuplexWorker(CfPersistenceUtil dbUtilService,CfBatchPrintConfiguration printConfig,FilenetDocumentRetrieval docmgmtClient) {
DuplexWorker.dbUtilService = dbUtilService;
DuplexWorker.printConfig = printConfig;
DuplexWorker.docmgmtClient=docmgmtClient;
}
private MailUtil mailUtil;
private NotifyConfig notify;
private List<PrintJobItem> printJobItems;
private List<String> groupIds;
private ArrayList duplexJobs;
private String groupId;
private CountDownLatch latch;
public DuplexWorker(ArrayList duplexJobs, String groupId,CountDownLatch latch) {
super();
this.latch=latch;
this.duplexJobs = duplexJobs;
this.groupId = groupId;
}
public DuplexWorker(CountDownLatch latch, MailUtil mailUtil,NotifyConfig notify,List<PrintJobItem> findByPrintStatusEquals,List<String>groupIds) {
this.latch=latch;
this.mailUtil=mailUtil;
this.notify=notify;
this.printJobItems=findByPrintStatusEquals;
this.groupIds=groupIds;
}
#Override
public Object call() throws Exception {
try {
if ((duplexJobs != null) && (!duplexJobs.isEmpty())) {
String prevJobId = null;
int docCount = 0;
CvPrintJob consolidatedPrintJob = (CvPrintJob)duplexJobs.get(0);
ArrayList printItems = new ArrayList();
if (consolidatedPrintJob != null)
{
ArrayList items = consolidatedPrintJob.getPrintJobItems();
int numPages = 0;
if ((items != null) && (!items.isEmpty()))
{
CvPrintJobItem firstItem = (CvPrintJobItem)items.get(0);
numPages = CfBatchPrintUtil.getItemTotalPages(firstItem);
logger.info("Item Total Pages == " + numPages);
logger.info("Job Item Page Limit == " +
printConfig.getJobItemPageLimit());
consolidatedPrintJob.setSequence(firstItem.getSequence());
}
if (numPages <= printConfig.getJobItemPageLimit())
{
consolidatedPrintJob.setHasLargeItems(false);
logger.info("Item setHasLargeItems == false");
}
else
{
consolidatedPrintJob.setHasLargeItems(true);
logger.info("Item setHasLargeItems == true");
}
}
ArrayList startBannerDataList = new ArrayList();
ArrayList barcodeList = new ArrayList();
ArrayList barcodeCorresPageCount = new ArrayList();
ArrayList statementNumberList = new ArrayList();
for (int i = 0; i < duplexJobs.size(); i++)
{
CvPrintJob job = (CvPrintJob)duplexJobs.get(i);
if ((prevJobId == null) ||
(!prevJobId.equalsIgnoreCase(job.getJobId()))) {
docCount = 0;
}
populateItemDocuments(job, printConfig.geteCMObjectStore(), printConfig.geteCMUserId());
}
consolidatedPrintJob.setPrintJobItems(printItems);
}
else
{
logger.info("====================================================================");
logger.info("=================>> No DUPLEX jobs to process <<===================");
logger.info("====================================================================");
}
duplexJobs = null;
this.latch.countDown();
System.gc();
return null;
}catch(Exception e) {
e.printStackTrace();
return null;
}
}
public static void populateItemDocuments(CvPrintJob job, String objectStore, String userid)
throws CfException
{
logger.info("Enters populateItemDocuments");
try
{
ArrayList items = job.getPrintJobItems();
job.setIsProcess(true);
ArrayList modelDocList = null;
logger.info("Items size::::::" + items.size());
for (int i = 0; i < items.size(); i++)
{
modelDocList = new ArrayList();
CvPrintJobItem x = (CvPrintJobItem)items.get(i);
ArrayList guidList = x.getGuidList();
if ((guidList != null) && (!guidList.isEmpty())) {
modelDocList.addAll(guidList);
}
logger.info("guidList size::::::" + guidList.size());
CvRenderPayloadRequest cvRenderPayloadRequest = null;
if ((modelDocList != null) && (!modelDocList.isEmpty()))
{
cvRenderPayloadRequest = new CvRenderPayloadRequest();
logger.info("Before creating CvRenderPayloadRequest");
logger.info("Document Class::: " +
x.getDocumentClass());
cvRenderPayloadRequest.setDocumentClass(
x.getDocumentClass());
cvRenderPayloadRequest.setGuid(modelDocList);
cvRenderPayloadRequest.setUserId(userid);
logger.info("After creating the CvRenderPayloadRequest");
try
{
if (cvRenderPayloadRequest != null)
{
List pdfContents = docmgmtClient.retrieveDocument(cvRenderPayloadRequest.getGuid());
if ((pdfContents != null) &&
(!pdfContents.isEmpty()))
{
logger.info(
"PDF contents sizenew::::::::::::::" + pdfContents.size());
Iterator pdfItr = pdfContents.iterator();
while (pdfItr.hasNext())
{
byte[] contents = (byte[])pdfItr.next();
CvPrintJobItem item = (CvPrintJobItem)items.get(i);
item.addDocumentList(contents);
int filenetpagecount = 100;
item.setPageCountFromFileNet(filenetpagecount);
logger.info("PageCOunt from Filenet " + filenetpagecount);
}
}
}
}
catch (Exception e)
{
e.printStackTrace();
throw new CfException(" Error populating documents" + e);
}
}
}
}
catch (Exception e)
{
e.printStackTrace();
throw new CfException(" Error populating documents" + e);
}
logger.info("Exits populateItemDocuments");
}
First of all you are using Tomcat server that runs the application. If you want to make standalone spring application you can configure like below
#Configuration
public class ApplicationMain {
#Bean
public Stackoverflow stackoverflow() {
return new Stackoverflow ();
}
public static void main(String[] args) {
ConfigurableApplicationContext configurableApplicationContext = new AnnotationConfigApplicationContext(ApplicationMain.class);
System.out.println(configurableApplicationContext.getBean("stackoverflow"));
}
}
'JVM is not getting shutdown after completion.' is normal behavior for Tomcat server because it waits for request to handle.
You can give basepackage like below
new AnnotationConfigApplicationContext("com.example");
it will scan the package for you

How to simulate throwing an exception only once in retry with JUnit/Mockito test?

I put a simple retry because the operation can rarely fail. The simplified code is below. The method putObject can accidentally throw an exception, in this case the retry should allow to invoke this method again. Is it possible to write a JUnit test for this?
I know that with Mockito library we can force to throw an Exception invoking a method but how to force this exception to be thrown only once?
public class RetryExample {
Bucket bucket = new Bucket();
static int INTERNAL_EXCEPTION_CODE = 100;
class AException extends RuntimeException {
private static final long serialVersionUID = 1L;
int statusCode;
public int getStatusCode() {
return statusCode;
}
}
class Bucket {
public void putObject(String fileName, byte[] data) throws AException {
System.out.println("PutObject=" + fileName + " data=" + data);
}
}
public void process(String fileName, byte[] data) throws AException {
try {
retryOperation((f, d) -> bucket.putObject(f, d), fileName, data);
} catch (Exception ex) {
throw new AException("Failed to write data", ex);
}
}
private <T, U> void retryOperation(BiConsumer<T, U> biConsumer, T t, U u) {
int retries = 0;
boolean retry = false;
AException lastServiceException = null;
do {
try {
biConsumer.accept(t, u);
} catch (AException e) {
lastServiceException = e;
int statusCode = e.getStatusCode();
if (statusCode == INTERNAL_EXCEPTION_CODE) {
throw e;
} else {
break;
}
}
retries++;
if (retries >= 3) {
retry = false;
}
} while (retry);
if (lastServiceException != null) {
throw lastServiceException;
}
}
Test Class:
public class RetryExampleTest {
...
#Test
public void test() {
RetryExample retryExample = new RetryExample();
String fileName = "TestFile";
byte[] data = simulatedPayload(10000);
try {
retryExample.process(fileName, data);
} catch (Exception e) {
fail("Exception thrown=" + e);
}
}
According to the Mockito documentation you can set different behavior for consecutive method calls.
when(mock.someMethod("some arg"))
.thenThrow(new RuntimeException())
.thenReturn("foo");
In case of a void method you can do something similar (Mockito documentation)
doThrow(new RuntimeException())
.doNothing()
.when(mock).doSomething();
I think you can use a global data object to store the times of throw Exceptions, so in the Mockito library invoke the Exception method just taken the global data object to record the times. It would be simple. Just all by your control.

Testing a method that reads and processes data from a file [duplicate]

This question already has answers here:
Mocking Files in Java - Mock Contents - Mockito
(3 answers)
Closed 6 years ago.
I have the following code:
public class FolderServiceImpl implements FolderService {
private static final Logger L = LoggerFactory.getLogger(FolderServiceImpl.class);
public int getStatus(String folderPath) {
int status = 0;
File folderStatusFile = new File(folderPath, ".folderstatus");
if (folderStatusFile.exists()) {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(folderStatusFile));
String line = br.readLine();
status = Integer.parseInt(line);
} catch (Exception e) {
L.error("can't read file " + folderStatusFile.getAbsolutePath(), e);
status = 4;
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
L.warn("could not close reader ", e);
}
}
}
} else {
status = 3;
}
return status;
}
}
I want to test this method without creating actual files for every case. I should be using Java 1.7, JUnit 4, Mockito and/or PowerMockito.
Any ideas on how to do that?
I am talking about mocking either the data source or simply changeing the input for the method.
My test looks something like this:
`#Rule
public TemporaryFolder folder = new TemporaryFolder();
private FolderServiceImpl serviceToTest = new FolderServiceImpl();
private String folderPath;
#Before
public void setUp() {
folderPath = folder.getRoot().getAbsolutePath();
try {
folder.newFile(".folderstatus");
} catch (IOException e) {
e.printStackTrace();
}
}
#Test
public void shouldReturnFolderStatus3WhenFolderStatusIsNotFound() {
// given
deleteFolderStatusFile();
// actual
int status = serviceToTest.getFolderStatus(folderPath);
// expected
assertEquals(3, status);
}
#Test
public void shouldReturnFolderStatus4WhenTheStatusIsUnreadable() {
// given
writeStatusToTestFile("Test");
// actual
int status = serviceToTest.getFolderStatus(folderPath);
// expected
assertEquals(4, status);
}
#Test
public void shouldReturnFolderStatusInTheFile() {
// given
writeStatusToTestFile("1");
// actual
int status = serviceToTest.getFolderStatus(folderPath);
// expected
assertEquals(1, status);
}
private void writeStatusToTestFile(String status) {
Path file = Paths.get(folder.getRoot().getAbsolutePath(), ".folderstatus");
try {
Files.write(file, status.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
private void deleteFolderStatusFile() {
Path file = Paths.get(folder.getRoot().getAbsolutePath(), ".folderstatus");
try {
Files.delete(file);
} catch (IOException e) {
e.printStackTrace();
}
}`
Although the answer of #BenHeid may work I'd suggest to change to different approach.
IMHO when ever I use PowerMock(-ito) it is a surrender to bad design.
Also the PowerMock solution will confuse test coverage tools since it changes the Applications byte code after it has been instrumented for coverage measurement.
So the approach I'd prefer is to stick to Clean Code and OOP rules.
One of them is separation of concerns.
In your case the method creates some infrastructure classes (dependencies) to work with, namely FileReader and BufferedReader.
But the instantiation of (direct) dependencies is not a responsibility of a class containing business logic.
Therefore I'd suggest to refactor that code out into a separate class:
class ReaderFactory {
public BufferedReader createFor(File file) throws FileNotFoundException {
return new BufferedReader(new FileReader(file));
}
}
Your Class would change to this:
class FolderServiceImpl {
private static final Logger L = LoggerFactory.getLogger(FolderServiceImpl.class);
private final ReaderFactory readerFactory;
FolderServiceImpl(ReaderFactory readerFactory) {
this.readerFactory = readerFactory;
}
public int getStatus(String folderPath) {
int status = 0;
File folderStatusFile = new File(folderPath, ".folderstatus");
// try "with resource" takes care of closing the reader
try (BufferedReader br = readerFactory.createFor(folderStatusFile);) {
String line = br.readLine();
status = Integer.parseInt(line);
} catch (IOException e) {
status = 3;
} catch (Exception e) {
L.error("can't read file " + folderStatusFile.getAbsolutePath(), e);
status = 4;
}
return status;
}
}
And your Test would be this:
public class FolderServiceImplTest {
private static final String ANY_FILE_NAME = "";
#Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
#Rule
public ExpectedException thrown = ExpectedException.none();
#Mock
private ReaderFactory readerFactory;
#InjectMocks
FolderServiceImpl sut;
#Test
public void getStatus_FileNotExisting_returnStatus3() throws Exception {
// arrange
Mockito.doThrow(new FileNotFoundException("UnitTest")).when(readerFactory).createFor(Mockito.any(File.class));
// act
int status = sut.getStatus(ANY_FILE_NAME);
// assert
Assert.assertThat("status",status,CoreMatchers.equalTo(3));
}
#Test
public void getStatus_ValidFile_returnFileContentAsInt() throws Exception {
// arrange
BufferedReader bufferedReader = Mockito.mock(BufferedReader.class);
Mockito.doReturn(bufferedReader).when(readerFactory).createFor(Mockito.any(File.class));
Mockito.doReturn("4711").when(bufferedReader).readLine();
// act
int status = sut.getStatus(ANY_FILE_NAME);
// assert
Assert.assertThat("status",status,CoreMatchers.equalTo(4711));
}
}
You have to use something like this:
#RunWith(PowerMockRunner.class)
#PrepareForTest(tests.class)
public class test {
#Test
public void test() throws Exception {
File fileMock = Mockito.mock(File.class);
PowerMockito.whenNew(File.class).withArguments(Mockito.anyString(), Mockito.anyString()).thenReturn(fileMock);
FolderServiceImpl sut = new FolderServiceImpl sut ();
Mockito.when(fileMock.exists()).thenReturn(true);
sut.getStatus("");
// Your verifications..
}
}
Powermock will mock the File object which is created in the method getStatus of your class. With Mockito.when you can say what is the return value of folderStatusFile.exists() in your code.
EDIT
I have included the following two jars with maven, but you don't need to use maven: https://mvnrepository.com/artifact/org.powermock/powermock-module-junit4/1.4.6 and https://mvnrepository.com/artifact/org.powermock/powermock-api-mockito/1.4.9 and https://mvnrepository.com/artifact/org.mockito/mockito-all/1.10.19

Spring MVC blocking queue with initializing of huge library

I am using a huge library in my application. I cannot initialize the library every time a request come so I put the initialization into the configuration. I have implemented a queue and a service for managing the queue. After application is loaded I have two instances running. Problem is that it stucks and no response is getting back.
Application context xml:
<context:component-scan base-package="com.metadata.tripletws.model" />
<context:component-scan base-package="com.metadata.tripletws.service" />
<bean id="wsdService" class="com.metadata.tripletws.service.WsdService" init-method="init"></bean>
<context:component-scan base-package="com.metadata.tripletws.controller" />
Service
#Service
public class WsdService
{
public final static int MAX_THREADS = 2;
private WsdQueue queue;
public void init()
{
try {
queue = new WsdQueue(MAX_THREADS);
queue.initQueue();
} catch (InterruptedException ex) {
Logger.getLogger(WsdService.class.getName()).log(Level.SEVERE, null, ex);
}
}
public WSD getInstance() throws InterruptedException
{
return queue.dequeue();
}
public void releaseInstance(WSD instance) throws InterruptedException
{
queue.enqueue(instance);
}
}
Queue
public class WsdQueue
{
private List<WSD> queue = new LinkedList();
private int limit = 5;
public WsdQueue()
{
}
public WsdQueue(int limit)
{
this.limit = limit;
}
public void initQueue() throws InterruptedException
{
for (int i = 0; i < limit; i++) {
System.out.println("Initializing WSD nr." + i);
WSD wsd = new WSD();
wsd.Initialize();
this.enqueue(wsd);
}
}
public synchronized void enqueue(WSD item) throws InterruptedException
{
while (this.queue.size() == this.limit) {
wait();
}
if (this.queue.size() == 0) {
notifyAll();
}
System.out.println("Adding instance");
this.queue.add(item);
}
public synchronized WSD dequeue() throws InterruptedException
{
while (this.queue.size() == 0) {
wait();
}
if (this.queue.size() == this.limit) {
notifyAll();
}
System.out.println("Taking instance");
return this.queue.remove(0);
}
}
and here is the controller
Controller
#RequestMapping(value = "/api")
public class ApiController
{
#Autowired
private WsdService wsdService;
#RequestMapping(value = "/wordnet", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody
ArrayList<LexicalWord> getWordsFromSentence(#RequestBody String sentence)
{
ArrayList<LexicalWord> results = new ArrayList<>();
try {
WSD wsdInstance = wsdService.getInstance();
List<CWSDResult> list = wsdInstance.AnanlyseSentenceToList(sentence);
for (CWSDResult res : list) {
if (!res.hasLegalSense) {
continue;
}
String key = getHighestProbableSynsetKey(res);
if (key != null && res.senses.containsKey(key)) {
Synset synset = res.senses.get(key);
if (synset != null) {
results.add(new LexicalWord(res.token, synset.getLexFileName()));
}
}
}
wsdService.releaseInstance(wsdInstance);
} catch (InterruptedException ex) {
Logger.getLogger(ApiController.class.getName()).log(Level.SEVERE, null, ex);
}
return results;
}
}
This is the first time I am making a queue and working with threads and I appriciate any kind of help or example. There is no error, it just stucks, does nothing and no response is send back.
EDIT1:
after answers I changed the code, but no luck. Still stucks. Maybe the problem is somewhere else, but when I send a single request it works and I get the response.
#Component
public class WsdService
{
public final static int MAX_THREADS = 2;
private BlockingQueue<WSD> queue;
public WsdService()
{
queue = new ArrayBlockingQueue(MAX_THREADS);
}
#PostConstruct
public void init()
{
try {
for (int i = 0; i < MAX_THREADS; i++) {
WSD wsd = new WSD();
wsd.Initialize();
System.out.println("WSD nr. " + i + " initialized!");
queue.put(wsd);
}
} catch (InterruptedException ex) {
Logger.getLogger(WsdService.class.getName()).log(Level.SEVERE, null, ex);
}
}
public WSD getInstance() throws InterruptedException
{
return queue.take();
}
public void releaseInstance(WSD instance) throws InterruptedException
{
queue.put(instance);
}
}
and here is new applicationContext
<context:component-scan base-package="com.metadata.tripletws.model" />
<context:component-scan base-package="com.metadata.tripletws.service" />
<context:component-scan base-package="com.metadata.tripletws.controller" />
SOLUTION
So ..after lot of digging of the library I assumed it is not possible to use multithreading there. Anyway I used the blockingQueue in other service (NLP) and it is working nicely (Same as EDIT1 just the variable is different). Thanks everybody for your help.
Thanks,
Michal
So you're essentially trying to make a pool of WSDs?. You're certain that WSD isn't thread-safe?
You can safely throw your queue in the garbage, and use a correct ready made version of BlockingQueue instead. It might not necessarily solve your actual problem, but it'll be a working version of what you're attempting here.

Issue invoking WatchService inside a singleton bean

we wanted to watch a file periodically for changes, we are using jboss 7 . Following is my code snippet. I initialized the watcher in the postconstruct method of singleton bean and scheduled a method to poll watch events. I could observe the changes when i modify the file very first time, however the subsequent modifications to the file are not recieved . Can anyone please let me know what could be the issue
#Startup
#ConcurrencyManagement(ConcurrencyManagementType.BEAN)
#Interceptors(NonThrowingPostConstructInterceptor.class)
#Singleton
#Service
#LocalBinding(jndiBinding=IHeartBeatProducerService.JNDI_LOCAL_BINDING)
public class HeartBeatProducerService extends EMSingletonService implements IHeartBeatProducerService{
#EJB(mappedName=IMessageService.JNDI_LOCAL_BINDING)
public IMessageService messageService;
#EJB(mappedName=ICommandExecutionService.JNDI_LOCAL_BINDING)
public ICommandExecutionService commandService;
private final static String LAST_OPERATION_COMPLETED="Last Operation Completed";
private final static String STATUS="Status";
private WatchService watcher;
private Path dir;
private String concServer;
public static final String TOPIC="foo";
private IMLogger logger = new IMLogger("foo");
private String content=null;
#PostConstruct
#Override
public void init() {
// TODO Auto-generated method stub
super.init();
try {
watcher = FileSystems.getDefault().newWatchService();
dir=Paths.get("/shared/foo");
dir.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY);
logger.entering(0, IHeartBeatProducerService.class.getSimpleName(), "Initializing Heart Beat", new String[]{"Entered"});
} catch (IOException e) {
e.printStackTrace();
}
}
#Schedule(second="*/10", minute = "*", hour="*")
private void checkStatus()
{
logger.entering(0, IHeartBeatProducerService.class.getSimpleName(), "Checking Status", new String[]{"Entered"});
final String[] command={"pidof","server"};
commandService.run(command, null, false);
concServer=(commandService.getExitCode()==0)?"UP":"DOWN";
if(concServer.equals("UP"))
{
watch();
}
else
{
content="foo:Failed";
}
produce();
}
public void watch()
{
logger.entering(0, IHeartBeatProducerService.class.getSimpleName(), "Entering watch()", new String[]{"Entered"});
WatchKey key = null;
try
{
key = watcher.take();
}
catch (InterruptedException e)
{
logger.error(HeartBeatProducerService.class.getSimpleName(),"Interupted Exception " + e.getMessage());
}
for ( WatchEvent<?> event: key.pollEvents())
{
WatchEvent.Kind kind = event.kind();
logger.info(HeartBeatProducerService.class.getSimpleName(),"Watch Event :" + kind.name());
if(kind.name().equals("OVERFLOW"))
{
continue;
}
if(kind.name().equals("ENTRY_MODIFY"))
{
Path concLog = (Path) event.context();
logger.info(HeartBeatProducerService.class.getSimpleName(),"Modified File Name:" + concLog.getFileName());
if(concLog.endsWith("current_status.txt"))
{
logger.info(HeartBeatProducerService.class.getSimpleName(), "Reading Status");
readStatus();
}
}
}
boolean valid = key.reset();
if ( !valid)
{
logger.error(HeartBeatProducerService.class.getSimpleName(),"Key Unregistered");
}
}
private void parse(String output)
{
// parse file contents
}
private void readStatus() {
//read status and parse()
}
private void produce()
{
try {
messageService.publish(TOPIC, content, PublishType.ASync);
} catch (MessageException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
There is already a link explaining the same with #Asynchronous tag (EJB 3.1 and NIO2: Monitoring the file system) . however I need to know what could be wrong in this approach.
Your watch method needs to run in an infinite loop. What's happening now is that after
try {
key = watcher.take();
}
you process the event and then the watch() method is finished. Try the effect of
for(;;) {
before the above lines, ending the for block after the validity check. Did you see the example at The Java Tutorials?

Categories