So I want to use the standard format for error messages. I don't want to specify other than default codes.
Example:
domain.property.minSize.notmet=I like purple {?}.
So I am looping through my errors:
domain.errors.fieldErrors.each {
println g.message(error: it, args: ['bunnies'])
}
This doesn't work correctly because I think the first x arguments are already defined because of the default error message, and that number changes depending on what the error is. How can I specify arguments to the standard error codes without struggling to know what number '?' should be?
So I've gone down this road, hopefully there isn't some way easier option. I am overriding the messageSource bean with my own implementation that simply adds a method:
public class MessageSource extends PluginAwareResourceBundleMessageSource implements GrailsApplicationAware, PluginManagerAware, InitializingBean {
public final String getMessage(MessageSourceResolvable resolvable, Object[] args, Locale locale)
throws NoSuchMessageException {
Object[] arguments;
if (args == null) {
arguments = resolvable.getArguments();
} else {
arguments = args;
}
String[] codes = resolvable.getCodes();
if (codes == null) {
codes = new String[0];
}
for (String code : codes) {
String msg = getMessageInternal(code, arguments, locale);
if (msg != null) {
return msg;
}
}
String defaultMessage = resolvable.getDefaultMessage();
if (defaultMessage != null) {
return renderDefaultMessage(defaultMessage, arguments, locale);
}
if (codes.length > 0) {
String fallback = getDefaultMessage(codes[0]);
if (fallback != null) {
return fallback;
}
}
throw new NoSuchMessageException(codes.length > 0 ? codes[codes.length - 1] : null, locale);
}
}
This is really almost an exact copy of one of the other methods, that I just modified to take in arguments. The problem I am having with this is that it never finds my error message, always falling back to default. msg is always null.
Edit: Just tried it with the standard method and the same is true with msg always being null.
Related
I have this as queryparam in my requestmapping:
#QueryParam("isBenchmark") boolean isBenchmark
Now if am passing any String value also it is defaulting it to false. How can I avoid this and throw error if it is anything other than true/false.
Is there any annotations with which I can throw such validations
It is a known issue.
It is converted to boolean using the new Boolean(isBenchmark) So when isBenchmark is true it converts to true, in all other cases it converts to false.
Unfortunately you have to handle it by your self
public void YourMethod(#QueryParam("isBenchmark") String isBenchmark) {
boolean val
if (isBenchmark != null && isBenchmark.equals("true")){
val = true;
} else if (isBenchmark != null && isBenchmark.equals("false")) {
val = false;
} else {
Throw Exception or return a bad request
}
}
We have a situation where the CrmServiceClient class cannot be instantiated, with an 'Object reference not set to an object' error coming from deep within the bowels of the constructor. I've also received a Collection was modified; enumeration operation may not execute error in a few situations.
This does not happen all the time, but we seem to be able to reproduce it when we trigger multiple requests very quickly.
We create the object as follows:
var ctx = new CrmServiceClient(ConfigurationManager.ConnectionStrings["Xrm"].ConnectionString);
The connection string is valid and we have set RequireNewInstance to true
We were originally using the ctx in a using block but we were advised that we shouldn't be disposing of the CrmServiceClient, so we've removed the using block, but this has not resolved the problem.
The stack trace is below - i've only pasted the relevant part. The stack leading up to this point can be any piece of code that attempts to connect to the CRM to retrieve data
at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
at System.Collections.Generic.List`1.Enumerator.MoveNext()
at Microsoft.Xrm.Tooling.Connector.Utilities.GetOrgnameAndOnlineRegionFromServiceUri(Uri serviceUri, String& onlineRegion, String& organizationName, Boolean& isOnPrem)
at Microsoft.Xrm.Tooling.Connector.CrmConnection.SetOrgnameAndOnlineRegion(Uri serviceUri)
at Microsoft.Xrm.Tooling.Connector.CrmConnection..ctor(String serviceUri, String userName, String password, String domain, String homeRealmUri, String authType, String requireNewInstance, String clientId, String redirectUri, String tokenCacheStorePath, String loginPrompt, String certStoreName, String certThumbprint, String skipDiscovery)
at Microsoft.Xrm.Tooling.Connector.CrmConnection..ctor(IDictionary`2 connection)
at Microsoft.Xrm.Tooling.Connector.CrmConnection.Parse(String connectionString)
at Microsoft.Xrm.Tooling.Connector.CrmServiceClient.ConnectToCrmWebService(String crmConnectionString)
at Microsoft.Xrm.Tooling.Connector.CrmServiceClient..ctor(String crmConnectionString)
I believe I've tracked down the issue. I used DotNetPeek to look at the underlying code that was failing. The static method GetOrgnameAndOnlineRegionFromServiceUriwas where the error was occurring.
I tracked it down to a static list (discoSvcs) that was being set to null before the method returns. Other threads that call this method are also trying to do things with this list. It ends up that there is a race condition where one thread could check to see if it isn't null.
The only way I can get around it now is making sure only one CrmServiceClient is being instantiated at any time, by using a lock. This isn't ideal but I am running out of time
Static list definition
namespace Microsoft.Xrm.Tooling.Connector
{
public class Utilities
{
private static CrmOnlineDiscoveryServers discoSvcs;
private static List<string> _autoRetryRetrieveEntityList;
private Utilities()
{
}
Problem Function
The static list variable is checked at the beginning of this function and if it is null, it is populated with some values. It is then used later in the method before being set to null in the finally block.
public static void GetOrgnameAndOnlineRegionFromServiceUri(
Uri serviceUri,
out string onlineRegion,
out string organizationName,
out bool isOnPrem)
{
isOnPrem = false;
onlineRegion = string.Empty;
organizationName = string.Empty;
if (serviceUri.Host.ToUpperInvariant().Contains("DYNAMICS.COM") || serviceUri.Host.ToUpperInvariant().Contains("MICROSOFTDYNAMICS.DE") || (serviceUri.Host.ToUpperInvariant().Contains("MICROSOFTDYNAMICS.US") || serviceUri.Host.ToUpperInvariant().Contains("DYNAMICS-INT.COM")))
{
if (Utilities.discoSvcs == null)
Utilities.discoSvcs = new CrmOnlineDiscoveryServers();
try
{
List<string> stringList = new List<string>((IEnumerable<string>) serviceUri.Host.Split(new string[1]
{
"."
}, StringSplitOptions.RemoveEmptyEntries));
organizationName = stringList[0];
stringList.RemoveAt(0);
StringBuilder stringBuilder = new StringBuilder();
foreach (string str in stringList)
{
if (!str.Equals("api"))
stringBuilder.AppendFormat("{0}.", (object) str);
}
string crmKey = stringBuilder.ToString().TrimEnd('.').TrimEnd('/');
stringBuilder.Clear();
if (!string.IsNullOrEmpty(crmKey))
{
CrmOnlineDiscoveryServer onlineDiscoveryServer = Utilities.discoSvcs.OSDPServers.Where<CrmOnlineDiscoveryServer>((Func<CrmOnlineDiscoveryServer, bool>) (w =>
{
if (w.DiscoveryServer != (Uri) null)
return w.DiscoveryServer.Host.Contains(crmKey);
return false;
})).FirstOrDefault<CrmOnlineDiscoveryServer>();
if (onlineDiscoveryServer != null && !string.IsNullOrEmpty(onlineDiscoveryServer.ShortName))
onlineRegion = onlineDiscoveryServer.ShortName;
}
isOnPrem = false;
}
finally
{
Utilities.discoSvcs.Dispose();
Utilities.discoSvcs = (CrmOnlineDiscoveryServers) null;
}
}
else
{
isOnPrem = true;
if (((IEnumerable<string>) serviceUri.Segments).Count<string>() < 2)
return;
organizationName = serviceUri.Segments[1].TrimEnd('/');
}
}
I have this example code
public static ActionProcessable getActionProcessor(TaskType currentTaskType, UserAction userAction){
String actionKey;
if(userAction != null){
if(currentTaskType != null){
actionKey = buildKey(currentTaskType, userAction);
if(dossierActions.containsKey(actionKey)){
return dossierActions.get(actionKey);
}
}
actionKey = buildKey(anyTaskType(), userAction);
if(dossierActions.containsKey(actionKey)){
return dossierActions.get(actionKey);
}
}
return new NullActionProcessor();
}
In this logic i have a map to store the ActionProcessable by combined-key TaskType and UserAction. This method will return ActionProcessable with input taskType and action. TaskType can be null so in that case we only need to get by userAction.
When i check this code by sonar, it say the third if is "Nested if-else depth is 2 (max allowed is 1)"
But i don't know how to make it better.
Does anyone suggest me something?
You can move "if containsKey" part out of condition to remove code duplication:
public static ActionProcessable getActionProcessor(TaskType currentTaskType, UserAction userAction){
if (userAction != null) {
String actionKey = currentTaskType != null
? buildKey(currentTaskType, userAction)
: buildKey(anyTaskType(), userAction);
if (dossierActions.containsKey(actionKey)){
return dossierActions.get(actionKey);
}
}
return new NullActionProcessor();
}
Now, intent of the code looks more clear (at least, for me).
You can also make the first condition short-circuit and\or use ternary if for containsKey, it will remove even more ifs, but can make code more complex for some people.
public static ActionProcessable getActionProcessor(TaskType currentTaskType, UserAction userAction){
if (userAction == null) {
return new NullActionProcessor();
}
String actionKey = currentTaskType != null
? buildKey(currentTaskType, userAction)
: buildKey(anyTaskType(), userAction);
return dossierActions.containsKey(actionKey)
? dossierActions.get(actionKey);
: new NullActionProcessor();
}
Choose the one you like, they are technically similar.
Since you haven't specified specific programming language, one more thing to say: your code is a good example of use case of null-coalsecing operator. Sadly, AFAIK, there is none in Java. In C#, the code could look like this:
public static ActionProcessable GetActionProcessor(TaskType currentTaskType, UserAction userAction) {
if (userAction == null) {
return new NullActionProcessor();
}
var actionKey = BuildKey(currentTaskType ?? anyTaskType(), userAction);
return dossierActions[actionKey] ?? new NullActionProcessor();
}
Let's say I have function:
void sayHello(String name, String surname);
and I want to be sure that both parameters are valid. Now I'm doing it this way:
if (name == null)
throw new Exception("Name is invalid");
if (surname == null)
throw new Exception("Surname is invalid");
When I'm invoking it with sayHello(null, null); I'm getting only information about invalid name.
Is there a clean way to be warned about two errors at once? By clean, I mean without two flags (or more in case of more arguments) and many if statements?
The snippets are in Java but I'm rather asking for a generic design solution.
I would suggest to build error message with each validation but throw once i.e. after all validations are done.
Eg:
void someFunction(String param1, String param2, String param3) {
String error = "";
if (invalid(param1)) {
error += "param1 is invalid";
}
if (invalid(param2)) {
error += "param2 is invalid";
}
if (invalid(param3)) {
error += "param3 is invalid";
}
if (!error.equals("")) {
throw new Exception(error);
}
}
I am trying to implement routing slip (EI Pattern) using Spring integration. The configuration I have done is
#Bean
#Transformer(inputChannel = "routingServiceChannel")
public HeaderEnricher headerEnricher() {
return new HeaderEnricher(Collections.singletonMap(IntegrationMessageHeaderAccessor.ROUTING_SLIP,
new RoutingSlipHeaderValueMessageProcessor("routingChannel2",
"routingChannel1")));
}
So when it reaches routingServiceChannel, it goes to routingChannel2 and then routingChannel1. But in my case it always throws an exception that it does not have a reply channel. when I set output channel, like
#Transformer(inputChannel = "routingServiceChannel", outputChannel=""xyzChannel)
Then then routing happens to xyzChannel instead of going to routingChannel2, and routingChannel1.
When I debugged the code in spring integration core, I stumbled with this code,
In
class AbstractReplyProducingMessageHandler
protected final void handleMessageInternal(Message<?> message) {
Object result;
if (this.advisedRequestHandler == null) {
result = handleRequestMessage(message);
} else {
result = doInvokeAdvisedRequestHandler(message);
}
if (result != null) {
sendOutputs(result, message);
} else if (this.requiresReply) {
throw new ReplyRequiredException(message, "No reply produced by handler '" + getComponentName()
+ "', and its 'requiresReply' property is set to true.");
} else if (logger.isDebugEnabled()) {
logger.debug("handler '" + this + "' produced no reply for request Message: " + message);
}
}
Here in handle message method they obtain the routingSlip map and assigning it to the result.
And
protected void produceOutput(Object reply, Message<?> requestMessage) {
MessageHeaders requestHeaders = requestMessage.getHeaders();
Object replyChannel = null;
if (getOutputChannel() == null) {
Map<?, ?> routingSlipHeader = requestHeaders.get(IntegrationMessageHeaderAccessor.ROUTING_SLIP, Map.class);
if (routingSlipHeader != null) {
Assert.isTrue(routingSlipHeader.size() == 1, "The RoutingSlip header value must be a SingletonMap");
Object key = routingSlipHeader.keySet().iterator().next();
Object value = routingSlipHeader.values().iterator().next();
Assert.isInstanceOf(List.class, key, "The RoutingSlip key must be List");
Assert.isInstanceOf(Integer.class, value, "The RoutingSlip value must be Integer");
List<?> routingSlip = (List<?>) key;
AtomicInteger routingSlipIndex = new AtomicInteger((Integer) value);
replyChannel = getOutputChannelFromRoutingSlip(reply, requestMessage, routingSlip, routingSlipIndex);
if (replyChannel != null) {
// TODO Migrate to the SF MessageBuilder
AbstractIntegrationMessageBuilder<?> builder = null;
if (reply instanceof Message) {
builder = this.getMessageBuilderFactory().fromMessage((Message<?>) reply);
} else if (reply instanceof AbstractIntegrationMessageBuilder) {
builder = (AbstractIntegrationMessageBuilder<?>) reply;
} else {
builder = this.getMessageBuilderFactory().withPayload(reply);
}
builder.setHeader(IntegrationMessageHeaderAccessor.ROUTING_SLIP,
Collections.singletonMap(routingSlip, routingSlipIndex.get()));
reply = builder;
}
}
if (replyChannel == null) {
replyChannel = requestHeaders.getReplyChannel();
}
}
Message<?> replyMessage = createOutputMessage(reply, requestHeaders);
sendOutput(replyMessage, replyChannel);
}
Instead of getting the routingSlip configuration from the reply, they are trying to get from the requestMessage.
Am I missing something here? Are there any additional configuration that I need to set?
Thank you for the attention to the subject, BTW! :)
Everything looks good, but you have missed the point of the Routing Slip.
First of all you should configure it for the message. And since Routing Slip is a header you should use HeaderEnricher to add it to the headers of the message.
The routing is really caused in the downstream from and exactly for the requestMessage, not the reply. The Routing Slip is out of HeaderEnricher.
Although it may happen for the HeaderEnricher's requestMessage, of course.
If you would like to consult Routing Slip exactly after the HeaderEnricher, you should configure something like:
#BridgeTo
#Bean
public MessageChannel xyzChannel() {
return new DirectChannel();
}
Note: no one new header is available during HeaderEnricher logic. Only in the downstream. And Routing Slip is one of them.