Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(some work required) Karaf Tutorial Part 4 - CXF Services in OSGi #39

Open
ghost opened this issue Oct 10, 2017 · 11 comments
Open

(some work required) Karaf Tutorial Part 4 - CXF Services in OSGi #39

ghost opened this issue Oct 10, 2017 · 11 comments

Comments

@ghost
Copy link

ghost commented Oct 10, 2017

Hi,
I was working with the CXF tutorials and noticed a few strange things: I'm reporting them below.

1) maven clean install only builds the SOAP one

corrado@powerdesk2:~/karaf/SRC/Karaf-Tutorial/cxf$ mj8 clean install [INFO] Scanning for projects... [INFO] ------------------------------------------------------------------------ [INFO] Reactor Build Order: [INFO] [INFO] personservice-parent [INFO] personservice-model [INFO] personservice-server [INFO] personservice-proxy [INFO] personservice-webui [INFO] karaf-tutorial-cxf [INFO] ...

that's because only that module is listed in the CXF pom:

<modules> <module>personservice</module> </modules>

it should be like this, right?

<modules> <module>personservice</module> <module>personservice-rest</module> </modules>

2) there is a "proxy-rest" module in both the SOAP and the REST projects:

screenshot from 2017-10-10 08-37-31

also notice:

  • the contents (pom and blueprint) are the same
  • neither of the two "proxy-rest" modules is used:

this is the SOAP pom:
<modules> <module>model</module> <module>server</module> <module>proxy</module> <module>webui</module> </modules>

this is the REST POM:
<modules> <module>model</module> <module>server</module> <module>webui</module> </modules>

the latter should be like this, right?

<modules> <module>model</module> <module>server</module> <module>proxy-rest</module> <module>webui</module> </modules>

I mean, at least for getting the REST one building correctly.

Indeed I could run the SOAP one OK, while the REST one failed:
personservice-rest - deploy-failure.txt

3) the CXF tutorial should be refactored

why having two different models, one for SOAP, one for REST?

screenshot from 2017-10-10 08-47-01

it is ok to have two services, but they shall use same "Person" model, right?
screenshot from 2017-10-10 08-48-51

the solution for this should be having a single "model" module at the "main CXF" level, right?

Let me know and I'll try to fix/refactor this

Thx
Corrado

@cschneider
Copy link
Owner

cschneider commented Oct 10, 2017

It would be great if you could take a look at fixing the problems. I would not like to join the JAX-WS and JAX-RS projects though. Actually I started with a common model project some time ago but I later split it up.

There are some reasons for that:

  1. With a common model you would need both JAX-WS and JAX-RS annotations on the model objects. This is confusing for beginners as they might then use some additional unnecessary annotations for pure JAX-WS or JAX-RS services too.
  2. Sometimes you need to adapt your model for JAX-RS to have a good mapping to REST principles. For example a REST service should return the correct http statuscode 201 when you create an object. So for a good REST service you can often not simply use the pure model interface like in SOAP which is more similar to a remote procedure call.
  3. You need different dependencies for JAX-WS and JAX-RS. I wanted to reflect that in the projects s people understand what the minimal set of dependencies is.

So my goal for the CXF projects is to show best practices for JAX-WS and JAX-RS and I found that mixing both would probably lead people to some rather bad practices.

As I did not have a lot of time for fleshing out this recently I would appreciate if you could take a look and create one or more pull requests.

@ghost
Copy link
Author

ghost commented Oct 10, 2017

Hi Chris,

IMHO your choice is reasonable for a basic tutorial, covering a situation where you have either REST xor SOAP, as the single "common infrastructure", which is not the case in real life, especially in large organizations with tons of legacy infrastructure: clients may want to access the same Person data from both interfaces (personal experience here).

Moreover, "it is not good" that the "actual implementation choices" go "messing the business code" (see cleancoders.com): is there a way to avoid the annotations, by declaring some mapping or implementing an "annotator" to inject them, where needed?

PS: the only annotation in the current model classes is this:
@XmlRootElement
which is required by SOAP, not by REST, right?

I mean, I used simple POJOs with no annotations and just an ObjectMapper to do the serialize/deserialize job, which is heaven on earth, compared to SOAP!

Request:
screenshot from 2017-10-10 09-49-54

Response:
screenshot from 2017-10-10 09-49-58

Serialize/Deserialize:
screenshot from 2017-10-10 09-50-19

So:

  • I'll be happy to help fixing (and refactoring), but let's agree on how to do this!

  • I'd need the REST version to work, for my project: shall I focus on fixing that first, keeping the current "duplicated model"?

PS: I'm quite new to git, I never used it to "push back" my updates, I'd need some instructions in case.

Regards,
Corrado.

@cschneider
Copy link
Owner

Normally you need @XmlRootElement for both JAX-WS and JAX-RS. JAX-RS uses this to map to xml and I think also to map to json.

I don`t think there is a good way to avoid the annotations. For bigger projects it probably makes sense to have a pure inner model without annotations and maybe also with cross links to other model elements and special facades for SOAP and REST that then map to the inner model. This is more work but for a bigger projects I think it is more important to keep the inner model clean and independent than to save a small layer ... but I think this is always an individual architectural decision.
For a simple tutorial I wanted to avoid to introduce an inner model. We could have a more advanced demo though that shows this.

@ghost
Copy link
Author

ghost commented Oct 11, 2017

Hi Chris,

I've kept the current structure, just suffixed all the rest stuff with "-rest":

screenshot from 2017-10-11 08-11-44

I was able to compile all the bundles and install properly all them except the proxy one:

karaf@root()> list
START LEVEL 100 , List Threshold: 50
 ID | State   | Lvl | Version        | Name

 55 | Active  |  80 | 1.0.0.SNAPSHOT | tasklist-command
 56 | Active  |  80 | 1.0.0.SNAPSHOT | tasklist-model
 57 | Active  |  80 | 1.0.0.SNAPSHOT | tasklist-persistence
 58 | Active  |  80 | 1.0.0.SNAPSHOT | tasklist-ui
138 | Active  |  80 | 1.0.0.SNAPSHOT | personservice-model
139 | Active  |  80 | 1.0.0.SNAPSHOT | personservice-server
140 | Active  |  80 | 1.0.0.SNAPSHOT | personservice-proxy
141 | Active  |  80 | 1.0.0.SNAPSHOT | personservice-webui
143 | Active  |  80 | 1.1.0.SNAPSHOT | personservice-rest-model
145 | Active  |  80 | 1.1.0.SNAPSHOT | personservice-rest-server
157 | Active  |  80 | 1.1.0.SNAPSHOT | personservice-rest-webui
169 | Failure |  80 | 1.1.0.SNAPSHOT | personservice-rest-proxy

It look like I can't get the jaxrs-client blueprint configuration to work:

karaf@root()> log:tail 
2017-10-11 08:08:27,950 | WARN  | nsole user karaf | NamespaceHandlerRegistryImpl     | 12 - org.apache.aries.blueprint.core - 1.7.1 | NamespaceHandler org.apache.cxf.jaxrs.client.blueprint.JAXRSBPNamespaceHandler is behaving badly and should be fixed
2017-10-11 08:08:27,955 | WARN  | nsole user karaf | NamespaceHandlerRegistryImpl     | 12 - org.apache.aries.blueprint.core - 1.7.1 | Unable to find namespace handler for http://cxf.apache.org/configuration/beans
2017-10-11 08:08:28,165 | WARN  | nsole user karaf | NamespaceHandlerRegistryImpl     | 12 - org.apache.aries.blueprint.core - 1.7.1 | Unable to find namespace handler for http://cxf.apache.org/blueprint/jaxrs
2017-10-11 08:08:28,320 | ERROR | nsole user karaf | BlueprintContainerImpl           | 12 - org.apache.aries.blueprint.core - 1.7.1 | Unable to start blueprint container for bundle net.lr.tutorial.karaf.cxf.personservice_rest.personservice-rest-proxy/1.1.0.SNAPSHOT
org.xml.sax.SAXParseException: src-import.3.1: The namespace attribute, 'http://cxf.apache.org/blueprint/jaxrs', of an  element information item must be identical to the targetNamespace attribute, 'http://cxf.apache.org/jaxrs', of the imported document.
	at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)[:]
...

is this because of this issue with cxf<3.1.10?

I shall update my karaf version then, since the deployed CXF version is "too old to work":

karaf@root()> feature:list | grep cxf
cxf-specs                       | 3.1.5            |          | Started     | cxf-3.1.5                |
cxf-jaxb                        | 3.1.5            |          | Uninstalled | cxf-3.1.5                |
...

I'm attaching the blueprint file I've been working with, renamed as TXT:

blueprint.xml.txt

Regards,
Corrado.

@ghost
Copy link
Author

ghost commented Oct 11, 2017

looks like so!

screenshot from 2017-10-11 08-47-14

but the webui-rest is still to be fixed:
screenshot from 2017-10-11 08-47-24

PS: I used a brand new karaf instance, to get "newer" CXF version, but I could also have done something else, like upgrading the cxf feature in the older karaf, right?

I mean doing something like this:

feature:repo-add cxf 3.1.11

instead of

feature:repo-add cxf 3.1.5

thx
.k.

@ghost
Copy link
Author

ghost commented Oct 11, 2017

yep, also works on older Karaf, by removing cxf 3.1.5 and installing 3.1.11:

If you use -u option, the feature:repo-remove command uninstalls all features described by the features repository

So I used this to remove all features from that repo (after having uninstalled all cxf-related tutorial bundles):

feature:repo-remove -u cxf-3.1.5

looks like it works now (still webui URLs are buggy):

screenshot from 2017-10-11 09-19-47

@cschneider
Copy link
Owner

I typically always delete the data dir or use karaf clean. So I am sure I have a fresh karaf instance.
You can upgrade features in the newest karaf version by installing the new repo, then install the feature again. Then you can remove the old repo.

Whenever possible I avoid this though as it can easily leave over old bundles if not used carefully.
So as far as possible I always try to treat an upgrade like a new installation.

@ghost
Copy link
Author

ghost commented Oct 11, 2017

I'd rather spend some time around such issues, since once what you've developed is in production, you'd be involved in DevOps - and ops guys are sometime rude with people with the "greenfield syndrome" (check uncle bob about that).

I'm quite happy of what I've achieved so far, with you help: I tried learning karaf in the past too, but with little success, as there have been a lot of "dead ends", due to errors like the one above, in turn due to buggy framework versions, not my understanding...

I'll try fix the webui bundle later today: I have to fix my TvApp first, it shall work with local network only, like the browser does, not like the netflix tvapp...

Let me know how to "push back" the working cxf-rest tutorial

cheers
corrado

@cschneider
Copy link
Owner

cschneider commented Oct 11, 2017 via email

@ghost
Copy link
Author

ghost commented Oct 11, 2017

Hi Chris,

let me recap my understandings, comments and doubts first.

I've studied the cxf tutorial quite deeply, basically doing pom analysis and "diffing" the -soap vs the -rest versions. I started with the main cxf pom and its two soap/rest modules:

01 - comparing main modules of cxf tutorial

Here I'd say:

  • I'd like module folder names and module project aIds to be more aligned ("-parent")
  • gIds are package names, "-" goes into "_", better avoid suffixing, better use package structure: "net...cxf.personservice.rest" is quite better to me
  • why javax.ws.rs here?

Then I did the same for the inner modules, let's start with the "model":
02 - comparing model modules

  • "commons" dependencies should be inherited from parent, right?
  • why PersonService here? why not in the proxy? see shot below
  • "javax.ws.rs" here... models should be just pojos... maybe moving PersonService to proxy could help?

06 - why the service is in the model

Here's for the "proxy" modules:
03 - comparing proxy modules

  • why the -rest has a "build config" here, while the -soap one has one in the "server" module?
  • "commons" dependencies should be inherited from parent, right?

Here's for the "server" modules:
04 - comparing server modules

  • "commons" dependencies should be inherited from parent, right?
  • why the -soap has a "build config" here, while the -rest one has one in the "proxy" module?

And here for the "ui" modules:
05 - comparing webui modules

  • what about using pom properties to define URLs used in the UI?

Could you pls take a look and let me know?

I think I can fix the webui and follow the process you mentioned for the update.

But I don't think I'm going to do all the cleanups and changes I commented about...

cheers
corrado

@cschneider
Copy link
Owner

Sorry for the late reply .. this is a lot to look through and it took me a while to find the time.

About the naming of artifact ids. Please be aware that the artifact id will be the default project name in eclipse. So you have to make sure these project names are half way unique. If not it will be difficult for a user to check out personservice soap and rest modules at the same time.

I agree with changing the gids to be like the package.

For model I always put together the interface and the classes. This allows implementors as well as users of a service to only depend on the model. The big question is if the model should be pure pojos. In larger projects I tend to say yes but it adds another indirection and layer. So for these small examples I opted to keep the annotations in the model to make the code smaller an so easier to understand. Maybe we should have a little warning that for larger projects there should be a seaparation.

I used a build config where I needed to change the maven-bundle-plugin settings. For the newer tutorials I found a much better way for this. There I configure the maven-bundle-plugin just in the parent and use a bnd.bnd file for special configurations. If you want you can apply the here too. See the tasklist-ds example: https://github.com/cschneider/Karaf-Tutorial/blob/master/tasklist-ds/pom.xml#L107-L118 . An even better way is in the liquibase tutorial. There I used the bnd-maven-plugin which does not even require the packaging bundle: https://github.com/cschneider/Karaf-Tutorial/blob/master/liquibase/pom.xml#L73-L94

Using properties for paths in the UI is ok but keep it simple.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant