DFC - set a different filestore before save - java

I have a thread who's updating a map where all the available filestore are declared.
To be available, a filestore must be "online" and his size must be < 500MB. If the filestore reach the 500MB limit, he's turn "Read Only" and a new one is created. That part is OK.
The main thread is attributing a filestore, based on the available ones on the map, to every new document. BUT, I want to handle the case where document is linked to a filestore, let's say the filestore_01, and just between the attribution and the save() method, the filestore_01 is update by the second thread and turned "Read Only".
So, I put a catch and I do a test on the error code to launch a new compute storage to the document if that error occurs. The problem is even if the "new" filestore seems to be linked to my document, when I recall the save() method Documentum retry to save the document in the original filestore, the filestore_01.
I do everything via DFC, I can't use the MIGRATE_JOB as my document is new and not save for the moment.
Anyone has an idea ?
Here's the code :
//Save the document
try {
doc.save();
DfLogger.info(ListenerCreateDocumentOperation.class, "Created document with id '" + doc.getObjectId().getId() + "' and serie '" + serialId + "'", null, null);
} catch (DfException e) {
//if filestore is readonly
if(e.getErrorCode()==256) {
StorageService.getInstance().updateFileStoresArray(); //force to update the filestores map
try {
doc.computeStorageType(); //recompute the filestore where the doc will be save
doc.save(); //save the document
DfLogger.info(ListenerCreateDocumentOperation.class, "Created document with id '" + doc.getObjectId().getId() + "'", null, null);
} catch (Exception e2) {
e.printStackTrace();
throw new DfException("Error - Transaction aborted for XML : " + process.getXmlPath());
}
}
e.printStackTrace();
The first computeStorage() call is inside the setFile() DFC method, where I link a PDF to the document.
And the second thread where the filestore map is update (running approx. every 5 seconds) launch this function :
public void updateFileStoresArray() {
LOGGER.info(StorageService.class+" updating filestore array");
IDfSession s0 = null;
try {
FILESTORE_ARRAY.clear();
s0 = getDctmSessionManager().getSession(getRepository());
s0.addDynamicGroup("dm_superusers_dynamic");
getAllFileStores(s0);
for(int i=0; i<FILESTORE_ARRAY.size(); i++) {
try {
IDfFileStore currentFileStore = FILESTORE_ARRAY.get(i);
if(currentFileStore.getCurrentUse()/1000000 >= max_size) {
LOGGER.info("Filestore "+currentFileStore.getName()+" is full, he'll be set in readonly mode and a new dm_filestore will be create");
FILESTORE_ARRAY.remove(i);
IDfQuery batchList = new DfQuery();
batchList.setDQL("execute set_storage_state with store = '"+currentFileStore.getName()+"', readonly=true");
batchList.execute(s0, IDfQuery.DF_QUERY);
IDfFileStore filestore = createNewFilestore(s0);
FILESTORE_ARRAY.add(filestore);
}
} catch (Exception e) {
DfLogger.error(StorageService.class, "Error in execute()", null, e);
e.printStackTrace();
}
}
if(FILESTORE_ARRAY.size()==0) {
LOGGER.info("Recomputing");
createNewFilestore(s0);
}
}
catch (DfException e1) {
e1.printStackTrace();
}
finally {
if (s0 != null) {
getDctmSessionManager().release(s0);
}
}
}
And here's the computeStorage() method :
public void computeStorageType() throws DfException {
if(getStorageType()==null || getStorageType().equals("filestore_01") || Utils.isNullString(getStorageType())) {
getSession().addDynamicGroup("dm_superusers_dynamic");
String storageType=null;
StorageService.getInstance();
storageType = StorageService.computeStorage(getSession(), this);
if(getStorageType()==null || !getStorageType().equals(storageType)) {
setStorageType(storageType);
}
getSession().removeDynamicGroup("dm_superusers_dynamic");
}
}
public static String computeStorage(IDfSession s0, IGenericAspect vfkGenericDocumentAspect) throws DfException {
String result = null;
try {
if(FILESTORE_ARRAY.size()==0) {
getAllFileStores(s0);
}
if(FILESTORE_ARRAY.size()==0) {
createNewFilestore(s0);
getAllFileStores(s0);
}
IDfFileStore filestore = FILESTORE_ARRAY.get(currentFileStoreIndex);
if(filestore.getStatus()==2 || filestore.getStatus()==1) {
if(currentFileStoreIndex+1<FILESTORE_ARRAY.size() && FILESTORE_ARRAY.get(currentFileStoreIndex+1)!=null) {
currentFileStoreIndex=currentFileStoreIndex+1;
filestore = FILESTORE_ARRAY.get(currentFileStoreIndex);
}
}
result= filestore.getName();
LOGGER.info("Document "+vfkGenericDocumentAspect.getObjectId()+" will be store in filestore "+result);
if(currentFileStoreIndex+1<FILESTORE_ARRAY.size())
currentFileStoreIndex=currentFileStoreIndex+1;
else
currentFileStoreIndex=0;
} catch(Exception e) {
DfLogger.error(StorageService.class, "Error in execute()", null, e);
e.printStackTrace();
}
return result;
}

Related

Replacing Future<Integer> with Future<Void>

I am writing an application that searches for Java files in a given directory and its subdirectories and writes all the strings from those files in reverse order to a new folder. Each directory and file is handled in a separate thread.
At the moment my program works correctly, but I want to change its behavior.
Right now, the program overwrites the files correctly and outputs the number of overwritten files to the console at the end. I want my program to just overwrite the files and display the line "All files overwritten" at the end. But I don't quite understand how I can change my code and replace Future (I think that's my problem). Here is part of the code from the Main class:
ExecutorService pool = Executors.newCachedThreadPool();
ReverseWritter reverseWritter = new ReverseWritter(dirToSearch, dirToStorePath + "//" + dirToStoreName, pool);
Future<Integer> res = pool.submit(reverseWritter);
try {
System.out.println(res.get() + " files reversed");
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
pool.shutdown();
Here's the method that overwrites the file:
public boolean reverseWrite(File file) {
if (file.isFile() && file.toString().endsWith(".java")) {
String whereTo = dirToStorePathName + "\\" + file.getName().substring(0, file.getName().indexOf(".java")) + "Reversed" + ".java";
try ( Scanner myReader = new Scanner(file); FileWriter myWriter = new FileWriter(whereTo);) {
while (myReader.hasNextLine()) {
String data = myReader.nextLine();
myWriter.write(new StringBuffer(data).reverse().toString());
myWriter.write(System.getProperty("line.separator"));
}
} catch (FileNotFoundException e) {
System.out.println("An error occurred.");
e.printStackTrace();
return false;
} catch (IOException e) {
System.out.println("An error occurred.");
e.printStackTrace();
return false;
}
}
return true;
}
And this is the call method (my class implements the Callable interface):
#Override
public Integer call() {
int count = 0;
try {
File[] files = dirToSearch.listFiles();
ArrayList<Future<Integer>> result = new ArrayList<>();
for (File f : files) {
if (f.isDirectory()) {
ReverseWritter reverseWritter = new ReverseWritter(f, dirToStorePathName, pool);
Future<Integer> rez = pool.submit(reverseWritter);
result.add(rez);
} else if (reverseWrite(f)) {
count++;
}
for (Future<Integer> rez : result) {
count += rez.get();
}
}
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
return count;
}
You just need to change the class to implement Callable<Void> and remove the operations which do the counting. Change the return type of call from Integer to Void.
public class ReverseWriterCallable implements Callable<Void> {
#Override
public Void call() throws Exception {
//do stuff
//don't do the counting operations
//when return type is Void you can only return null
return null;
}
}
Or implement Runnable and submit it to the executor service.
public class ReverseWriterRunnable implements Runnable {
#Override
public void run() {
//do stuff
//don't do the counting operations
}
}
Then just don't care about the result of the Future:
try {
res.get();
System.out.println("All files reversed");
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
pool.shutdown();

How can loop continue before method is finished?

I have multiple threads(runnables) in my program. On of theme is handling RS232 communication.
My problem is that code inside the loop is not executed in the order that is written:
while(!serialData.dataToSend.isEmpty())
{
try {
SerialMsgToSend msgObject = serialData.dataToSend.remove();
if(msgObject.type == msgObject.HOLDING_REGISTER)
{
Thread.sleep(COMMAND_WAIT_TIME);
Toolkit.getDefaultToolkit().beep();
modBusManager.singleRegisterWriteToMultipleRegisters(msgObject.unit, msgObject.startRegisterAdress, msgObject.data);
}
else if(msgObject.type == msgObject.COIL)
{
Thread.sleep(COMMAND_WAIT_TIME);
Toolkit.getDefaultToolkit().beep();
modBusManager.writeToCoil(msgObject.unit, msgObject.startRegisterAdress, msgObject.data[0] == 1);
}
Thread.sleep(5000);
readUnitsData(msgObject.unit);
Thread.sleep(5000);
if(msgObject.RESPONSE > 0)
{
serialData.listeners[msgObject.unit - 1].sendResponseToServer(msgObject.RESPONSE);
}
} catch (Exception ex) {
log.error("Exception on sending data: " + ex.toString());
}
}
First I write to ModBus register with calling:
modBusManager.singleRegisterWriteToMultipleRegisters(msgObject.unit, msgObject.startRegisterAdress, msgObject.data);
After that I want to wait 5 seconds that registers are updated, then read them and send information to server.
I read the data with calling method:
readUnitsData(msgObject.unit);
And then I am using listener to tell another thread to send data to server:
serialData.listeners[msgObject.unit - 1].sendResponseToServer(msgObject.RESPONSE);
My problem is that data is sent to server before it gets read/updated so I send old data. I am used that code is executed in the order that is written. Am I using threads in a wrong way or what could be the problem?
Here is method which I call to read data:
private void readUnitsData(int unitID)
{
if(mtxData.climatList[unitID] != null)
{
try
{
log.info("Serial reading data for: " + unitID);
int[] coils = modBusManager.readCoils(unitID + 1,0,87);
String[] holding = modBusManager.readHoldingRegisters(unitID + 1,0,64); //(int slaveAdress, int registerAdress, int registerQuntaity)
if(coils != null && holding != null)
{
System.out.println("send to listner: " + unitID);
serialData.listeners[unitID].newHoldingAndCoilData(holding, coils);
}
} catch (Exception ex)
{
log.error("Exception on run: " + ex.toString());
}
}
}
And method inside other runnable, which is connected to listener:
#Override
public void sendResponseToServer(int responseType)
{
try
{
log.info("listener for sendStatusToServer called: " + responseType);
Thread.sleep(15000);
switch(responseType)
{
case 1:
communicationManager.sendStatus();
break;
case 2:
communicationManager.sendSettings();
break;
}
}catch(Exception ex)
{
log.error("Exception on sendResponseToServer: " + ex);
}
}
I did like #Markus Mitterauer proposed and took apart the code. I found that that it was problem with one of the unitID's which was wrong. Because of that I didn't get any values when reading registers and listener wasn't triggered correctly.

How can I catch a runtime exception from a EJB?

I have a very curious situation.
I'm trying to execute EJB's method and returns the result with JAX-RS
public Service readSingle(...) {
try {
service.query(...);
} catch (final NoResultException nre) {
throw new NotFoundException(...);
} catch (final NonUniqueResultException nure) {
throw new BadRequstException(...);
}
}
The query method requires some values and a BiFuction and a Function.
The actual call looks like this.
try {
return serviceService.<Service>query(
id,
ofNullable(matrixParameters.getFirst("onid"))
.map(Integer::parseInt).orElse(null),
ofNullable(matrixParameters.getFirst("tsid"))
.map(Integer::parseInt).orElse(null),
ofNullable(matrixParameters.getFirst("sid"))
.map(Integer::parseInt).orElse(null),
ofNullable(matrixParameters.getFirst("number"))
.map(Integer::parseInt).orElse(null),
ofNullable(matrixParameters.getFirst("programId"))
.orElse(null),
operatorId,
(builder, root) -> emptyList(),
TypedQuery::getSingleResult);
} catch (final NoResultException nre) {
throw new NotFoundException(
"no entity idnetified by " + serviceIdSegment.getPath()
+ " with " + matrixParameters.toString());
} catch (final NonUniqueResultException nure) {
throw new BadRequestException("multiple entities identified");
}
Ok I passed TypedQuery::getSingleResult and I expect NonUniqueResultException should be caught when it has to be thrown.
But Payara keep responding with 500 and the log shows that the NonUniqueResultException has never caught by the code.
I disabled my ExceptionMappers the the results are same.
Ok. I figured it out. I had to do this.
try {
// execute EJB
} catch (final EJBTransactionRolledbackException ejbtre) {
Exception leaf = ejbtre;
try {
for (Exception c;
(c = ((EJBException) leaf).getCausedByException()) != null;
leaf = c);
} catch (final ClassCastException cce) {
}
logger.severe("causedByException: " + leaf);
if (leaf instanceof NoResultException) {
throw new NotFoundException(
"no entity idnetified by " + serviceIdSegment.getPath()
+ " with " + matrixParameters.toString());
} else if (leaf instanceof NonUniqueResultException) {
throw new BadRequestException(
"multiple entities identified by "
+ serviceIdSegment.getPath()
+ " with " + matrixParameters.toString());
}
throw new InternalServerErrorException(ejbtre);
}
This is far nasty beyond I've expected. The EJB's method design is not good.
Is there any way to do this more simply?
Let me introduce one of my utility class I used to justify myself.
public final class EJBExceptions {
private static final Logger logger
= getLogger(EJBExceptions.class.getName());
public static Stream<Exception> causedByExceptions(EJBException ejbe) {
final Stream.Builder<Exception> builder = Stream.builder();
while (ejbe != null) {
final Exception causedByException = ejbe.getCausedByException();
if (causedByException != null) {
builder.add(causedByException);
} else {
break;
}
if (causedByException instanceof EJBException) {
ejbe = (EJBException) causedByException;
} else {
break;
}
}
return builder.build();
}
public static Optional<Exception> lastCausedByException(
final EJBException ejbe) {
return causedByExceptions(ejbe).reduce((first, second) -> second);
}
private EJBExceptions() {
super();
}
}

LRUCache returns size 0 until all images have been cached

I'm using LRUCache to cache images that I retrieve from a server. I'm requesting them from a RecyclerView but till all the images are cached the LRUCache instance returns size 0.
Here's the Code
public void buildCache() {
for (Feed feed : mFeeds) {
List<User> users = new ArrayList<>();
users.add(feed.getAuthor());
try {
if (feed.getPostType() == Feed.PostType.Collab) {
for (User receiver : feed.getUsers())
users.add(receiver);
getImages(users);
Log.d(LOG_TAG, "Cache size: " + imagesLruCache.size());
} else if (feed.getPostType() == Feed.PostType.Search){
String receiverUsername = feed.getReceiver().getUsername();
getImages(users);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
mCacheBuildingInterface.OnCacheBuilt();
dataSetChanged();
}
What should I do to fix the problem ?
Thx to everyone

login in flex and java using multithreading

I have problem with my login application in java and flex. we use fingerprint login. the system waits for 60 seconds for any fingerprint input from the user. After that it automatically goes out of the page. The user also has text password option on that page. When user clicks on that option, control goes to some other page. But the problem is whenver user click on text password option, he is redirected but the thread of 60 seconds keep running. Can any one help me how to stop that thread. Here is my code. I am using blocking queue concept to get out of the input screen by inputting some dummy value of one bit.
private void interruptCaptureProcess() {
System.out.println("Interrupting Capture Process.");
ExactScheduledRunnable fingerScanInterruptThread = new ExactScheduledRunnable()
{
public void run()
{
try
{
if (capture != null)
{
DPFPSampleFactoryImpl test = new DPFPSampleFactoryImpl();
samples.put(test.createSample(new byte[1]));
capture.stopCapture();
}
}
catch (Exception e)
{
LOGGER.error("interruptCaptureProcess", e);
e.printStackTrace();
}
}
};
timeOutScheduler.schedule(fingerScanInterruptThread, getTimeOutValue(), TimeUnit.SECONDS);
}
/**
* Scans and Verifies the user finger print by matching it with the previous registered template for the user.
*
* #param userVO is the user value object which has to be verified.
* #return the acknowledgment string according to result for operation performed.
* #throws UserServiceException when there is an error in case of getting user record.
*/
public String verifyUserFingerPrint(Long userId) throws LoginServiceException {
System.out.println("Performing fingerprint verification...\n");
interruptCaptureProcess();
UserVO userVO = null;
try {
userVO = new UserService().findUserById(userId, true);
if (userVO != null) {
stopCaptureProcess();
DPFPSample sample = getSample(selectReader(), "Scan your finger\n");
timeOutScheduler.shutdownNow();
if (sample.serialize().length == 1) {
System.out.println("Coming in code");
return null;
} else if (sample.serialize().length == 2) {
System.out.println("Capturing Process has been Timed-Out");
return TIMEOUT;
}
if (sample == null)
throw new UserServiceException("Error in scanning finger");
DPFPFeatureExtraction featureExtractor = DPFPGlobal.getFeatureExtractionFactory()
.createFeatureExtraction();
DPFPFeatureSet featureSet = featureExtractor.createFeatureSet(sample,
DPFPDataPurpose.DATA_PURPOSE_VERIFICATION);
DPFPVerification matcher = DPFPGlobal.getVerificationFactory().createVerification();
matcher.setFARRequested(DPFPVerification.MEDIUM_SECURITY_FAR);
byte[] tempByte = userVO.getFingerPrint();
DPFPTemplateFactory facotory = new DPFPTemplateFactoryImpl();
for (DPFPFingerIndex finger : DPFPFingerIndex.values()) {
DPFPTemplate template = facotory.createTemplate(tempByte);
if (template != null) {
DPFPVerificationResult result = matcher.verify(featureSet, template);
// Fix of enh#1029
Map<ScriptRxConfigType, Map<ScriptRxConfigName, String>> scriptRxConfigMap = ScriptRxConfigMapSingleton
.getInstance().getScriptRxConfigMap();
Map<ScriptRxConfigName, String> fingerPrintPropertiesMap = scriptRxConfigMap
.get(ScriptRxConfigType.FINGERPRINT);
String fingerPrintDemoMode = fingerPrintPropertiesMap.get(ScriptRxConfigName.DEMOMODE);
if (fingerPrintDemoMode != null && fingerPrintDemoMode.equalsIgnoreCase("DemoEnabled")) {
return "LOGS_MSG_101";
}
// End of fix of enh#1029
if (result.isVerified()) {
System.out.println("Matching finger: %s, FAR achieved: %g.\n" + fingerName(finger)
+ (double) result.getFalseAcceptRate() / DPFPVerification.PROBABILITY_ONE);
return "LOGS_MSG_101";
}
}
}
}
} catch (IndexOutOfBoundsException iob) {
LOGGER.error("verifyUserFingerPrint", iob);
throw new LoginServiceException("LOGS_ERR_101", iob);
} catch (Exception exp) {
LOGGER.error("verifyUserFingerPrint", exp);
System.out.println("Failed to perform verification.");
throw new LoginServiceException("LOGS_ERR_105", exp);
} catch (Throwable th) {
LOGGER.error("verifyUserFingerPrint", th);
throw new LoginServiceException("LOGS_ERR_106", th.getMessage(), th);
}
System.out.println("No matching fingers found for \"%s\".\n" + userVO.getFirstName().toUpperCase());
throw new LoginServiceException("LOGS_ERR_107", null);
}
/* finger scanning process
*/
private void stopCaptureProcess() {
ExactScheduledRunnable fingerScanInterruptThread = new ExactScheduledRunnable() {
public void run() {
try {
DPFPSampleFactoryImpl test = new DPFPSampleFactoryImpl();
samples.put(test.createSample(new byte[2]));
capture.stopCapture();
} catch (Throwable ex) {
ex.printStackTrace();
}
}
};
timeOutScheduler.schedule(fingerScanInterruptThread, getTimeOutValue(), TimeUnit.SECONDS);
}
/**
* API will get the value for the finger scanner time out configuration(Default will be 60 seconds)
*/
private long getTimeOutValue() {
long waitTime = 60;
String configValue = ScriptRxSingleton.getInstance().getConfigurationValue(ConfigType.Security,
ConfigName.FingerprintTimeout);
try {
waitTime = Long.valueOf(configValue);
} catch (NumberFormatException e) {
LOGGER.debug("Configuration value is not a number for FingerTimeOut", e);
}
return waitTime;
}
Stopping blocking tasks in Java is a complicated topic, and requires cooperation between the blocking code and the code that wants to unblock it. The most common way in Java is to interrupt the thread that is blocking, which works if the code that is blocking and the code around it understands interruption. If that's not the case you're out of luck. Here's an answer that explains one way to interrupt a thread that is blocking in an Executor: https://stackoverflow.com/a/9281038/1109

Categories

Resources