Liferay model listener - on after update handler loop - liferay

I have created custom model listener for DLFileEntry in Liferay 6.2 GA6. However, the onAfterUpdate method is called repeatedly even when no change has been made on DLFileEntry.
Let me describe the situation:
The file entry is changed through the content administration in Liferay
The onAfterUpdate method is triggered (this is OK)
The onAfterUpdate method is triggered again and again - even though there is no update made on this entry
I' ve dumped the stack trace when the (unexpected) update event happenes. It looks like the onAfterUpdate is triggered by incrementViewCounter(..)method, which is triggered by BufferedIncrementRunnable class
java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Thread.java:1365)
at eu.package.hook.model.listener.DLFileEntryModelListener.onAfterUpdate(DLFileEntryModelListener.java:63)
at eu.package.hook.model.listener.DLFileEntryModelListener.onAfterUpdate(DLFileEntryModelListener.java:32)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.liferay.portal.kernel.bean.ClassLoaderBeanHandler.invoke(ClassLoaderBeanHandler.java:67)
at com.sun.proxy.$Proxy865.onAfterUpdate(Unknown Source)
at com.liferay.portal.service.persistence.impl.BasePersistenceImpl.update(BasePersistenceImpl.java:340)
at com.liferay.portlet.documentlibrary.service.impl.DLFileEntryLocalServiceImpl.incrementViewCounter(DLFileEntryLocalServiceImpl.java:1450)
at sun.reflect.GeneratedMethodAccessor2034.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:115)
at com.liferay.portal.spring.transaction.DefaultTransactionExecutor.execute(DefaultTransactionExecutor.java:62)
at com.liferay.portal.spring.transaction.TransactionInterceptor.invoke(TransactionInterceptor.java:51)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.increment.BufferedIncreasableEntry.proceed(BufferedIncreasableEntry.java:48)
at com.liferay.portal.increment.BufferedIncrementRunnable.run(BufferedIncrementRunnable.java:65)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
I have read the documenantation about the bufferend increment in portal.properties docs page. It's not recommended to disable this feature.
I have also thought about checking if any relevant change has been made on DLFileEntry object in model listener method. I just wanted to check, if there is any configuration that could be made to bypass the onAfterUpdate method when it's triggered by incrementViewCounter method.
Any help is appreciated.
Update:
On after update method:
private void createMessage(DLFileEntry model, String create) {
JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
jsonObject.put("action", create);
jsonObject.put("id", model.getFileEntryId());
MessageBusUtil.sendMessage(SUPIN_MESSAGE_LISTENER_DESTINATION, jsonObject);
}
#Override
public void onAfterUpdate(DLFileEntry model) throws ModelListenerException {
if (LOG.isTraceEnabled()) {
URL[] urls = ((URLClassLoader) (Thread.currentThread().getContextClassLoader())).getURLs();
LOG.trace("Current thread classpath is: " + StringUtils.join(urls, ","));
}
LogMF.info(LOG, "File entry on update event - id {0}" , new Object[]{model.getFileEntryId()});
Thread.dumpStack();
createMessage(model, UPDATE);
}
Here is the message listener (message bus) which performs the on after update actions:
private void createOrUpdate(DLFileEntry model, String createOrUpdate) {
try {
initPermissionChecker(model);
LOG.info("Document " + model.getFileEntryId() + " " + createOrUpdate + "d in Liferay. Creating entry in Safe.");
long documentInSafe;
if (UPDATE.equalsIgnoreCase(createOrUpdate)) {
documentInSafe = (long) model.getExpandoBridge().getAttribute(EXPANDO_SAFE_DOCUMENT_ID);
if (documentInSafe > 0) {
safeClient.updateDocumentInSafe(model);
} else {
documentInSafe = safeClient.createDocumentInSafe(model);
}
} else {
documentInSafe = safeClient.createDocumentInSafe(model);
}
LOG.info("Document " + createOrUpdate +"d successfully with id " + documentInSafe);
saveSafeIDToExpando(model, documentInSafe);
} catch (Exception e) {
LOG.error("Unable to safe ID of document in Safe", e);
}
}
private void saveSafeIDToExpando(DLFileEntry model, long documentInSafe) throws SystemException {
try {
ExpandoTable table = ExpandoTableLocalServiceUtil.getDefaultTable(model.getCompanyId(), DLFileEntry.class.getName());
ExpandoColumn column = ExpandoColumnLocalServiceUtil.getColumn(table.getTableId(), EXPANDO_SAFE_DOCUMENT_ID);
ExpandoValueLocalServiceUtil.addValue(model.getCompanyId(), table.getTableId(), column.getColumnId(), model.getClassPK(), String.valueOf(documentInSafe));
LOG.info("ID of document in Safe updated in expando attribute");
} catch (PortalException e) {
LOG.error("Unable to save Safe document ID in expando." , e);
;
}
}
private void initPermissionChecker(DLFileEntry model) throws Exception {
User safeAdminUser = UserLocalServiceUtil.getUserByScreenName(model.getCompanyId(), SAFE_ADMIN_SCREEN_NAME);
PermissionChecker permissionChecher = PermissionCheckerFactoryUtil.create(safeAdminUser);
PermissionThreadLocal.setPermissionChecker(permissionChecher);
PrincipalThreadLocal.setName(safeAdminUser.getUserId());
CompanyThreadLocal.setCompanyId(model.getCompanyId());
LOG.info("Permission checker successfully initialized.");
}

I suggest this, but I am not sure if it resolves your case.
I've changed the body of your own method onAfterUpdate.
Using TransactionCommitCallbackRegistryUtil you can detach the model update request from the subsequent createMessage logic.
public void onAfterUpdate(DLFileEntry model) throws ModelListenerException {
TransactionCommitCallbackRegistryUtil.registerCallback(new Callable() {
#Override
public Void call() throws Exception {
createMessage(model, UPDATE);
}
}

Related

How to abort a Task in JavaFX?

Is it possible to abort a Task in JavaFX? My Task could run into situations where I want to cancel the rest of the operations within it.
I would need to return a value, somehow, so I can handle the cause of the abort in the JFX Application Thread.
Most of the related answers I've seen refer to handling an already-canceled Task, but now how to manually cancel it from within the Task itself.
The cancel() method seems to have no effect as both messages below are displayed:
public class LoadingTask<Void> extends Task {
#Override
protected Object call() throws Exception {
Connection connection;
// ** Connect to server ** //
updateMessage("Contacting server ...");
try {
connection = DataFiles.getConnection();
} catch (SQLException ex) {
updateMessage("ERROR: " + ex.getMessage());
ex.printStackTrace();
cancel();
return null;
}
// ** Check user access ** //
updateMessage("Verifying user access ...");
try {
String username = System.getProperty("user.name");
ResultSet resultSet = connection.createStatement().executeQuery(
SqlQueries.SELECT_USER.replace("%USERNAME%", username));
// If user doesn't exist, block access
if (!resultSet.next()) {
}
} catch (SQLException ex) {
}
return null;
}
}
And example would be greatly appreciated.
Why not just let the task go into a FAILED state if it fails? All you need (I also corrected the errors with the type of the task and return type of the call method) is
public class LoadingTask extends Task<Void> {
#Override
protected Void call() throws Exception {
Connection connection;
// ** Connect to server ** //
updateMessage("Contacting server ...");
connection = DataFiles.getConnection();
// ** Check user access ** //
updateMessage("Verifying user access ...");
String username = System.getProperty("user.name");
ResultSet resultSet = connection.createStatement().executeQuery(
SqlQueries.SELECT_USER.replace("%USERNAME%", username));
// I am not at all sure what this is supposed to do....
// If user doesn't exist, block access
if (!resultSet.next()) {
}
return null;
}
}
Now if an exception is thrown by DataFiles.getConnection(), the call method terminates immediately with an exception (the remained is not executed) and the task enters a FAILED state. If you need access to the exception in the case that something goes wrong, you can do:
LoadingTask loadingTask = new LoadingTask();
loadingTask.setOnFailed(e -> {
Throwable exc = loadingTask.getException();
// do whatever you need with exc, e.g. log it, inform user, etc
});
loadingTask.setOnSucceeded(e -> {
// whatever you need to do when the user logs in...
});
myExecutor.execute(loadingTask);

Socket EACCESS permission denied with Android Studio

I am trying to connect my android emulator to my host computer with socket connection.
I have a simple Java server running and lessening in the host on port 6789.
I have the following code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Declares streamText to refer to text area to show all messages
TextView streamText = ((TextView) findViewById(R.id.streamText));
streamText.setText("");
streamText.append("Attempting connection at " + serverIP + " : 6789 \n");
try {
connection = new Socket(InetAddress.getByName(serverIP), 6789); // WHAT IP to connect to host, not virtual device host
streamText.append("Connected to: " + connection.getInetAddress().getHostAddress());
}catch(IOException Exception){
streamText.append(Exception.toString());
Exception.printStackTrace();
}
}
And i am getting this error on logcat:
02-05 11:46:52.257 2663-2663/net.ruiruivo.myfirstapp.chatclientv1 E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: net.ruiruivo.myfirstapp.chatclientv1, PID: 2663
java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{net.ruiruivo.myfirstapp.chatclientv1/net.ruiruivo.myfirstapp.chatclientv1.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.view.Window.findViewById(int)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2209)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
at android.app.ActivityThread.access$800(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.view.Window.findViewById(int)' on a null object reference
at android.app.Activity.findViewById(Activity.java:2071)
at net.ruiruivo.myfirstapp.chatclientv1.MainActivity.<init>(MainActivity.java:33)
at java.lang.reflect.Constructor.newInstance(Native Method)
at java.lang.Class.newInstance(Class.java:1572)
at android.app.Instrumentation.newActivity(Instrumentation.java:1065)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2199)
          
And inside my textView window the Exception Says:
java.net.SocketException: socket failed: EACCES (Permission denied)
I have search this and other sites, the answered that appeared the closest to this was <permission android:name="android.permission.INTERNET"></permission> in my manifest but did not solved the problem.
Can anyone help?
Your problem is somewhere else.
1.) post your XML file because it seems that you run into a NPE because streamText is null
2.) You can not do network code in the main thread - this will cause a
android.os.NetworkOnMainThreadException
You have to implement a separate task for that, e.g.:
private class NetworkTask extends AsyncTask<Void, Void, Object>{...}
Update:
Here you go:
#Override
protected void onCreate(Bundle savedInstanceState) {
//your code
new NetworkTask().execute();
}
private class NetworkTask extends AsyncTask<Void, Void, Object>{
#Override
protected Object doInBackground(Void... v) {
try {
//do your network stuff here
return "";
}
catch (HttpException e) {
return e;
}
}
// onPostExecute displays the results of the AsyncTask.
#Override
protected void onPostExecute(Object result) {
if(result instanceof String){
//everything was fine
}
else{
if(((HttpException)result).getMessage()!=null){
//exception occured
}
}
}
}

javafx-2 applet doesn't update gui when called from javascript

I'm trying to invoke a method from javascript object which in turn calls a the following java method :
public void loadPicture(final String absolutePath) {
System.out.println("loadPicture " + absolutePath);
Image dbimage;
dbimage = new Image(absolutePath, 100.0d, 100.0d, false, false);
final ImageView dbImageView = new ImageView();
dbImageView.setImage(dbimage);
Platform.runLater(new Runnable() {
#Override
public void run() {
try {
System.out.println("hbox children : "+hbox.getChildren().size());
hbox.getChildren().add(dbImageView);
System.out.println("hbox children : "+hbox.getChildren().size());
//test
//logger.debug(" aggiunto "+absolutePath);
DropPictures.getPicturesNames().add(absolutePath);
} catch (Exception e) {
System.out.println("eccezione :" + e.getLocalizedMessage());
}
}
});
}
In javascript the method invocation is :
var a = document.getElementById(myDivId);
a.loadPicture();
I've traced the execution and the above method doesn't throw any exception,but it is run cause i see the output in java console, but the applet doesn't show the picture.
I've used Platform.runLater to update the GUI in the javafx thread, still no update is performed.

rewriting a series in JavaFX linechart

I have a JavaFX app that utilizes the lineChart chart. I can write a chart to the app, and clear it, but when I want to write a new series and have it displayed, I get an error,
java.lang.IllegalArgumentException: Children: duplicate children added:
I understand the meaning, but not how to fix (I am very new to Java, let alone to FX).
Here is the relevant code from my controller (minus some class declarations):
(method called by the 'submit' button in chart tab window)
#FXML
private void getEngDataPlot(ActionEvent event) {
//check time inputs
boolean start = FieldVerifier.isValidUtcString(startRange.getText());
boolean end = FieldVerifier.isValidUtcString(endRange.getText());
type = engData.getValue().toString();
// Highlight errors.
startRangeMsg.setTextFill(Color.web(start ? "#000000" : "#ff0000"));
endRangeMsg.setTextFill(Color.web(end ? "#000000" : "#ff0000"));
if (!start || !end ) {
return;
}
// Save the preferences.
Preferences prefs = Preferences.userRoot().node(this.getClass().getName());
prefs.put("startRange", startRange.getText());
prefs.put("endRange", endRange.getText());
prefs.put("engData", engData.getValue().toString());
StringBuilder queryString = new StringBuilder();
queryString.append(String.format("edit out",
startRange.getText(),
endRange.getText()));
queryString.append(type);
log(queryString.toString());
// Start the query task.
submitEngData.setDisable(true);
// remove the old series.
engChart.getData().clear();
engDataProgressBar.setDisable(false);
engDataProgressBar.setProgress(-1.0);
//ProgressMessage.setText("Working...");
Thread t = new Thread(new EngDataPlotTask(queryString.toString()));
t.setDaemon(true);
t.start();
}
(the task called by above method:)
public EngDataPlotTask(String query) {
this.query = query;
}
#Override
protected Void call() {
try {
URL url = new URL(query);
String inputLine = null;
BufferedReader in = new BufferedReader(
new InputStreamReader(url.openStream()));
// while ( in.readLine() != null){
inputLine = in.readLine(); //}
Gson gson = new GsonBuilder().create();
DataObject[] dbin = gson.fromJson(inputLine, DataObject[].class);
in.close();
for (DataObject doa : dbin) {
series.getData().add(new XYChart.Data(doa.danTime, doa.Fvalue));
}
xAxis.setLabel("Dan Time (msec)");
} catch (Exception ex) {
log(ex.getLocalizedMessage());
}
Platform.runLater(new Runnable() {
#Override
public void run() {
submitEngData.setDisable(false);
// do some pretty stuff
String typeName = typeNameToTitle.get(type);
series.setName(typeName);
// put this series on the chart
engChart.getData().add(series);
engDataProgressBar.setDisable(true);
engDataProgressBar.setProgress(1.0);
}
});
return null;
}
}
The chart draws a first time, clears, and then the exception occurs. Requested stack trace follows:
Exception in runnable
java.lang.IllegalArgumentException: Children: duplicate children added: parent = Group#8922394[styleClass=plot-content]
at javafx.scene.Parent$1.onProposedChange(Unknown Source)
at com.sun.javafx.collections.VetoableObservableList.add(Unknown Source)
at com.sun.javafx.collections.ObservableListWrapper.add(Unknown Source)
at javafx.scene.chart.LineChart.seriesAdded(Unknown Source)
at javafx.scene.chart.XYChart$2.onChanged(Unknown Source)
at com.sun.javafx.collections.ListListenerHelper$SingleChange.fireValueChangedEvent(Unknown Source)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(Unknown Source)
at com.sun.javafx.collections.ObservableListWrapper.callObservers(Unknown Source)
at com.sun.javafx.collections.ObservableListWrapper.add(Unknown Source)
at com.sun.javafx.collections.ObservableListWrapper.add(Unknown Source)
at edu.arizona.lpl.dan.DanQueryToolFX.QueryToolController$EngDataPlotTask$1.run(QueryToolController.java:231)
at com.sun.javafx.application.PlatformImpl$4.run(Unknown Source)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access$100(Unknown Source)
at com.sun.glass.ui.win.WinApplication$2$1.run(Unknown Source)
at java.lang.Thread.run(Thread.java:722)
Any ideas what I am doing wrong. I am a RANK NEWBIE, so please take that into account if you wish to reply. Thank you!
It took long time to find a workaround solution for this issue.
Please add below piece of code and test:
engChart.getData().retainAll();
engChart.getData().add(series);
My guess about the root cause according to your incomplete code is this line:
engChart.getData().add(series);
You should add series only once in initialize block for instance. But I think in your task thread, you are adding the already added same series again and having that mentioned exception. If your aim is to refresh the only series data, then just manipulate the series, getting it by engChart.getData().get(0); and delete that line in the code.
Once you add the series to the graph all you do is edit the series. Don't add it to the graph again.
The graph will follow whatever happens to the series i.e. just change the series data and the graph will automatically reflect the changes.

NoClassDefFoundError in j2me

I have build a jar file and trying to use it in j2me application. I have included the jar in the build path and imported the required classes as well. But when I run my j2me application I am getting NoClassDefFound Error in the line where I am trying to instantiate the class which is present in the jar.
I can instantiate the classes of the jar in the java project but not in j2me.
Below is the error log:
WARNING - MMA -
C:/Builds/jme-sdk/javacall-javame-sdk-305/implementation/share/jsr135_mmapi/ju_mmconfig.c
line 801: caps: optional settings missing: SuspendBehavior
java.lang.NoClassDefFoundError: com/canvasm/ida/gps/LocationUpdater
- com.test.ida.HelloIDA.(HelloIDA.java:11)
- java.lang.Class.newInstance(), bci=0
- com.sun.midp.main.CldcMIDletLoader.newInstance(), bci=46
- com.sun.midp.midlet.MIDletStateHandler.createMIDlet(), bci=66
- com.sun.midp.midlet.MIDletStateHandler.createAndRegisterMIDlet(), bci=17
- com.sun.midp.midlet.MIDletStateHandler.startSuite(), bci=27
- com.sun.midp.main.AbstractMIDletSuiteLoader.startSuite(), bci=52
- com.sun.midp.main.CldcMIDletSuiteLoader.startSuite(), bci=8
- com.sun.midp.main.AbstractMIDletSuiteLoader.runMIDletSuite(), bci=161
- com.sun.midp.main.AppIsolateMIDletSuiteLoader.main(), bci=26 javacall_lifecycle_state_changed() lifecycle: event is
JAVACALL_LIFECYCLE_MIDLET_SHUTDOWN status is JAVACALL_OK
TestApp(j2me app):
import com.test.gps.LocationUpdater;
public class Hello extends MIDlet {
public Hello() {
LocationUpdater loc = new LocationUpdater();
System.out.println("Loc updater object :"+loc.toString());
}
protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
// TODO Auto-generated method stub
}
protected void pauseApp() {
// TODO Auto-generated method stub
}
protected void startApp() throws MIDletStateChangeException {
}
}
JAR file main class:
public class LocationUpdater {
private boolean isUpdateSuccess = false;
public static void main(String[] args){
}
public boolean updateLocation(final String serverUrl, final String userMSISDN) throws LocationException{
AppConstants.url = serverUrl;
AppConstants.msisdn = userMSISDN;
LocationCanvas loc = new LocationCanvas();
isUpdateSuccess = loc.getLocation(serverUrl, userMSISDN);
return isUpdateSuccess;
}
}
LocationCanvas class:
public class LocationCanvas {
private Location location;
private LocationProvider locationProvider;
private Coordinates coordinates;
private Criteria criteria;
private Timer tm;
private double lat, lon;
private String posturl;
private boolean status,updateStatus;
public LocationCanvas() {
}
public boolean getLocation(String url, String msisdn) {
tm = new Timer();
criteria = new Criteria();
criteria.setHorizontalAccuracy(500);
try {
locationProvider = LocationProvider.getInstance(criteria);
if (locationProvider != null) {
tm.wait(4000);
try {
location = locationProvider.getLocation(2000);
} catch (Exception e) {
System.out.println(e.getMessage());
}
coordinates = (Coordinates)location.getQualifiedCoordinates();
if (coordinates != null) {
// Use coordinate information
lat = coordinates.getLatitude();
lon = coordinates.getLongitude();
System.out.println("Latitude :"+lat);
System.out.println("Longitude :"+lon);
}
posturl = url + "?IMEI=" + msisdn
+ "&positioningtype=" + "gps" + "&locationdata=" + lat
+ "," + lon;
}else{
//return false.. cos location provider is null
updateStatus = false;
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
return updateStatus;
}
error log:
Exception in thread "main" java.lang.NoClassDefFoundError:
javax/microedition/location/Coordinates
at com.canvasm.ida.gps.LocationUpdater.updateLocation(LocationUpdater.java:17)
at com.test.HelloTest.main(HelloTest.java:10)
Caused by: java.lang.ClassNotFoundException: javax.microedition.location.Coordinates
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
Any help would be appreciated.
It specifies that class file present at compile time is not found at run time.Check for build time and run time classpaths .
Finally able to solve the issue.
The problem was not in the code. It was due to the compilation issue.
First of all To solve the NoClassDefFoundError , I had to right click on the project and in the build path-> order and export -> check the jar that you have added.
Later while running I faced classFormatError 56.
The jar file which was created, was compiled using 1.6v.
And the j2me application was getting compiled with 1.3v.
I had to recompile my library project with 1.3v and create a jar out of it and used it in the j2me application.
Here is the link to guide: Build a Project from the Command Line - Java ME SDK

Resources