I found the following error in a Mule 4 components. How can I report this issue to Mulesoft?
Mule 4 XML Module 1.2.3 introduced a bug that causes the wrong Mule error to be raised in the module.
When validating an invalid XML payload (non-xml string, "XML" with unclosed or unpaired tags, etc) version 1.2.2 of the component would raise mule error XML-MODULE:INVALID_INPUT_XML, but with version 1.2.3 of the component the error is now XML-MODULE:TRANSFORMATION.
The problem seems to be that version 1.2.3 of the module removed the call to XMLUtils.toDOMNode, which was used to do an initial validation of the message and threw exception of class InvalidInputXmlException when processing an invalid XML.
XML module : 1.2.2
public class SchemaValidatorOperation extends PooledTransformerOperation<SchemaValidatorOperation.SchemaKey, Validator> {
private LSResourceResolver resourceResolver = (LSResourceResolver)new MuleResourceResolver();
#Validator
#Execution(ExecutionType.CPU_INTENSIVE)
#Throws({SchemaValidatorErrorTypeProvider.class})
public void validateSchema(#Path(type = PathModel.Type.FILE, acceptedFileExtensions = {"xsd"}) String schemas, #Optional(defaultValue = "W3C") SchemaLanguage schemaLanguage, #Content(primary = true) InputStream content, #Config XmlModule config) {
Node node = XMLUtils.toDOMNode(content, this.documentBuilderFactory);
withTransformer(new SchemaKey(schemas, schemaLanguage.getLanguageUri(), this.expandEntities), validator -> {
validator.setResourceResolver(this.resourceResolver);
final List<SchemaViolation> errors = new LinkedList<>();
validator.setErrorHandler(new ErrorHandler() {
public void warning(SAXParseException exception) {}
public void error(SAXParseException exception) {
trackError(exception);
}
public void fatalError(SAXParseException exception) {
trackError(exception);
}
private void trackError(SAXParseException exception) {
errors.add(new SchemaViolation(exception.getLineNumber(), exception.getColumnNumber(), exception.getMessage()));
}
});
try {
validator.validate(new DOMSource(node));
} catch (SAXParseException e) {
throw new TransformationException("Failed to validate schema. " + e.getMessage(), e);
} catch (IOException e) {
throw new InvalidInputXmlException("Could not validate schema because the input was not valid XML. " + e.getMessage(), e);
}
if (!errors.isEmpty())
throw new SchemaValidationException("Input XML was not compliant with the schema. Check this error's Mule message for the list of problems (e.g: #[error.errorMessage.payload[0].description)", errors);
return null;
});
}
XML module : 1.2.3
public class SchemaValidatorOperation extends PooledTransformerOperation<SchemaValidatorOperation.SchemaKey, Validator> {
private LSResourceResolver resourceResolver = (LSResourceResolver)new MuleResourceResolver();
#Validator
#Execution(ExecutionType.CPU_INTENSIVE)
#Throws({SchemaValidatorErrorTypeProvider.class})
public void validateSchema(#Path(type = PathModel.Type.FILE, acceptedFileExtensions = {"xsd"}) String schemas, #Optional(defaultValue = "W3C") SchemaLanguage schemaLanguage, #Content(primary = true) InputStream content, #Config XmlModule config) {
withTransformer(new SchemaKey(schemas, schemaLanguage.getLanguageUri(), this.expandEntities), validator -> {
validator.setResourceResolver(this.resourceResolver);
final List<SchemaViolation> errors = new LinkedList<>();
validator.setErrorHandler(new ErrorHandler() {
public void warning(SAXParseException exception) {}
public void error(SAXParseException exception) {
trackError(exception);
}
public void fatalError(SAXParseException exception) {
trackError(exception);
}
private void trackError(SAXParseException exception) {
errors.add(new SchemaViolation(exception.getLineNumber(), exception.getColumnNumber(), exception.getMessage()));
}
});
try {
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
spf.setFeature("http://xml.org/sax/features/external-general-entities", this.expandEntities.isAcceptExternalEntities());
spf.setFeature("http://xml.org/sax/features/external-parameter-entities", this.expandEntities.isAcceptExternalEntities());
spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", !this.expandEntities.isExpandInternalEntities());
spf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", this.expandEntities.isExpandInternalEntities());
validator.validate(new SAXSource(spf.newSAXParser().getXMLReader(), new InputSource(content)));
} catch (SAXParseException e) {
throw new TransformationException("Failed to validate schema. " + e.getMessage(), e);
} catch (IOException e) {
throw new InvalidInputXmlException("Could not validate schema because the input was not valid XML. " + e.getMessage(), e);
}
if (!errors.isEmpty())
throw new SchemaValidationException("Input XML was not compliant with the schema. Check this error's Mule message for the list of problems (e.g: #[error.errorMessage.payload[0].description)", errors);
return null;
});
}
Not that XMLUtils.toDOMNode was perfect since it catched any Exception, but at least it was useful to detect instances when trying to validate an incorrect xml.
XMLUtils.toDOMNode
public class XMLUtils {
public static Node toDOMNode(InputStream src, DocumentBuilderFactory factory) {
return toDOMNode(src, factory, null);
}
public static Node toDOMNode(InputStream src, DocumentBuilderFactory factory, EntityResolver entityResolver) {
try {
DocumentBuilder documentBuilder = factory.newDocumentBuilder();
if (entityResolver != null)
documentBuilder.setEntityResolver(entityResolver);
return documentBuilder.parse(src);
} catch (Exception e) {
throw new InvalidInputXmlException("Cannot parse input XML because it is invalid.", e);
}
}
}
For open source components of Mule like the XML Module you can open a JIRA ticket in MuleSoft open tracker: https://www.mulesoft.org/jira/projects/MULE. The sources for the XML module are at https://github.com/mulesoft/mule-xml-module so you could attach a push request to the ticket if you create one.
If you are a current customer of MuleSoft you can engage their Support directly.
Related
I have client like this :
import org.basex.api.client.ClientSession;
#Slf4j
#Component(value = "baseXAircrewClient")
#DependsOn(value = "baseXAircrewServer")
public class BaseXAircrewClient {
#Value("${basex.server.host}")
private String basexServerHost;
#Value("${basex.server.port}")
private int basexServerPort;
#Value("${basex.admin.password}")
private String basexAdminPassword;
#Getter
private ClientSession session;
#PostConstruct
private void createClient() throws IOException {
log.info("##### Creating BaseX client session {}", basexServerPort);
this.session = new ClientSession(basexServerHost, basexServerPort, UserText.ADMIN, basexAdminPassword);
}
}
It is a singleton injected in a service which run mulitple queries like this :
Query query = client.getSession().query(finalQuery);
return query.execute();
All threads query and share the same session.
With a single thread all is fine but with multiple thread I get some random (and weird) error, like the result of a query to as a result of another.
I feel that I should put a synchronized(){} arround query.execute() or open and close session for each query, or create a pool of session.
But I don't find any documentation how the use the session in parrallel.
Is this implementation fine for multithreading (and my issue is comming from something else) or should I do it differently ?
I ended creating a simple pool by adding removing the client from a ArrayBlockingQueue and it is working nicely :
#PostConstruct
private void createClient() throws IOException {
log.info("##### Creating BaseX client session {}", basexServerPort);
final int poolSize = 5;
this.resources = new ArrayBlockingQueue < ClientSession > (poolSize) {
{
for (int i = 0; i < poolSize; i++) {
add(initClient());
}
}
};
}
private ClientSession initClient() throws IOException {
ClientSession clientSession = new ClientSession(basexServerHost, basexServerPort, UserText.ADMIN, basexAdminPassword);
return clientSession;
}
public Query query(String finalQuery) throws IOException {
ClientSession clientSession = null;
try {
clientSession = resources.take();
Query result = clientSession.query(finalQuery);
return result;
} catch (InterruptedException e) {
log.error("Error during query execution: " + e.getMessage(), e);
} finally {
if (clientSession != null) {
try {
resources.put(clientSession);
} catch (InterruptedException e) {
log.error("Error adding to pool : " + e.getMessage(), e);
}
}
}
return null;
}
i use JSF and want to have file download in my page . i wrote some codes but i get ClientAbortException error when i use some download manager for download my file :
public class FileUtil {
public static FacesContext getContext() {
return FacesContext.getCurrentInstance();
}
public static void sendFile(File file, boolean attachment) throws IOException {
sendFile(getContext(), file, attachment);
}
public static void sendFile(FacesContext context, File file, boolean attachment) throws IOException {
sendFile(context, new FileInputStream(file), file.getName(), file.length(), attachment);
}
public static void sendFile(FacesContext context, byte[] content, String filename, boolean attachment) throws IOException {
sendFile(context, new ByteArrayInputStream(content), filename, (long) content.length, attachment);
}
public static void sendFile(FacesContext context, InputStream content, String filename, boolean attachment) throws IOException {
sendFile(context, content, filename, -1L, attachment);
}
private static void sendFile(FacesContext context, InputStream input, String filename, long contentLength, boolean attachment) throws IOException {
ExternalContext externalContext = context.getExternalContext();
externalContext.setResponseBufferSize(10240);
externalContext.setResponseContentType(getMimeType(context, filename));
externalContext.setResponseHeader("Content-Disposition", String.format("%s;filename=\"%2$s\"; filename*=UTF-8\'\'%2$s", new Object[]{attachment ? "attachment" : "inline", encodeURL(filename)}));
if (((HttpServletRequest) externalContext.getRequest()).isSecure()) {
externalContext.setResponseHeader("Cache-Control", "public");
externalContext.setResponseHeader("Pragma", "public");
}
if (contentLength != -1L) {
externalContext.setResponseHeader("Content-Length", String.valueOf(contentLength));
}
long size = stream(input, externalContext.getResponseOutputStream());
if (contentLength == -1L) {
externalContext.setResponseHeader("Content-Length", String.valueOf(size));
}
context.responseComplete();
}
public static String getMimeType(FacesContext context, String name) {
String mimeType = context.getExternalContext().getMimeType(name);
if (mimeType == null) {
mimeType = "application/octet-stream";
}
return mimeType;
}
public static long stream(InputStream input, OutputStream output) throws IOException {
ReadableByteChannel inputChannel = Channels.newChannel(input);
Throwable var3 = null;
try {
WritableByteChannel outputChannel = Channels.newChannel(output);
Throwable var5 = null;
try {
ByteBuffer buffer = ByteBuffer.allocateDirect(10240);
long size = 0L;
while (inputChannel.read(buffer) != -1) {
buffer.flip();
size += (long) outputChannel.write(buffer);
buffer.clear();
}
long var9 = size;
return var9;
} catch (Throwable var33) {
var5 = var33;
throw var33;
} finally {
if (outputChannel != null) {
if (var5 != null) {
try {
outputChannel.close();
} catch (Throwable var32) {
var5.addSuppressed(var32);
}
} else {
outputChannel.close();
}
}
}
} catch (Throwable var35) {
var3 = var35;
throw var35;
} finally {
if (inputChannel != null) {
if (var3 != null) {
try {
inputChannel.close();
} catch (Throwable var31) {
var3.addSuppressed(var31);
}
} else {
inputChannel.close();
}
}
}
}
public static String encodeURL(String string) {
if (string == null) {
return null;
} else {
try {
return URLEncoder.encode(string, StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException var2) {
throw new UnsupportedOperationException("UTF-8 is apparently not supported on this platform.", var2);
}
}
}
}
something that i can not understand is when download is done by native chorome download without usage of any download manager like IDM or eagleget , I Do not get any ClientAbortException , but when i use these download manager software for (enable their AddOns) i get these error
what happens ? i know this error happens with some connection losing ... but i did not close my page or any thing that cause this error!
and this is my bean code:
#ManagedBean(name = "bean")
#RequestScoped
public class MB implements Serializable {
public void MBdowan() throws IOException {
File file = new File("E:\\Animation\\IA\\Learning movies\\webinar1\\01_Aug_webinar_08\\Aug08_edited_webinar_animation.mov");
FileUtil.sendFile(file,true);
}
and this is my xhtml page :
</h:head>
<h:body>
<h:form>
<p:commandButton value="Download file" ajax="false" actionListener="#{bean.MBdowan}"/>
</h:form>
</h:body>
Download accelerators (and media players!) expect files which are idempotently available via GET and HEAD requests (i.e. when just typing URL in browser's address bar) and preferably also support HTTP Range requests (so multiple HTTP connections could be opened to download parts simultaneously). The JSF backing bean method is only invoked on a POST request (i.e. when submitting a HTML form with method="post"). The ClientAbortException happens because the download accelerator didn't got the response it expected while sniffing for HEAD and Range support and aborted it.
If those files are static and thus not dynamic, then your best bet is to create a separate servlet which supports HEAD and preferably also HTTP Range requests.
Given that you clearly ripped off the source code from OmniFaces Faces#sendFile(), I'd suggest to rip off the source code of another OmniFaces artifact, the FileServlet. You can find snapshot showcase and source code link here: OmniFaces (2.2) FileServlet.
Here's how you could use it:
#WebServlet("/webinar_animation.mov")
public class YourFileServlet extends FileServlet {
#Override
protected File getFile(HttpServletRequest request) throws IllegalArgumentException {
return new File("E:\\Animation\\IA\\Learning movies\\webinar1\\01_Aug_webinar_08\\Aug08_edited_webinar_animation.mov");
}
}
Download file
See also:
How to stream audio/video files such as MP3, MP4, AVI, etc using a Servlet
i did not find any answer for question "How to handle method validation exceptions?", which is thrown automatically by Bean Validation 1.1.
I have following environment:
Glassfish 4
hibernate-validator-5.0.1.Final.jar (in ear)
Now I try to implement auto validation of method parameters:
#Local
#ValidateOnExecution(type = ExecutableType.ALL)
public interface SomeServiceLocal {
String someMethod(#Size(max = 1) String value);
}
in execution of:
#Stateless
public class OtherBean implements OtherBeanLocal {
#EJB
private SomeServiceLocal someService;
#Override
public String otherMethod() {
return someService.someMethod("abc");
}
}
}
Now, when I call otherMethod a receive:
javax.ejb.EJBTransactionRolledbackException
at com.sun.ejb.containers.BaseContainer.mapLocal3xException(BaseContainer.java:2279)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:2060)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:1979)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:220)
followed by
Caused by: javax.validation.ConstraintViolationException: 1 constraint violation(s) occurred during method validation
...
Constraint violations:
(1) Kind: PARAMETER
parameter index: 3
message: size must be between 0 and 1
What is a best practice to handle violation exceptions?
I've created cdi interceptor which handles EJBException and extract constraint violations. It works perfect:
#MyValidation
#Interceptor
public class MyValidationExceptionInterceptor implements Serializable {
private static final long serialVersionUID = -5280505156146359055L;
#AroundInvoke
public Object processViolationException(InvocationContext ctx) throws Exception {
try {
return ctx.proceed();
} catch (EJBTransactionRolledbackException e) {
Throwable throwable = e.getCause();
if (throwable != null && throwable.getCause() != null && throwable.getCause() instanceof ConstraintViolationException) {
ConstraintViolationException cve = (ConstraintViolationException) throwable.getCause();
throw new MyException(getMessage(cve));
}
throw e;
} catch (Exception e) {
throw e;
}
}
private String getMessage(ConstraintViolationException cve) {
StringBuilder builder = new StringBuilder();
for(ConstraintViolation<?> violation : cve.getConstraintViolations()) {
builder.append(violation.getMessage()).append(';');
}
return builder.toString();
}
}
I am trying to call a WCF service from a Silverlight client using channel factory as per this link. Working with channel factory is something new for me so please bear with me!
Everything mentioned in the article works just fine. But now I am trying to implement Fault exceptions so that I can catch the actual exceptions on the Silverlight side. But for some reason I always end up catching CommunicationException which doesn't serve my purpose.
Here is my service contract:
[OperationContract]
[FaultContract(typeof(Fault))]
IList<Category> GetCategories();
Catch block of the service:
catch (Exception ex)
{
Fault fault = new Fault(ex.Message);
throw new FaultException<Fault>(fault, "Error occured in the GetCategories service");
}
Service contract for client with async pattern:
[OperationContract(AsyncPattern = true)]
[FaultContract(typeof(Fault))]
IAsyncResult BeginGetCategories(AsyncCallback callback, object state);
IList<Category> EndGetCategories(IAsyncResult result);
Here is the service call from client:
ICommonServices channel = ChannelProviderFactory.CreateFactory<ICommonServices>(COMMONSERVICE_URL, false);
var result = channel.BeginGetCategories(
(asyncResult) =>
{
try
{
var returnval = channel.EndGetCategories(asyncResult);
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
CategoryCollection = new ObservableCollection<Category>(returnval);
});
}
catch (FaultException<Fault> serviceFault)
{
MessageBox.Show(serviceFault.Message);
}
catch (CommunicationException cex)
{
MessageBox.Show("Unknown Communications exception occured.");
}
}, null
);
I am sharing the DataContract .dll between both the service and client applications and hence they are referring to same data contract classes (Category & Fault)
Please tell me what I am doing wrongly?
UPDATE: I do clearly see the fault exception sent from the service in Fiddler. Which makes me believe I am missing something in the client side.
For catching normal exceptions in sivleright you must create "Silverlight-enabled WCF Service" (Add -> New Item -> Silverlight-enabled WCF Service).
If you already created standard WCF service you can add attribute [SilverlightFaultBehavior] to your service manually.
Default implementation of this attribute is:
public class SilverlightFaultBehavior : Attribute, IServiceBehavior
{
private class SilverlightFaultEndpointBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new SilverlightFaultMessageInspector());
}
public void Validate(ServiceEndpoint endpoint)
{
}
private class SilverlightFaultMessageInspector : IDispatchMessageInspector
{
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
if ((reply != null) && reply.IsFault)
{
HttpResponseMessageProperty property = new HttpResponseMessageProperty();
property.StatusCode = HttpStatusCode.OK;
reply.Properties[HttpResponseMessageProperty.Name] = property;
}
}
}
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ServiceEndpoint endpoint in serviceDescription.Endpoints)
{
endpoint.Behaviors.Add(new SilverlightFaultEndpointBehavior());
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
}
We use our own custom ServiceException class on the server e.g.
[Serializable]
public class ServiceException : Exception
{
public ServiceException()
{
}
public ServiceException(string message, Exception innerException)
: base(message, innerException)
{
}
public ServiceException(Exception innerException)
: base("Service Exception Occurred", innerException)
{
}
public ServiceException(string message)
: base(message)
{
}
}
And then in our server side service methods we use error handling like this:
try
{
......
}
catch (Exception ex)
{
Logger.GetLog(Logger.ServiceLog).Error("MyErrorMessage", ex);
throw new ServiceException("MyErrorMessage", ex);
}
We then use a generic method for all web service calls:
/// <summary>
/// Runs the given functon in a try catch block to wrap service exception.
/// Returns the result of the function.
/// </summary>
/// <param name="action">function to run</param>
/// <typeparam name="T">Return type of the function.</typeparam>
/// <returns>The result of the function</returns>
protected T Run<T>(Func<T> action)
{
try
{
return action();
}
catch (ServiceException ex)
{
ServiceLogger.Error(ex);
throw new FaultException(ex.Message, new FaultCode("ServiceError"));
}
catch (Exception ex)
{
ServiceLogger.Error(ex);
throw new FaultException(GenericErrorMessage, new FaultCode("ServiceError"));
}
}
I have a Silverlight client with a grid getting data from WCF Data Service. Works fine.
However if I want to update some changed grid row, the service data context UpdateObject is not working:
DataServiceContext.UpdateObject(MyGrid.SelectedItem);
foreach (Object item in DataServiceContext.Entities)
{
//
}
DataServiceContext.BeginSaveChanges(SaveChangesOptions.Batch, OnChangesSaved, DataServiceContext);
I just have created a loop to inspect the values for the entities items and the value is not updated at all. BeginSaveChanges works fine, but it just uses not updated values.
Any ideas how to fix that?
thanks
Right a fully flushed out SaveChanges that will show the error message if EndSaveChanges() fails, like the code sample below. Obviously you can't use the console to write out your message in silverlight, but you get the idea.
For instance, when I wrote the following sample, I found that I was getting a forbidden error, because my entity set had EntitySetRights.AllRead, not EntitySetRights.All
class Program
{
private static AdventureWorksEntities svc;
static void Main(string[] args)
{
svc =
new AdventureWorksEntities(
new Uri("http://localhost:5068/AWDataService.svc",
UriKind.Absolute));
var productQuery = from p in svc.Products
where p.ProductID == 740
select p;
var product = productQuery.First();
ShowProduct(product);
product.Color = product.Color == "Silver" ? "Gray" : "Silver";
svc.UpdateObject(product);
svc.BeginSaveChanges(SaveChangesOptions.Batch, OnSave, svc);
ShowProduct(product);
Console.ReadKey();
}
private static void ShowProduct(Product product)
{
Console.WriteLine("Id: {0} Name: {1} Color: {2}",
product.ProductID, product.Name, product.Color);
}
private static void OnSave(IAsyncResult ar)
{
svc = ar.AsyncState as AdventureWorksEntities;
try
{
WriteResponse(svc.EndSaveChanges(ar));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private static void WriteResponse(DataServiceResponse response)
{
if(response.IsBatchResponse)
{
Console.WriteLine("Batch Response Code: {0}", response.BatchStatusCode);
}
foreach (ChangeOperationResponse change in response)
{
Console.WriteLine("Change code: {0}", change.StatusCode);
if(change.Error != null)
{
Console.WriteLine("\tError: {0}", change.Error.Message);
}
}
}
}