apache-cfx and JAXRSx log with the wrong ressourceName - java

I use Spring and jaxrs
I have a restApi with 2 endpoints, say
/cats
/dogs
each endpoint is in its own ressource class, say CatRessource.class and DogRessource.class
everythings works fine, but the ressourceName in the apache-cfx logging is wrong, i always end-up with a componentId :
org.apache.cxf.services.CatRessource.REQ_IN -
even if I know, my code is going the the DogRessource class.
from what I looked, the name come from apache
protected Logger getLogger(final LogEvent event) {
final String cat = "org.apache.cxf.services." + event.getPortTypeName().getLocalPart() + "." + event.getType();
return LoggerFactory.getLogger(cat);
}
who gets it from
Endpoint ep = message.getExchange().getEndpoint()
and looking still up, that endpoint is created when the APi start, the name of the ressource is given by Jaxrs who gives the name of the first ressourceclass it finds
public class JAXRSServiceImpl extends AbstractAttributedInterceptorProvider implements Service, Configurable {
...
public QName getName() {
if (serviceName != null) {
return serviceName;
}
if (address == null && !classResourceInfos.isEmpty()) {
Class<?> primaryClass = classResourceInfos.get(0).getServiceClass();
String ns = PackageUtils.getNamespace(PackageUtils.getPackageName(primaryClass));
return new QName(ns, primaryClass.getSimpleName());
}
return new QName(address, "WebClient");
}
is there an easy way to have the correct name in the log, or a default one?

Related

HAPI FHIR #Create Operation not returning MethodOutcome Response

I was basing my program off of the samples on hapishir's website and the operation works in that I receive the JSON body and I'm updating the database. The issue I have though is that there is no response being returned. I build the MethodOutcome object, and "return" it, but nothing appears in postman. I've written #read and #Search operations also and those both return the resource in the response on Postmat, but this #Create doesn't return any response.
ObservationResourceProvider.java
public class ObservationResourceProvider implements IResourceProvider {
public ObservationResourceProvider() { }
#Override
public Class<? extends IBaseResource> getResourceType() {
return Observation.class;
}
#Create()
public MethodOutcome createObservation(#ResourceParam Observation observation){
OpenERMDatabase db = new OpenERMDatabase();
String newObservationId = db.addNewObservation(observation);
//return the new Id if success else return an error message
MethodOutcome retVal = new MethodOutcome();
if (newObservationId != null) {
retVal.setId(new IdType("Observation", newObservationId, "1.0"));
retVal.setCreated(true);
}else {
OperationOutcome outcome = new OperationOutcome();
outcome.addIssue().setDiagnostics("An Error Occurred");
retVal.setOperationOutcome(outcome);
retVal.setCreated(false);
}
return retVal;
}
}
SimpleRestfulServer.java
#WebServlet("/*")
public class SimpleRestfulServer extends RestfulServer{
//Initialize
#Override
protected void initialize()throws ServletException{
//create a context for the appropriate version
setFhirContext(FhirContext.forDstu3());
//Register Resource Providers
registerProvider(new PatientResourceProvider());
registerProvider(new ObservationResourceProvider());
}
}
I've built an environment and debugged the server side code.
I'm sure you will get some hint from this. There are three modes defined in PreferReturnEnum, when you specify an extra header in the HEADERS with key as "Prefer" and value as " return=OperationOutcome", the value defined in operationOutcome will be retured.

How to parse DFT_P03 message with ZPM segment

I am coding a server application that will receive DFT_P03 messages with an added ZPM segment (which i have created a class for as per the HAPI documentation). Currently i am able to access this field as a generic segment when doing the following :
#Override
public Message processMessage(Message t, Map map) throws ReceivingApplicationException, HL7Exception
{
String encodedMessage = new DefaultHapiContext().getPipeParser().encode(t);
logEntryService.logDebug(LogEntry.CONNECTIVITY, "Received message:\n" + encodedMessage + "\n\n");
try
{
InboundMessage inboundMessage = new InboundMessage();
inboundMessage.setMessageTime(new Date());
inboundMessage.setMessageType("Usage");
DFT_P03 usageMessage = (DFT_P03) t;
Segment ZPMSegment = (Segment)usageMessage.get("ZPM");
inboundMessage.setMessage(usageMessage.toString());
Facility facility = facilityService.findByCode(usageMessage.getMSH().getReceivingFacility().getNamespaceID().getValue());
inboundMessage.setTargetFacility(facility);
String controlID = usageMessage.getMSH().getMessageControlID().encode();
controlID = controlID.substring(controlID.indexOf("^") + 1, controlID.length());
inboundMessage.setControlId(controlID);
Message response;
try
{
inboundMessageService.save(inboundMessage);
response = t.generateACK();
logEntryService.logDebug(LogEntry.CONNECTIVITY, "Message ACKed");
}
catch (Exception ex)
{
response = t.generateACK(AcknowledgmentCode.AE, new HL7Exception(ex));
logEntryService.logDebug(LogEntry.CONNECTIVITY, "Message NACKed");
}
return response;
}
catch (IOException e)
{
logEntryService.logDebug(LogEntry.CONNECTIVITY, "Message rejected");
throw new HL7Exception(e);
}
}
I have created a DFT_P03_Custom class as following :
public class DFT_P03_Custom extends DFT_P03
{
public DFT_P03_Custom() throws HL7Exception
{
this(new DefaultModelClassFactory());
}
public DFT_P03_Custom(ModelClassFactory factory) throws HL7Exception
{
super(factory);
String[] segmentNames = getNames();
int indexOfPid = Arrays.asList(segmentNames).indexOf("FT1");
int index = indexOfPid + 1;
Class<ZPM> type = ZPM.class;
boolean required = true;
boolean repeating = false;
this.add(type, required, repeating, index);
}
public ZPM getZPM()
{
return getTyped("ZPM", ZPM.class);
}
}
When trying to typecast the message to a DFT_P03_Custom instance i get a ClassCastException. As per their documentation, i did create the CustomModelClassFactory class but using this i just get tons of validation errors on the controlId field.
I am already using an identical logic to send custom MFN_M01 messages with an added ZFX segment and that works flawlessly. I understand there is some automatic typecasting being done by HAPI when it receives a DFT_P03 message and that is likely what i need to somehow override for it to be able to give me a DFT_P03_Custom instance instead.
If you have some insight on how i can achieve this without having to use a generic segment instance please help!
Thank you!
I finally figured this out. The only way i got this to work was to generate a conformance profile XML file (using an example message from our application as a base) with the messaging workbench on the HAPI site and use the maven plugin to generate the message and segment classes. Only with these classes am i able to correctly parse a message to my custom class. One thing to note is that it DOES NOT work if i try to use the MSH, PID, PV1 or FT1 classes provided by HAPI and use my Z-segment class. It only works if all the segments are the classes generated by the conformance plugin. This combined with a CustomModelClassFactory class (as shown on the HAPI website) and the proper package structure finally allowed me to access my Z-segment.

How do I read a JNDI property from a Client GWT app

On Server side, there is a JNDI resource, that I need to read from a Client GWT App.
I know, that I can make a GWT RPC call to get the JNDI resource dynamically, but the JNDI resource is a static URL, that will not change, once the page is loaded. So - my idea was to load the JNDI resource when loading the page.
I found an outdated description about how this could be done - in 2011
https://webtide.com/gwt-and-jndi/
However, I would like to know, whether this would be possible for a more current version of GWT (I am using GWT 2.7.0)
I had the same problem. Pass JNDI parameters and some other configuration values to the GWT application.
The trick is to generate the GWT hostpage dynamically (with JSP in my case).
Each inital call to my GWT application goes to a front controller (a Servlet) for authorizition purposes and some other intitialization stuff.
Then I get all the JNDI parameters and other values, put them into the request context and call the hostpage JSP.
In my JSP page I define a JavaScript hash and initialize it with the parameters.
<script type="text/javascript">
var my_params = {
jndiParam1: '<%= request.getAttribute("jndiParam1") %>',
exampleUrl: '<%= request.getAttribute("exampleUrl") %>',
jndiParam2: '<%= request.getAttribute("jndiParam2") %>'
};
</script>
And inside my GWT application I have a class HostPageParameter which uses a com.google.gwt.i18n.client.Dictionary to access the JavaScript hash my_params.
public class HostPageParameter {
private static final String DICTNAME = "my_params";
private static HostPageParameter instance = null;
public static HostPageParameter getInstance() {
if(instance == null) {
instance = new HostPageParameter();
}
return instance;
}
private Dictionary myParams;
private HostPageParameter() {
try {
myParams = Dictionary.getDictionary(DICTNAME);
} catch(MissingResourceException e) {
// If not defined
myParams = null;
}
}
public String getParameter(String paramName) {
return getParameter(paramName, null);
}
public String getParameter(String paramName, String defaultValue) {
String paramValue = null;
if(myParams != null && paramName != null) {
try {
paramValue = myParams.get(paramName);
} catch (MissingResourceException e) {
// If not defined
paramValue = defaultValue;
}
}
return paramValue;
}
}
And to read the values you simply can use:
// Without a default value, If not defined, null is returned.
final String jndiParam1 = HostPageParameter.getInstance().getParameter("jndiParam1");
// With default value.
final String exampleUrl = HostPageParameter.getInstance().getParameter("exampleUrl",
"http://example.com");

Logging exceptions when firing rules with ConsequenceExceptionHandler

I have my drools server configured via spring/camel and I'd like to be able log to a file all runtime exceptions that occur when rules are fired, along with details about the state of the working memory at the time of the exception.
I found that drools version >= 5.2 of drools-spring does allow for the setting of a custom ConsequenceExceptionHandler class in the spring configuration:
https://issues.jboss.org/browse/JBRULES-2674
I'm having some trouble (some of which related from migrating from drools 5.1 to 5.2) so I was wondering if anyone has done the logging of exceptions before and could share some implementation details. Or if someone can tell me if there's a better way to achieve this than through a custom exception handler.
In my project (I think I'll have to write about it on my blog http://toomuchcoding.blogspot.com where I have some articles about Drools) I wrote a custom Listener in the following manner (I think I found a nice tutorial over here http://members.inode.at/w.laun/drools/CustomConsequenceExceptionHandlingHowTo.html)
I defined my KnowledgeBase as a bean in my applicationContext:
<drools:kbase id="fxKBase">
<drools:resources>
<drools:resource type="DRL" source="classpath:path/first.drl"/>
<drools:resource type="DRL" source="classpath:path/second.drl"/>
</drools:resources>
<drools:configuration>
<drools:consequenceExceptionHandler handler="a.b.c.MyConsequenceExceptionHandler" />
</drools:configuration>
</drools:kbase>
Then I defined MyConsequenceExceptionHandler
public class MyConsequenceExceptionHandler implements ConsequenceExceptionHandler {
#Override
public void handleException(Activation activation, WorkingMemory workingMemory, Exception exception) {
throw new MyConsequenceException(activation, workingMemory, exception);
}
and the MyConsequenceException:
public class MyConsequenceException extends RuntimeException {
private final WorkingMemory workingMemory;
private final Activation activation;
public MyConsequenceException(final Activation activation, final WorkingMemory workingMemory, final Exception exception) {
super(exception);
this.activation = activation;
this.workingMemory = workingMemory;
}
#Override
public String getMessage() {
StringBuilder sb = new StringBuilder( "Exception executing consequence for " );
if( activation != null && ( activation.getRule() ) != null ){
Rule rule = activation.getRule();
String ruleName = rule.getName();
sb.append("rule [\"").append( ruleName ).append( "\"]. " );
} else {
sb.append( "rule, name unknown" );
}
Throwable throwable = ExceptionUtils.getRootCause(getCause());
sb.append("The thrown exception is [").append(throwable).append("]. ");
return sb.toString();
}
#Override
public String toString() {
return getMessage();
}
}
In that way when an exception is thrown you will get a custom message of your choosing.

Determine target service/method from CXF Interceptor

I'd like to write an interceptor for the Apache CXF JAX-RS implementation that inspects the target service/method for a particular annotation and does some special processing for that annotation.
I can't seem to find anything in the interceptor documentation that describes how to do this. Does anyone have any ideas?
Thanks!
If the interceptor runs fairly late in the chain (like the USER_LOGICAL
phase), you should be able to do something like:
Exchange exchange = msg.getExchange();
BindingOperationInfo bop = exchange.get(BindingOperationInfo.class);
MethodDispatcher md = (MethodDispatcher)
exchange.get(Service.class).get(MethodDispatcher.class.getName());
Method meth = md.getMethod(bop);
That should give you the Method that was bound in so you can get the declared
class or the annotations, etc...
Ah. I didn't specify that I was using the JAX-RS part of CXF; not sure if that impacts Daniel Kulp's answer but his solution didn't actually work for me. I believe it is because CXF does things differently when handling JAX-RS.
I came across the source for CXF's [JAXRSInInterceptor][1] and I saw in that code that this interceptor is putting the method info into the Exchange object like so:
message.getExchange().put(OperationResourceInfo.class, ori);
...during the UNMARSHAL phase, which according to the CXF interceptor docs happens before the *_LOGICAL phase. So by writing an Interceptor that handles the USER_LOGICAL phase I can do:
message.getExchange().get(OperationResourceInfo.class)
...to get access in there to the Method and Class<?> of the Service handling the call!
Building off the original interrogator's answer, I came up with this
public UserContextInterceptor() {
super(Phase.USER_LOGICAL);
}
#Override
public void handleMessage(Message message) {
if(StringUtils.isEmpty(getHeader("some-header-name", message))) {
final Method method = getTargetMethod(message);
if(isAnnotated(method.getDeclaringClass().getAnnotations()) || isAnnotated(method.getAnnotations())) {
final Fault fault = new Fault(new LoginException("Missing user id"));
fault.setStatusCode(HttpServletResponse.SC_UNAUTHORIZED);
throw fault;
}
}
}
private static Method getTargetMethod(Message message) {
final Exchange exchange = message.getExchange();
final OperationResourceInfo resource = exchange.get(OperationResourceInfo.class);
if(resource == null || resource.getMethodToInvoke() == null) {
throw new AccessDeniedException("Method is not available");
}
return resource.getMethodToInvoke();
}
private static boolean isAnnotated(Annotation[] annotations) {
for(Annotation annotation : annotations) {
if(UserRequired.class.equals(annotation.annotationType())) {
return true;
}
}
return false;
}
It has been quite some time since the accepted answer. But there are a few supporting abstractions provided in the
cxf-rt-core-2.7.3.jar
One in there that is provided is org.apache.cxf.interceptor.security.AbstractAuthorizingInInterceptor
This sample excerpt from the source might be a good reference:
protected Method getTargetMethod(Message m) {
BindingOperationInfo bop = m.getExchange().get(BindingOperationInfo.class);
if (bop != null) {
MethodDispatcher md = (MethodDispatcher)
m.getExchange().get(Service.class).get(MethodDispatcher.class.getName());
return md.getMethod(bop);
}
Method method = (Method)m.get("org.apache.cxf.resource.method");
if (method != null) {
return method;
}
throw new AccessDeniedException("Method is not available : Unauthorized");
}

Categories

Resources