Forums de discussion

big application

Pa Blo, modifié il y a 9 années.

big application

New Member Publications: 14 Date d'inscription: 09/03/14 Publications récentes
Hi,

I have a legacy Liferay application (Liferay 6.1 with Tomcat 7) for our enterprise portal with dozens of portlets and hooks. The app is growing day by day and I, as the main developer, have no other choice than to deploy the same core jars in every portlet/hook, that is, breaking the rule saying "don't repeat code". After searching on this and other forums I have found no other solution than to put jars in <TOMCAT>/lib/ext and import them using the portal class loader and all of this but... I think that is not a good idea (and everybody says that!).

Now I'm facing with another problem. The application consumes web services and we have to duplicate the WS client code (one more time) in all the portlets and hooks that are using it. Also, the application, as a web application, has many threads and every one of them needs to create the endpoint, to configure the HTTP/SSL connection and else, and that takes 1 or 2 seconds so... I don't like how it is working and I'm looking for a good solution.

I'm not asking for a concrete solution to my problem but I'm asking that: What's the "common" architecture in a big Liferay application? Do I need to replicate the common code in the portlets/hooks, or there is another solution? How can I implement, i.e., a thread pool to call the webservices?

That's the story. If you have any idea or something I will be grateful. And... sorry about my bad english, I know about it emoticon

Pablo.
thumbnail
David H Nebinger, modifié il y a 9 années.

RE: big application

Liferay Legend Publications: 14916 Date d'inscription: 02/09/06 Publications récentes
Most developers won't think of this, but Service Builder can be used to solve both of these issues...

By using "fake entities" as defined in this post: https://www.liferay.com/community/forums/-/message_boards/message/12095602, you can create non-DB entities.

These entities can be containers for values from web service calls, business logic, etc.

Basically any time you have multiple plugins using the same logic, you can use an SB fake entity to centralize the code (i.e. only building/maintaining it once) yet reuse it in multiple plugins. All they need is the lightweight service jar (either shared in each plugin or placed in the global lib dir).

So your web service requirements is a great example. Me, I'd generate your WS client code in a service builder plugin. Define "fake" entities which represent bridge objects between the portlets and the WS client objects. The other plugins just need the service jar, but none of the WS client stuff. Meanwhile in your XxxLocalServiceImpl guy, I'd use an object pool of WS connections. The pool can grow/shrink to deal w/ servicing requests but, since it's a pool, you can eliminate much of the startup/shutdown code for individual calls.

This is not a solution that works for, say, separate servlets, but for your portlet code this would work great. Even better, with Liferay 7 and the OSGi framework, sharing code like this is going to be so much easier, but that's still probably a year off before you can leverage that...
Pa Blo, modifié il y a 9 années.

RE: big application

New Member Publications: 14 Date d'inscription: 09/03/14 Publications récentes
Hi David,

First of all, many thanks for your message. I'm glad to talk/write directly with you (I've read many threads in which you've written, some of them about how to share classes or functionality).

I had tried to use the SB to put some shared entities as fake entities, but to say the truth, I haven't achieved the results I've been looking for. Although with this approx I can share classes, I need to go further: Suppose I write the connection pool for WS as a set of classes in a fake entity. I imagine I would have a facade class/interface to invoke operations at some server, but wait... where would be the class, I mean, in what ClassLoader? I think the only way would be to put the jar in lib/ext directory, but I'm not sure about the behaviour of Liferay having a jar using the SB (and their libraries) in that ClassLoader (the ROOT ClassLoader). So I think that using fake entities will be accurate only if you deploy the war as a portlet/hook (although I'm not sure to be right in this).

Another example: I need to put a layer over a service (suppose a set of several tables and an interface to act as a Facade for the functionality of the set) and to share this piece of software. The only way I found to do that is to replicate the Facade layer with the services created all over the portlets and hooks. In fact, when I use a service from two or more portlets/hooks I have to include the jar for that service in every portlet and hook.

I didn't know what you said about Liferay 7 and OSGi, I think that this will be the most accurate solution in order to implement big applications using Liferay. Until now, I'm using a two layer architecture: I'm splitting the software in two parts: One for those pieces using some Liferay libraries, that is portlets or hooks, and another for those which doesn't, that is simple jars. While the first part needs to be duplicated over every portlet/hook, the second can be in lib/ext directory.

I'm still investigating the best approach to a well-designed architecture for big applications with Liferay but I believe I will have to wait for that OSGi Liferay version. It will be the answer to all of this problems. Anyway, I refuse to believe that Liferay can not deal with big applications!

Best regards.
Pablo.
thumbnail
Miroslav Ligas, modifié il y a 9 années.

RE: big application

Regular Member Publications: 152 Date d'inscription: 29/07/14 Publications récentes
The principle, which is used here, is the same as Liferay uses to expose it's services. You need to place the interface into the shared Class Loader and not into the plugins itself. The implementation stays hidden in the web application context and would be just injected into the interface. You have zero code duplication and there is no (business) logic in the shared class loader.
It can be easily achieved with service builder as mentioned by David. You just need to push the service jar into the higher class loader. But you are not limited to the SB. The same approach can by used also without SB. For example you can create a bean (class) locator in shared Class Loader and register classes into it.
Pa Blo, modifié il y a 9 années.

RE: big application

New Member Publications: 14 Date d'inscription: 09/03/14 Publications récentes
Miroslav Ligas:
The principle, which is used here, is the same as Liferay uses to expose it's services. You need to place the interface into the shared Class Loader and not into the plugins itself. The implementation stays hidden in the web application context and would be just injected into the interface. You have zero code duplication and there is no (business) logic in the shared class loader.
It can be easily achieved with service builder as mentioned by David. You just need to push the service jar into the higher class loader. But you are not limited to the SB. The same approach can by used also without SB. For example you can create a bean (class) locator in shared Class Loader and register classes into it.



Hello Miroslav, Thank you very much for your help.

Just two questions: When you said "there is no (business) logic in the shared class loader", do you mean that there is no logic belonging to the plugin that uses it? That is, the shared class loader contains business logic being, in effect, bussines logic related to ALL plugins (since it is business logic related to my application), but not logic related to ONE plugin. Is that?
And second: Could you share a link about creating a bean locator and registering classes into it? I suppose that I'll need to obtain references from it to some of my shared classes from my plugins, but I don't know how. Also, I suppose too that I will need to start/stop some things (like to start a thread pool) when the server is started and stopped, but I'm not sure about how to do this.

BR.
Pablo.
thumbnail
David H Nebinger, modifié il y a 9 années.

RE: big application

Liferay Legend Publications: 14916 Date d'inscription: 02/09/06 Publications récentes
Liferay actually works very well for large applications, especially since you are really encouraged to decompose and modularize larger apps into smaller portlets.

For your SB implementation, you don't want to consider passing around objects so much (i.e. do not think about returning a connection object from a connection pool), consider only passing data. Basically all of the consumers of the data (your other plugins) don't care if the data is coming from a web service, a flat file, or a database record. They provide some key data and want data in return. It is that aspect where you draw the line and then implement the line using SB.

Your implementation of course is free to invoke the web service, access a database, read and parse a flat file, etc. In this particular example, your goal should be to hide the fact that it comes from a web service call at all, at least from the consumer perspective. Your implementation within the service provider will worry about the web service call, whether to use the connection pool or not, etc.

Yes, as with any SB implementation you can either share the service jar or push it to the global lib directory (tomcat's lib/ext directory). The important part here is that the service jar is lightweight - it doesn't contain any business logic, it just defines the API used to access the business logic. If you distribute with every dependent plugin, you don't have the global loader issue but if you have a large number of dependent plugins the deployment of an update a pain (by updating all dependent plugins). The global path would seem to be better for this situation, however you cannot deploy an update while the server is running (the jar file is locked and cannot be changed).

The service jar, however, is the only one that has to be shared. All other plugins can leverage the SB-based API to access the code.
Pa Blo, modifié il y a 9 années.

RE: big application

New Member Publications: 14 Date d'inscription: 09/03/14 Publications récentes
David H Nebinger:
Liferay actually works very well for large applications, especially since you are really encouraged to decompose and modularize larger apps into smaller portlets.

For your SB implementation, you don't want to consider passing around objects so much (i.e. do not think about returning a connection object from a connection pool), consider only passing data. Basically all of the consumers of the data (your other plugins) don't care if the data is coming from a web service, a flat file, or a database record. They provide some key data and want data in return. It is that aspect where you draw the line and then implement the line using SB.

Your implementation of course is free to invoke the web service, access a database, read and parse a flat file, etc. In this particular example, your goal should be to hide the fact that it comes from a web service call at all, at least from the consumer perspective. Your implementation within the service provider will worry about the web service call, whether to use the connection pool or not, etc.

Yes, as with any SB implementation you can either share the service jar or push it to the global lib directory (tomcat's lib/ext directory). The important part here is that the service jar is lightweight - it doesn't contain any business logic, it just defines the API used to access the business logic. If you distribute with every dependent plugin, you don't have the global loader issue but if you have a large number of dependent plugins the deployment of an update a pain (by updating all dependent plugins). The global path would seem to be better for this situation, however you cannot deploy an update while the server is running (the jar file is locked and cannot be changed).

The service jar, however, is the only one that has to be shared. All other plugins can leverage the SB-based API to access the code.



Hello David,

From your post I understand that I don't have to obtain a pool from my connection pool but I have to use the connection pool directly, as if it that pool doesn't exist. I mean that, instead of obtaining a connection, using it, and then returning it to the pool, what I should do is to call a method that encapsulates this behaviour, having this method in the shared classes pool. Inside this method I will obtain the connection, work and the return it to the pool Is that?

Many thanks.
Pablo.
thumbnail
David H Nebinger, modifié il y a 9 années.

RE: big application

Liferay Legend Publications: 14916 Date d'inscription: 02/09/06 Publications récentes
Sure. Say for example you're invoking a weather web service. Define an entity that encapsulates the results of the web service call, in this case some sort of Weather data.

The consumers, the ones using the Weather entity, do not know anything about the web service. Instead, they call some method that you implement, WeatherLocalServiceUtil.getWeather(zipcode);.

Within the WeatherLocalServiceImpl class you create the getWeather(String zipcode) method. In the method, this is where you worry about getting an object from the pool, invoking the web service, marshaling the response data into the Weather entity and returning it.

This encapsulates the invocation of the web service behind an SB facade so it's available to all of the service consumers, but instead of copying the web service code to all consumers, they just have the service interface. You have one point for your code, one point of maintenance, yet can expose the interface to all users.
Pa Blo, modifié il y a 9 années.

RE: big application

New Member Publications: 14 Date d'inscription: 09/03/14 Publications récentes
Ok David, understood. That's the path I started this morning!

Once theoretical questions are solved now I'm with the practical ones but it seems they will be easy to solve: I have created the portlet for the fake entities and added (I'm using eclipse) the jars with my thread queue, WS client and other stuff to the build path. I will deploy the service as a unique jar (as it is generated with ant build-services) to the lib/ext directory, and also I will deploy the jars with the libraries to that directory. This will ensure compilation in eclipse and execution in Liferay, I suppose.
With this I will have an entry point in the XXX-service.jar, that calls to the libraries in my other jars, that calls to the service methods in the XXX-service.jar.

Thank you very much, I will expose here my findings about this.

Best Regards.
Pablo.
Pa Blo, modifié il y a 9 années.

RE: big application

New Member Publications: 14 Date d'inscription: 09/03/14 Publications récentes
Hello again

I'm modifying the old application following your directions. Now I'm facing with a new problem: I have developed an entry point in a fake entity, and I'm planning to deploy the jar for this service in lib/ext. With that, the portlets/hooks which this software layer will use will find (I hope) the classes in the global liferay class loader. The thing is Eclipse? I mean: I need to add to the portlet/hook eclipse build path the XXX-portlet-service.jar in order to avoid compilation errors, so when I deploy this portlet/hook, the war will include that jar. Hence, the jar will be in two places: in the war and in the lib/ext, so my question is: Is there any standard procedure to exclude this jar from being included in the resulting war (Maybe I'm blundering or something)? Or, on the contrary, I have to manually delete the jar from the war?

Many thanks in advance.
BR.
Pablo.
Pa Blo, modifié il y a 9 années.

RE: big application

New Member Publications: 14 Date d'inscription: 09/03/14 Publications récentes
Hi all,

I will reply to myself. I have been crawling the web and with David's Teachings (note the uppercase ;) and some other findings (thanks too Miroslav):

1) Use SB to create entry points to your application shared software layer. Create there methods to solve the common functionalities to your application. If you need some classes, create them in a normal Java Project (I'm using eclipse). Remember that those clases can not call to the Liferay runtime (they would be low-level utility classes and hence would be called from your SB classes or from your portlets and/or hooks).
2) Deploy the XXXX-portlet-service.jar and your other jars to the lib/ext directory of your development environment (having the Liferay runtime properly configured (eclipse)). Eclipse will detect the new jars. They will appear in <plugin-name>/Java Resources/Libraries/Liferay vXXX (i'm using 6.1 CE). With this you won't need to include the services jars and/or the libraries jars in every portlet or hook you create.
3) On integration/production environment, deploy the jars again to lib/ext.
4) Create hooks and/or portlets in a normal way, using the SB classes and/or the utility classes you deployed to the lib/ext directory. They will be available without including them in the libs directory, since they are there!
5) Enjoy

Remember the title of this thread (big/large applications)! So, follow this instructions only for software pieces that will be used by more than one portlet or hook, having in mind that a Liferay restart will be mandatory when that jars change.

BR.
Pablo.
thumbnail
Jack Bakker, modifié il y a 9 années.

RE: big application

Liferay Master Publications: 978 Date d'inscription: 03/01/10 Publications récentes
For bigger bizclient solutions, when using move to global approach in development while suffering the restart of container with every service change is a pain in the arsenal - which might lead to social dementia while waiting. But then also the distributing service jar to many mutliple service consumer plugins has it's own overhead. Pa Blo has begun to define a threshold of which to choose according to the O laugh "it depends" principle.

Generally, I am guessing that if you are developing 'over' liferay and are thinking marketplace for more general distribution, then deploy to global is to be avoided.

I've gotta say that I think Valamis is one of the coolest and most exemplary to hit the Liferay scene of late. But that said, Scala hurts my head even more than Vaadin.. so I need for myself (and for those who might be available) some mere mortal and affordable approaches while free educational systems catch up to that which has evolved in Finland over the last, what, ~100 years ?

transactions need to be , well, they need to be

has anyone checked in detail PostgreSQL 9.4 support for nosql with json in context of Liferay ?
thumbnail
David H Nebinger, modifié il y a 9 années.

RE: big application

Liferay Legend Publications: 14916 Date d'inscription: 02/09/06 Publications récentes
Jack Bakker:
For bigger bizclient solutions, when using move to global approach in development while suffering the restart of container with every service change is a pain in the arsenal - which might lead to social dementia while waiting. But then also the distributing service jar to many mutliple service consumer plugins has it's own overhead. Pa Blo has begun to define a threshold of which to choose according to the O laugh "it depends" principle.


It is certainly a pain in the buttocks. When taking this path, you want to focus on completing the plugin providing the service as soon as possible and be as complete in it's specification that you possibly can. The goal is to reduce the number of deployments to the barest of minimums.
thumbnail
David H Nebinger, modifié il y a 9 années.

RE: big application

Liferay Legend Publications: 14916 Date d'inscription: 02/09/06 Publications récentes
If eclipse is configured for the bundle correctly, it may find the jar in tomcat's lib/ext folder.

Lately I've been doing maven plugins, and for those any time I have a global jar I just use the "provided" scope for the dependency; maven will include it for compiling, but it will not include it in the constructed war.

The SDK should do exactly the same thing.

Eclipse should also, I'm not sure why it's not working for you.
Pa Blo, modifié il y a 9 années.

RE: big application

New Member Publications: 14 Date d'inscription: 09/03/14 Publications récentes
Hello again,

No, my eclipse environment is working fine. Setting the required options for "Execution Environment" and "Liferay Plugin SDKs" at Window->Preferences->Liferay, all is working ok. I've created some ant scripts (I will try to do the same with maven too) in order to compile, create jars and copy them to my lib/ext directory in that Liferay installation, and now it's a one-click task. I'm creating the services as entry points using fake entities and with this architecture I've created a connection pool for the WS and several software layers to deal with some sets of tables, the ones logically related.

I suppose that to use completely independent portlets is only valid for tiny/small applications. Once you have a little more complicated functionality I imagine that this approx could take you to a hell of duplicated jars. As I said when started this thread, I have inherited a Liferay application with around 100 portlets/hooks: each of this plugins (most of them) have its own copy of a huge jar (the typical utils.jar shared among all the application), and each plugin that needs a XXX.portlet-service.jar to access one table has its own copy of it in WEB-INF/lib. Yeah, that's my sad life ;) I'm a newbie with Liferay, although I use Java since the first 1.1 version, so I was wondering why my "old" architectural knowledges were failing with Liferay. Now I know why, and I know what I have to do to refactor this "thing" and convert it in a five star app. It's my work!

Thank you again.
Pablo.
Pa Blo, modifié il y a 9 années.

RE: big application

New Member Publications: 14 Date d'inscription: 09/03/14 Publications récentes
Hi all,

I'm updating this in order to explain my new findings:

1) Serializable classes. If I have a fake entity that obtains, say, a POJO class (not Serializable) as a result and that fake entity tries to return this class to a plugin, it works normally. But if I have a fake entity that queries another fake entity that obtains the POJO class, then that POJO class MUST implement Serializable if I need this POJO class in a plugin. That is:

data source->fake entity->fake entity->plugin

then classes being returned from data source to plugin must be Serializable. My fake entities are local, (i'm using remote=false, local = true). Anybody knows what's happening with this?

2) When an Exception is thrown from a fake entity, usually the exception is hard to discover/locate. This is because the clp class catches only the exceptions specified in the method signature. If you don't specify the NotSerializableException in the method in the fake entity, then when this method throws an unchecked exception you will see an exception with something like "NotSerializableException is not a valid exception", but the stack trace of the NotSerializableException (or whatever other exception) will be lost. The reason is how SB generates the clp class: it only checks for declared exceptions (in the method signature) and if the exception is not found there then it throws a RuntimeException using:

throw new RuntimeException(t.getClass().getName() +" is not a valid exception")

I believe that the RuntimeException throw should contain the t exception too. I mean something like throw new RuntimeException( "blabla" , t ); I will look for the way to suggest this change for next Liferay SB versions.

3) Using fake entities implies that you will run ant build-service many times during the development. I've found that, sometimes, SB doesn't update the generated classes. When I change a private method in a fake entity the SB doesn't "detect" the change. I'm still investigating this, but I found that either I run an ant clean, or I change a public method in order to force SB to regenerate the classes. Somebody has some suggestion about this?

BR.
Pablo.
thumbnail
David H Nebinger, modifié il y a 9 années.

RE: big application

Liferay Legend Publications: 14916 Date d'inscription: 02/09/06 Publications récentes
Pa Blo:
1) Serializable classes. If I have a fake entity that obtains, say, a POJO class (not Serializable) as a result and that fake entity tries to return this class to a plugin, it works normally. But if I have a fake entity that queries another fake entity that obtains the POJO class, then that POJO class MUST implement Serializable if I need this POJO class in a plugin. That is:

data source->fake entity->fake entity->plugin

then classes being returned from data source to plugin must be Serializable. My fake entities are local, (i'm using remote=false, local = true). Anybody knows what's happening with this?


In what respect? When you cross the web app class loader boundary your objects must be serializable so they can be 'copied' from one side to the other. It's pretty much a core requirement.

2) When an Exception is thrown from a fake entity, usually the exception is hard to discover/locate. This is because the clp class catches only the exceptions specified in the method signature. If you don't specify the NotSerializableException in the method in the fake entity, then when this method throws an unchecked exception you will see an exception with something like "NotSerializableException is not a valid exception", but the stack trace of the NotSerializableException (or whatever other exception) will be lost. The reason is how SB generates the clp class: it only checks for declared exceptions (in the method signature) and if the exception is not found there then it throws a RuntimeException using:

throw new RuntimeException(t.getClass().getName() +" is not a valid exception")

I believe that the RuntimeException throw should contain the t exception too. I mean something like throw new RuntimeException( "blabla" , t ); I will look for the way to suggest this change for next Liferay SB versions.


There's good news here, SB is actually built off of Velocity. You can create and override default Liferay templates for SB to add this functionality yourself.

3) Using fake entities implies that you will run ant build-service many times during the development. I've found that, sometimes, SB doesn't update the generated classes. When I change a private method in a fake entity the SB doesn't "detect" the change. I'm still investigating this, but I found that either I run an ant clean, or I change a public method in order to force SB to regenerate the classes. Somebody has some suggestion about this?


Protected and private methods do not affect the public interface maintained by SB. If you create a protected/private method or member in XxxLocalServiceImpl, that method will never be available or exposed in the XxxLocalService interface or XxxLocalServiceUtil class.

SB doesn't "detect" the change because it has no impact on the generated code.
Pa Blo, modifié il y a 9 années.

RE: big application

New Member Publications: 14 Date d'inscription: 09/03/14 Publications récentes
David H Nebinger:
Pa Blo:
1) Serializable classes. If I have a fake entity that obtains, say, a POJO class (not Serializable) as a result and that fake entity tries to return this class to a plugin, it works normally. But if I have a fake entity that queries another fake entity that obtains the POJO class, then that POJO class MUST implement Serializable if I need this POJO class in a plugin. That is:

data source->fake entity->fake entity->plugin

then classes being returned from data source to plugin must be Serializable. My fake entities are local, (i'm using remote=false, local = true). Anybody knows what's happening with this?


In what respect? When you cross the web app class loader boundary your objects must be serializable so they can be 'copied' from one side to the other. It's pretty much a core requirement.


Yes, I know about those Serializable requirements, but what is strange for me is:
data source->fake entity->plugin : does't need to be Serializable
data source->fake entity->fake entity->plugin : needs to be Serializable


David H Nebinger:
Pa Blo:

2) When an Exception is thrown from a fake entity, usually the exception is hard to discover/locate. This is because the clp class catches only the exceptions specified in the method signature. If you don't specify the NotSerializableException in the method in the fake entity, then when this method throws an unchecked exception you will see an exception with something like "NotSerializableException is not a valid exception", but the stack trace of the NotSerializableException (or whatever other exception) will be lost. The reason is how SB generates the clp class: it only checks for declared exceptions (in the method signature) and if the exception is not found there then it throws a RuntimeException using:

throw new RuntimeException(t.getClass().getName() +" is not a valid exception")

I believe that the RuntimeException throw should contain the t exception too. I mean something like throw new RuntimeException( "blabla" , t ); I will look for the way to suggest this change for next Liferay SB versions.


There's good news here, SB is actually built off of Velocity. You can create and override default Liferay templates for SB to add this functionality yourself.


That's great. It will be useful for those (like me) who needs some kind of customization so I will investigate how I can throw those exceptions.


David H Nebinger:
Pa Blo:

3) Using fake entities implies that you will run ant build-service many times during the development. I've found that, sometimes, SB doesn't update the generated classes. When I change a private method in a fake entity the SB doesn't "detect" the change. I'm still investigating this, but I found that either I run an ant clean, or I change a public method in order to force SB to regenerate the classes. Somebody has some suggestion about this?


Protected and private methods do not affect the public interface maintained by SB. If you create a protected/private method or member in XxxLocalServiceImpl, that method will never be available or exposed in the XxxLocalService interface or XxxLocalServiceUtil class.

SB doesn't "detect" the change because it has no impact on the generated code.


Yes, private and protected methods are not available outside the LocalService iface. But my public methods are using other private methods and I've found that when I change one of those private methods, the change seems not being applied since the behaviour is the same (after copy jar to lib/ext, restart Liferay and redeploy the service). I mean that when I change a private method I'm able to change the behaviour of a fake entity only performing "ant clean", or changing one of the public methods, and then rebuilding the service. Since I'm still not sure of the "forced rebuilding" caused by "ant clean", I'm currently adding and removing methods like void aaaa() { } to "force" SB to rebuild the classes. Maybe I am not explained to me very well.

Regards.
Pablo.
thumbnail
David H Nebinger, modifié il y a 9 années.

RE: big application

Liferay Legend Publications: 14916 Date d'inscription: 02/09/06 Publications récentes
Pa Blo:
Yes, I know about those Serializable requirements, but what is strange for me is:
data source->fake entity->plugin : does't need to be Serializable
data source->fake entity->fake entity->plugin : needs to be Serializable


So just make all cases happy and make them serializable. They probably should be to pass through the class loader boundary safely anyway, and it surely won't hurt.

That's great. It will be useful for those (like me) who needs some kind of customization so I will investigate how I can throw those exceptions.


It's not that hard, actually. If you have the source check out the ServiceBuilder.java class. It will show you the command line options to use and you can use the current template file as a model for the new template. The fun part is affecting the change in your build process (maven or ant) to use your template.

Yes, private and protected methods are not available outside the LocalService iface. But my public methods are using other private methods and I've found that when I change one of those private methods, the change seems not being applied since the behaviour is the same (after copy jar to lib/ext, restart Liferay and redeploy the service). I mean that when I change a private method I'm able to change the behaviour of a fake entity only performing "ant clean", or changing one of the public methods, and then rebuilding the service. Since I'm still not sure of the "forced rebuilding" caused by "ant clean", I'm currently adding and removing methods like void aaaa() { } to "force" SB to rebuild the classes. Maybe I am not explained to me very well.


You're explaining fine, but the implementation does not have any change on the interface.

For example, if your method returns a List object and internally you change from an ArrayList to a LinkedList, the services do not have to be rebuilt again. The services just comprise the service jar and that's it. It has absolutely nothing to do with the interfaces that are generated.

All you need to do is build your portlet and deploy it, but not build services. The only time services have to change is when you add/remove a public method from the Impl classes or change a public method signature (like add a param or something). Internal changes that have nothing to do with the API do not require a service build.

If that's what you think is necessary, I'm afraid there's something else going on outside of the service building mechanism... The "ant clean" is also going to wipe the classes out from the java implementation files, not just the service files.
Pa Blo, modifié il y a 9 années.

RE: big application

New Member Publications: 14 Date d'inscription: 09/03/14 Publications récentes
Hi David,

Yeah, I will implement Serializable in all classes being managed by a fake entity. In this case it was a bit nuisance because the classes were generated by cxf and I had to create a custom binding file. It would be easy to simply add "implements Serializable" to the required classes but it is not how I work.

I will investigate the source code of the SB in order to customize the exceptions topic. It is a bit frustrating to have no idea of what is going wrong since the exception stack trace is lost. When this happens, one way is to surround the fake entity method call (in your plugin) with try catch(Throwable) and see what's the exception. When this doesn't work, you need to do the same but in the fake entity method instead of in the plugin method.

For the SB rebuilding topic, it is something strange. The thing is that sometimes, when I change a private method called from a public method and I rebuild the service, my changes are not seen. Sometimes work, sometimes doesn't. I have to find a minute to investigate exactly what is happening, when and how. I will inform here about that.

Many thanks.
Pablo.