Server-side schema validation with JAX-WS - validation

I have JAX-WS container-less service (published via Endpoint.publish() right from main() method). I want my service to validate input messages. I have tried following annotation: #SchemaValidation(handler=MyErrorHandler.class) and implemented an appropriate class. When I start the service, I get the following:
Exception in thread "main" javax.xml.ws.WebServiceException:
Annotation #com.sun.xml.internal.ws.developer.SchemaValidation(outbound=true,
inbound=true, handler=class mypackage.MyErrorHandler) is not recognizable,
atleast one constructor of class
com.sun.xml.internal.ws.developer.SchemaValidationFeature
should be marked with #FeatureConstructor
I have found few solutions on the internet, all of them imply the use of WebLogic container. I can't use container in my case, I need embedded service. Can I still use schema validation?

The #SchemaValidation annotation is not defined in the JAX-WS spec, but validation is left open. This means you need something more than only the classes in the jdk.
As long as you are able to add some jars to your classpath, you can set this up pretty easily using metro (which is also included in WebLogic. This is why you find solutions that use WebLogic as container.). To be more precise, you need to add two jars to your classpath. I'd suggest to
download the most recent metro release.
Unzip it somewhere.
Add the jaxb-api.jar and jaxws-api.jar to your classpath. You can do this for example by putting them into the JAVA_HOME/lib/endorsed or by manually adding them to your project. This largely depends on the IDE or whatever you are using.
Once you have done this, your MyErrorHandler should work even if it is deployed via Endpoint.publish(). At least I have this setup locally and it compiles and works.
If you are not able to modify your classpath and need validation, you will have to validate the request manually using JAXB.

Old question, but I solved the problem using the correct package and minimal configuration, as well using only provided services from WebLogic. I was hitting the same problem as you.
Just make sure you use correct java type as I described here.
As I am planning to expand to a tracking mechanism I also implemented the custom error handler.
Web Service with custom validation handler
import com.sun.xml.ws.developer.SchemaValidation;
#Stateless
#WebService(portName="ValidatedService")
#SchemaValidation(handler=MyValidator.class)
public class ValidatedService {
public ValidatedResponse operation(#WebParam(name = "ValidatedRequest") ValidatedRequest request) {
/* do business logic */
return response;
}
}
Custom Handler to log and store error in database
public class MyValidator extends ValidationErrorHandler{
private static java.util.logging.Logger log = LoggingHelper.getServerLogger();
#Override
public void warning(SAXParseException exception) throws SAXException {
handleException(exception);
}
#Override
public void error(SAXParseException exception) throws SAXException {
handleException(exception);
}
#Override
public void fatalError(SAXParseException exception) throws SAXException {
handleException(exception);
}
private void handleException(SAXParseException e) throws SAXException {
log.log(Level.SEVERE, "Validation error", e);
// Record in database for tracking etc
throw e;
}
}

Related

JOOQ execution listener does not catch exception

I'm trying to implement a generic solution for optimized locking. What I want to achieve is to have a specific piece of code run when record's version changes. I have it implemented as an ExecuteListener instance that looks for DataChangedException. It's registered as a Spring bean.
class LockingListener : DefaultExecuteListener() {
override fun exception(ctx: ExecuteContext) {
val exception = ctx.exception()
if (exception is DataChangedException) {
ctx.exception(IllegalStateException("Accessed data has been altered mid-operation."))
}
}
}
#Configuration
class JooqConfig {
#Bean
fun lockingListenerProvider() = DefaultExecuteListenerProvider(LockingListener())
}
I had a breakpoint set in org.jooq.impl.ExecuteListeners#get and it does look like it gets picked up alongside LoggerListener and JooqExceptionTranslator.
When I try to run a test case though, DataChangedException does not get picked up on UpdateableRecord#update and I get the following stacktrace instead, no IllegalStateException in sight.
org.jooq.exception.DataChangedException: Database record has been changed or doesn't exist any longer
at org.jooq.impl.UpdatableRecordImpl.checkIfChanged(UpdatableRecordImpl.java:540)
at org.jooq.impl.UpdatableRecordImpl.storeMergeOrUpdate0(UpdatableRecordImpl.java:349)
at org.jooq.impl.UpdatableRecordImpl.storeUpdate0(UpdatableRecordImpl.java:241)
at org.jooq.impl.UpdatableRecordImpl.access$100(UpdatableRecordImpl.java:89)
at org.jooq.impl.UpdatableRecordImpl$2.operate(UpdatableRecordImpl.java:232)
at org.jooq.impl.RecordDelegate.operate(RecordDelegate.java:149)
at org.jooq.impl.UpdatableRecordImpl.storeUpdate(UpdatableRecordImpl.java:228)
at org.jooq.impl.UpdatableRecordImpl.update(UpdatableRecordImpl.java:165)
Debugging shows that LockingListener#exception does not even get entered into.
That exception is not part of the ExecuteListener lifecycle, i.e. the lifecycle that deals with interactions with the JDBC API. In other words, it's not a SQLException, it happens higher up the stack. Use the RecordListener.exception() callback, instead.

Jooq configuration per request

I'm struggling to find a way to define some settings in DSLContext per request.
What I want to achieve is the following:
I've got a springboot API and a database with multiple schemas that share the same structure.
Depending on some parameters of each request I want to connect to one specific schema, if no parameters is set I want to connect to no schema and fail.
To not connect to any schema I wrote the following:
#Autowired
public DefaultConfiguration defaultConfiguration;
#PostConstruct
public void init() {
Settings currentSettings = defaultConfiguration.settings();
Settings newSettings = currentSettings.withRenderSchema(false);
defaultConfiguration.setSettings(newSettings);
}
Which I think works fine.
Now I need a way to set schema in DSLContext per request, so everytime I use DSLContext during a request I get automatically a connection to that schema, without affecting other requests.
My idea is to intercept the request, get the parameters and do something like "DSLContext.setSchema()" but in a way that applies to all usage of DSLContext during the current request.
I tried to define a request scopeBean of a custom ConnectionProvider as follows:
#Component
#RequestScope
public class ScopeConnectionProvider implements ConnectionProvider {
#Override
public Connection acquire() throws DataAccessException {
try {
Connection connection = dataSource.getConnection();
String schemaName = getSchemaFromRequestContext();
connection.setSchema(schemaName);
return connection;
} catch (SQLException e) {
throw new DataAccessException("Error getting connection from data source " + dataSource, e);
}
}
#Override
public void release(Connection connection) throws DataAccessException {
try {
connection.setSchema(null);
connection.close();
} catch (SQLException e) {
throw new DataAccessException("Error closing connection " + connection, e);
}
}
}
But this code only executes on the first request. Following requests don't execute this code and hence it uses the schema of the first request.
Any tips on how can this be done?
Thank you
Seems like your request-scope bean is getting injected into a singleton.
You're already using #RequestScope which is good, but you could forget to add #EnableAspectJAutoProxy on your Spring configuration class.
#Configuration
#EnableAspectJAutoProxy
class Config {
}
This will make your bean run within a proxy inside of the singleton and therefore change per request.
Nevermind, It seems that the problem I was having was caused by an unexpected behaviour of some cacheable function I defined. The function is returning a value from the cache although the input is different, that's why no new connection is acquired. I still need to figure out what causes this unexpected behaviour thought.
For now, I'll stick with this approach since it seems fine at a conceptual level, although I expect there is a better way to do this.
*** UPDATE ***
I found out that this was the problem I had with the cache Does java spring caching break reflection?
*** UPDATE 2 ***
Seems that setting schema in the underlying datasource is ignored. I'm currently trying this other approach I just found (https://github.com/LinkedList/spring-jooq-multitenancy)

Quarkus hibernate validations exceptions not showing on the console

I have a simple project using Quarkus 1.4.2. When I use the #Valid annotation, and the validations fail with a status 500, the exception is not show on the console. Only in the Swagger UI. What should I do to print it out on the console?
#ApplicationScoped
public class ProductService {
public void validateProduct(#Valid Product product) {
}
}
The exception that is occurring is:
javax.validation.UnexpectedTypeException: HV000030: No validator could be found for constraint
The error is correct. It is just not shown on the console.
I would expect the error to be logged as it's definitely a usability issue. And I would expect it to be logged on startup when we collect the Hibernate Validator metadata, not for every call.
You could create a reproducer and open a GitHub issue in the Quarkus tracker here.
I'll check it out and see if something needs fixing.
If I understand correctly, you need to use the Validator object in order to catch possible Exceptions:
#Inject
Validator validator;
public void validateProduct(Product product) {
// Should throw an error
Set<ConstraintViolation<Product>> violations = validator.validate(product);
if(violations.isEmpty()) {
return;
}
for (ConstraintViolation<Product> violation : violations) { // or log whole set as json
System.out.println(violation.toString()); //TODO prettify
}
throw new ValidationException(JsonbBuilder.create().toJson(violations));
}
If you get a 500 error, you can now catch it and log.
Or just catch UnexpectedTypeException where you call your service. This might be better.

Do JASON internal actions work with Spring Autowire?

I am developing an application using JADE, JASON (Agent frameworks) and Spring Boot. Basically what I have is a JADE Container where Both Jade and Jason Agents are registered in. And Since I am using Spring, I tend to Autowire services. In that case I am in need to access some services, inside some of my Jason internal actions (which I custom wrote extending DefaultInternalAction class). which seems not working. I have the idea how to Autowire and how the Beans work. My doubt is whether those internal actions are in the spring context or not. I guess they are not. Thats why may be the Autowire thing is not working. Can someone please explain me about the real action inside the jade container and internal actions so that I can think differently about using Autowire inside jason internal actions.
As far as I know, internal actions is created by jason, not spring that is why you cant autowire services. Personnaly, I create factory and use it for getting instance of a service. Something like this:
public class SpringPluginFactory {
private static final SpringPluginFactory INSTANCE = new SpringPluginFactory();
private ApplicationContext applicationContext;
private SpringPluginFactory(){}
private <T> T createPlugin(Class<T> iface) {
if(applicationContext == null){
throw new IllegalStateException("applicationContext cannot be null");
}
try {
return applicationContext.getBean(iface);
} catch (Exception e) {
throw new RuntimeException("factory unable to construct instance of " + iface.getName());
}
}
public static <T> T getPlugin(Class<T> iface){
return INSTANCE.createPlugin(iface);
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
then I create bean in order to set aplicationContext:
#Bean
public SpringPluginFactory pluginFactory(ApplicationContext applicationContext){
SpringPluginFactory pluginFactory = SpringPluginFactory.INSTANCE;
pluginFactory.setApplicationContext(applicationContext);
return pluginFactory;
}
and use the factory in any behaviours or internal actions
SpringPluginFactory.getPlugin(YouService.class).doSomething();
Maybe it will help.

GWT violation check on server side throws SerializationException

I followed the gwt 2.4 validation sample and implemented the whole stuff into my own App. The client side works great.
private void verifyRegistrationData(final RegistrationTO registration) throws ConstraintViolationException {
final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
final Set<ConstraintViolation<RegistrationTO>> violations = validator.validate(registration);
if (violations.size() > 0) {
final Set<ConstraintViolation<?>> temp = new HashSet<ConstraintViolation<?>>(violations);
throw new ConstraintViolationException(temp);
...
but if I do the same on the server side:
public void update(final RegistrationTO registration) throws IllegalArgumentException, ConstraintViolationException, TestException {
final Set<ConstraintViolation<RegistrationTO>> violations = validator.validate(registration);
if (!violations.isEmpty()) {
final Set<ConstraintViolation<?>> temp = new HashSet<ConstraintViolation<?>>(violations);
throw new ConstraintViolationException(temp);
}
...
the whole thing crashes with the following exception:
javax.servlet.ServletContext log: Exception while dispatching incoming RPC call
com.google.gwt.user.client.rpc.SerializationException: Type 'org.hibernate.validator.engine.PathImpl' was not included in the set of types which can be serialized by this SerializationPolicy or its Class object could not be loaded. For security purposes, this type will not be serialized.
That's how PathImpl looks like hibernate-validator-4.1.0.Final-sources.jar
public class PathImpl implements Path, Serializable {
private static final long serialVersionUID = 7564511574909882392L;
...
looks OK (at least to me)
I am using GWT 2.4, validation-api-1.0.0.GA, hibernate-validator-4.1.0.Final, gwt-servlet-deps ...
Thanks in advance!
Is there an explicitly defined a default constructor? i.e.,
public PathImpl() { } ? This is required by GWT's serialization mechanism; if it isn't in the source, serializing an RPC response will fail.
A custom serializer does exist for PathImpl, it's just that unless that class is explicitly referenced in your service API, it's not going to be added to the serialization policy.
The current work around is to add a dummy PathImpl field somewhere in your service API. The ValidationSupport class exists to group this and other such classes together to make this a bit easier.
I change the whole thing to RequestFactory as Thomas Broyer recommended. It was by far not so easy as GWT-RPC. This was the reason for me to collect all kind of informations and to build a sample program. For those who are interested - here you can find a sample with documentation and source. (Single line client logger is also implemented) (Documentation is in German but logging-output aso. is in English...)

Resources