I am having a problem mapping nested lists in an Open ESB BEPL processes.
I am calling a service that returns a object containing a list. One of the parameters in that list is another list. My return object, that I'm mapping to, more or less replicates the structure of the object returned by the service. (I.e. it has a list, one of the parameters of which is a nested list)
I can map the parameters from the first level lists to each other without issue. When I try to map the parameters in the nested list to the nested list in my return object I get a com.sun.xml.transform.sware.TooManyElementsException. Which seems to indicate (from what I can gather) that I'm trying to map a collection into a single variable. (Almost like BPEL is not iterating through the nested list). This is all being done in the same BPEL assign.
Here is my BPEL Code:< assign name="mapGetQuotesOut" >
<!-- this works -->
<copy> <from>$getClientQuotesOut.parameters/ns0:GetClientQuotesResult/ns1:QuotePolicy/ns1:ProductID</from>
<to>$viewCustomerOut.part1/return/quotes/produsctID</to>
</copy>
<!-- this works -->
<copy>
<from>$getClientQuotesOut.parameters/ns0:GetClientQuotesResult/ns1:QuotePolicy/ns1:LeadSourceCode</from>
<to>$viewCustomerOut.part1/return/quotes/leadSourceCode</to>
</copy>
<!-- this causes the error -->
<copy>
<from>$getClientQuotesOut.parameters/ns0:GetClientQuotesResult/ns1:QuotePolicy/ns1:QuoteItems/ns1:QuoteItem/ns1:ItemDesc<<from>
<to>$viewCustomerOut.part1/return/quotes/vehicleQuoteItems/itemDescription</to>
</copy>
<!-- this also causes the error -->
<copy>
<from>$getClientQuotesOut.parameters/ns0:GetClientQuotesResult/ns1:QuotePolicy/ns1:QuoteItems/ns1:QuoteItem/ns1:AgentCode</from>
<to>$viewCustomerOut.part1/return/quotes/vehicleQuoteItems/agentCode<to>
</copy>
</assign>
Any ideas or suggestions?
Mike
You need to perform XSL transformation by using for-each.
Related
I have a use-case that I need to retrieve the value from my properties file but that key should be derived dynamically from my query params.
How to handle this in MEL or Groovy? I am aware it is possible in DW.
Http request
https://localhost:9898/getStore?search=customer.weststore.name
And my placeholders are -
file.properties
customer.weststore.name=TESTING
customer.eaststore.name=IRERRER
So the way I need to access something like this
<set-variable variableName="westDetail" value="#[message.inboundProperites['customer.weststore.name']" doc:name="Variable"/>
<logger message="${westDetail}" level="INFO" /> --> Failed as no placeholder available
When I tried the above it's failing due to no placeholder as "westDetail" available whereas I need the fetch that particular key from the properties file.
This is something related to this article - https://help.mulesoft.com/s/question/0D52T00004mXTQUSA4/dynamically-read-property-values-from-a-properties-file-in-mule but the only solution provided with DW not MEL or Groovy.
How anyone advises, Is it possible?
I understand that the problem is that you want to query the properties by a key that is obtained at execution.
You are doing it incorrectly. ${} is for evaluating the value of a property, which is done at initialization time of the application. You missed that get the actual value in the set-variable.
#[] is for executing a MEL expression, which happens at execution time. flowVars.westDetail is a MEL expression that returns the value of flow variable westDetail. You can't use a MEL expression to evaluate the property placeholder ${}, because they are evaluated at different times.
A solution is to use a Spring bean to store the properties, instead of a configuration properties placeholder. Then you can assign it to a flow variable and access it like a map.
Example:
<spring:beans>
<spring:bean id="myProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<spring:property name="location" value="classpath:items.properties"/>
</spring:bean>
</spring:beans>
<flow name="myFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/" doc:name="HTTP"/>
<set-variable value="#[app.registry.myProperties]" variableName="props"></set-variable>
<logger message="a=#[flowVars.props['a']]" level="INFO"/>
</flow>
items.properties:
a=1
b=2
c=3
Output:
a=1
For elements with multiplicity > 1 (i.e.. where maxOccurs>1 or maxOccurs=unbound), e.g.:
<element name="Name" type="tns:Type" minOccurs="0" maxOccurs="unbound"/>
JAXB generates the following code:
#XmlElement(name = "Name")
protected List<type> name;
Strictly speaking the above schema describes an XML snippet that looks like so:
<Name attr1="a" attr2="x">
<Name attr1="b" attr2="y">
<Name attr1="c" attr2="z">
i.e. a sequence of "Name" elements (and only that!).
When marshalling a Java object to XML the JAXB runtime creates XML, which contains an additional wrapper element around the list, like so:
<Name>
<Name attr1="a" attr2="x">
<Name attr1="b" attr2="y">
<Name attr1="c" attr2="z">
<Name>
By default the wrapping element has the same name as the individual items. Note, that there is no Java class representing that element!
One can overrule the naming to something that makes more sense by manually (!) adding a java-annotation "#XmlElementWrapper" annotation, like so:
#XmlElementWrapper(name = "NameList")
#XmlElement(name = "Name")
protected List<Type> name;
which then yields the following XML:
<NameList>
<Name attr1="a" attr2="x">
<Name attr1="b" attr2="y">
<Name attr1="c" attr2="z">
<NameList>
I agree that such a wrapper element is syntactically nice and makes the XML more readable, BUT there is a severe problem with this: the generated Java code (with or without renaming the wrapper element) generates and expects an XML dialect which - strictly speaking - does not match the original schema anymore! There is no mentioning or any implicit notion of any such wrapper element in the original schema!
The issue only surfaces, if one uses the original schema in different tools (e.g. to create web forms or a different schema-based code generator) and if their result then adheres and/or expects the original XML (i.e. the bare sequence without any wrapper element), while the JAXB-generated code creates and insists on the presence of the wrapper element. Then the two cannot understand each other!
My question thus: how can one instruct JAXB to NOT add/expect said wrapper element while marshalling/unmarshalling XML?
I have searched the web now for quite a while for solutions or work-arounds to this but found nothing! I can't imagine that nobody else before ever stumbled over this and that there seems no other solution to this other problem than to hand-tweak the XML marshalling/unmarshalling code. Any ideas or suggestions to solve this issue?
I am simply using a cftry/cfcatch block for handling any exception. Take this simple exception:
<cftry>
<cfset abc = 1/0>
<cfcatch>
<cfdump var="#cfcatch.getClass().getName()#">
<cfdump var="#isStruct(cfcatch)#">
<cfdump var="#isObject(cfcatch)#">
<cfdump var="#structKeyExists(cfcatch, 'type')#">
</cfcatch>
</cftry>
And the above code's output is like this:
coldfusion.runtime.DivideByZeroException
NO
YES
YES
My question is:
Why structKeyExists is not throwing an error as cfcatch is not of type struct?
And on dumping cfcatch it seems like it is a struct.
Any suggestions.
I think what is confusing you is that you need to remember that ColdFusion is a typeless language.
ColdFusion documentation on data types
Data types
ColdFusion is often referred to as typeless because you do not assign types to variables and ColdFusion does not associate a type with the variable name. However, the data that a variable represents does have a type, and the data type affects how ColdFusion evaluates an expression or function argument. ColdFusion can automatically convert many data types into others when it evaluates expressions. For simple data, such as numbers and strings, the data type is unimportant until the variable is used in an expression or as a function argument.
ColdFusion variable data belongs to one of the following type categories:
Simple One value. Can use directly in ColdFusion expressions. Include numbers, strings, Boolean values, and date-time values.
Binary Raw data, such as the contents of a GIF file or an executable program file.
Complex ** A container for data. Generally represent more than one value. ColdFusion built-in complex data types include arrays, structures, queries, and XML document objects. You cannot use a complex variable, such as an array, directly in a ColdFusion expression, but you can use simple data type elements of a complex variable in an expression. For example, with a one-dimensional array of numbers called myArray, you cannot use the expression myArray * 5. However, you could use an expression myArray3 * 5 to multiply the third element in the array by five.
Objects Complex constructs. Often encapsulate both data and functional operations. The following table lists the types of objects that ColdFusion can use, and identifies the chapters that describe how to use them:
So the code within the <cfcatch> block contains an object that can be referred to as a "structure". By default the name of that structure is cfcatch. You can override that name by specifying the name attribute within the <cfcatch> tag.
The easiest way to see everything that is available to you is to <cfdump> the entire structure within the <cfcatch> block.
<cfcatch>
<cfdump var="#cfcatch#">
</cfcatch>
CFCatch documentation on cfcatch
The cfcatch variables provide the following exception information:
cfcatch variable Content
cfcatch.type Type: Exception type, as specified in cfcatch.
cfcatch.message Message: Exceptions diagnostic message, if provided; otherwise, an empty string; in the cfcatch.message variable.
cfcatch.detail Detailed message from the CFML interpreter or specified in a cfthrow tag. When the exception is generated by ColdFusion (and not cfthrow), the message can contain HTML formatting and can help determine which tag threw the exception.
cfcatch.tagcontext An array of tag context structures, each representing one level of the active tag context at the time of the exception.
cfcatch.NativeErrorCode Applies to type = "database". Native error code associated with exception. Database drivers typically provide error codes to diagnose failing database operations. Default value is -1.
cfcatch.SQLState Applies to type = "database". SQLState associated with exception. Database drivers typically provide error codes to help diagnose failing database operations. Default value is 1.
cfcatch.Sql Applies to type = "database". The SQL statement sent to the data source.
cfcatch.queryError Applies to type ="database". The error message as reported by the database driver.
cfcatch.where Applies to type= "database". If the query uses the cfqueryparam tag, query parameter name-value pairs.
cfcatch.ErrNumber Applies to type = "expression". Internal expression error > number.
cfcatch.MissingFileName Applies to type = "missingInclude". Name of file that could not be included.
cfcatch.LockName Applies to type = "lock". Name of affected lock (if the lock is unnamed, the value is "anonymous").
cfcatch.LockOperation Applies to type = "lock". Operation that failed (Timeout, Create Mutex, or Unknown).
cfcatch.ErrorCode Applies to type = "custom". String error code.
cfcatch.ExtendedInfo Applies to type = "application" and "custom". Custom error message; information that the default exception handler does not display.
(Too long for comments..)
Adding to Miguel-F's comments about CF's "typelessness"... according to the documentation, IsStruct uses the following rules (emphasis mine):
Returns True, if variable is a ColdFusion structure or is a Java
object that implements the java.lang.Map interface. The return value
is False if the object in variable is a user-defined function (UDF).
CFCatch does not meet that criteria. Hence why IsStruct returns false.
If you dump the cfcatch object, and examine the class hierarchy, you will see it is actually implemented as a subclass of java.lang.Exception:
coldfusion.runtime.DivideByZeroException
coldfusion.runtime.ExpressionException
coldfusion.runtime.NeoException
java.lang.RuntimeException
java.lang.Exception
java.lang.Throwable
java.lang.Object
... not coldfusion.runtime.struct ie CF structure:
coldfusion.runtime.Struct
coldfusion.util.FastHashtable
coldfusion.util.CaseInsensitiveMap
java.lang.Object
So as Miguel-F said, though it can be used like a structure (as can most complex object), technically it is not a CF structure, which explains why IsStruct returns false.
As an aside, the reason you can access its properties using dot notation, like with CF structures, is probably because the cfcatch class uses the JavaBean pattern:
ColdFusion can automatically invoke get_PropertyName_() and
set_PropertyName_(value) methods if a Java class conforms to the
JavaBeans pattern. As a result, you can set or get the property by
referencing it directly, without having to explicitly invoke a method.
So for example, you can access the "message" property of cfcatch using:
cfcatch.message
.. instead of invoking its "getter" method for that property:
cfcatch.getMessage()
cfcatch object acts like a struct, but it is not one. This is a special case.
What you can do is make a duplicate of cfcatch object and try isStruct method on it, it will return true.
for example-
<cftry>
<cfset abc = 1/0>
<cfcatch>
<cfset dup = duplicate(cfcatch)>
<cfdump var="#isStruct(dup)#">
<cfdump var="#isStruct(cfcatch)#">
<cfdump var="#isObject(cfcatch)#">
</cfcatch>
</cftry>
The output would be like
YES
NO
YES
My current application is using single instance of an object as a global variable for many of the main components, which I understand is considered inferior to using dependency injection.
I wish to make my applications open source in the future, but first I want to refactor the code to use the most recommended techniques for team collaboration so that other developers will be able to change my source code more easily.
Example of a shared resource: In the CFML language, you have the Server scope, which is shared memory that is available to any request for the entire server instance.
Here is my new design concept for managing changes to the Server scope:
Create a single instance of component named ServerMemoryManager which provides an interface for writing and reading to the server scope.
Any other code that needs to access the server scope will be injected with a reference to the single instance of the ServerMemoryManager via an init() function or a setServerMemoryManager() function.
Whenever a component reads/writes data to the ServerMemoryManager object, it will be able to internally lock the server scope so that no 2 threads can simultaneous write to the same piece of memory in the server scope.
Is this the best way to manage a shared resource (shared memory, filesystem, etc) that requires locking in order to be thread-safe?
Please describe any additional methods that can be used to manage a shared resource that requires locking during certain read/write operations which are considered best practices.
Edit: Based on the accepted answer, instead of locking scope="server", I will use named locks and manage the shared resources with more fine-grained locking. This may allow using multiple objects to manage the shared resources assuming they are all managing different keys in shared memory or files in the filesystem. For example, one application could have its own unique key or directory assigned to it so that it wouldn't conflict with another application trying to change a shared resource.
Edit2: I found I could use a single component named scope.cfc for each scope if I pass the scope into the init function when I create the object. I am now using fine-grained named locks. Let me know if it can be improved. The actual revised code now looks like this (I excluded the code for read, delete, clear). It also doesn't seem that it is required to have a single instance of the scope.cfc component anymore.
<cfcomponent>
<cfscript>
variables.scope=false;
variables.scopeName=false;
</cfscript>
<cffunction name="init" access="public" output="no" returntype="scope">
<cfargument name="scope" type="struct" required="yes">
<cfargument name="scopeName" type="string" required="yes">
<cfscript>
variables.scope=arguments.scope;
variables.scopeName=arguments.scopeName;
return this;
</cfscript>
</cffunction>
<cffunction name="write" access="public" output="no" returntype="boolean">
<cfargument name="key" type="string" required="yes">
<cfargument name="value" type="any" requires="yes">
<cfargument name="timeout" type="numeric" required="no" default="10">
<cftry>
<cflock type="exclusive" name="zcore-#variables.scopeName#-scope-#arguments.key#" timeout="#arguments.timeout#" throwontimeout="yes">
<cfscript>
variables.scope[arguments.key]=arguments.value;
</cfscript>
</cflock>
<cfcatch type="lock"><cfreturn false></cfcatch>
</cftry>
<cfreturn true>
</cffunction>
</cfcomponent>
** Edit3:** I tested the performance of reading from server scope through a component method like this and found it to be 20 times slower then reading the server scope directly when using a read only lock and 4 times slower without a lock. The overhead of an extra function call hundreds or thousands of times per request will be too slow. Tests done on Railo 3.3.x.
I prefer to build a large object in a non-public request and then set a single shared memory scope key then try to write an incomplete object to the scopes. Example:
<cfscript>
ts=structnew();
ts.largeObject=buildLargeObject();
server.cachedObject=ts;
</cfscript>
This lets you avoid locking across the entire application when you only write complete objects to shared memory since updating a single struct key is thread-safe. However, when you build the large object on startup, you need to be sure it is locked until that object is fully created.
I'm going to make the scope variable become directly readable by using the this scope instead of variables scope in the init function to avoid slowing down the application.
CFLOCK only prevents code from executing if every occurrence is locked the same way.
For example:
page1.cfm
<cflock type="exclusive" scope="server" timeout="10" >
<cfset application.xyz = 'abc'>
</cflock>
page2.cfm
<cfset application.xyz = '123'>
Page2.cfm is going to negate any locks you have on page1.cfm if page2 runs the same time page1 does. That said, it's good that you are locking inside your cfc so that each object doesn't have to be locked.
However, locking every occurrence isn't enough. The following won't do much good either.
page1.cfm
<cflock type="exclusive" scope="server" timeout="10" >
<cfset application.xyz = 'abc'>
</cflock>
page2.cfm
<cflock type="exclusive" scope="server" timeout="10" >
<cfset application.xyz = '123'>
</cflock>
This will halt the processing for every request of page1 and page2 but will not protect application.xyz on page1 from changes made to application.xyz on page2. To do this you need to give your locks a "name".
Locks name. Mutually exclusive with the scope attribute. Only one
request can execute the code within a cflocktag with a given name at a
time. Cannot be an empty string.
Permits synchronizing access to resources from different parts of an
application. Lock names are global to a ColdFusion server. They are
shared among applications and user sessions, but not clustered
servers.
Because you are creating multiple instances of your object, I believe serverMemoryManagerObject could interfere with serverMemoryManagerObject2 unless you name your lock.
Here is some more information about locking dos and don'ts
Locking code with cflock
CFLock And Negative Outcomes Think It Through
CFMythbusters - Countering Some Conventional Wisdom
I am creating a folderish type (archetype 1) and I want to have possibility to add only a single object of (archetype 2) to this folder.
You can restrict the addable types inside your folderish type ("archetype 1") to "archetype 2" by amending the "archetypes 1" types definition (profiles/default/archetype1.xml):
<?xml version="1.0"?>
<object name="archetype1">
...
<property name="filter_content_types">True</property>
<property name="allowed_content_types">
<element value="archetype2" />
</property>
...
</object>
Ok, so you want your second type archetype 2 to be addable only once inside archetype 1?
I would do it in such a way that the Add New dropdown on the green edit bar only shows archetype 2 if it can be added (the other solutions here require the user to first render the add form and then be told that this is not allowed).
You need to make sure that your folderish archetype 1 subclasses ConstrainTypesMixin.
I think if you use the folderish content types in Products.ATContentTypes you will automatically subclass this mixin class, but it helps to make sure.
Then, inside archetype 1, add the method: getLocallyAllowedTypes. This method is declared in the ConstrainTypesMixin class in Products/ATContentTypes/lib/constraintypes.py
In this method you can now add the logic to check if an instance of archetype 2 has already been added. If it has, don't return it as one of the locally allowed types. If it hasn't, then return it (with the other types if they exist).
Make sure to first call super() in this method to get the locally added types from the superclass's method.
To understand how this works, you can look at the *_addableTypesInContext* method in the FactoriesSubMenuItem class in plone/app/contentmenu/menu.py to see when and how this getLocallyAllowedTypes method is called.
You are probably best off creating a custom add form (perhaps using z3c.form) and making the placing the restriction there.
You can override the createObject.cpy script and add a check there:
this_type = REQUEST.form.get('type_name')
if this_type == 'MyATContentType':
# MyATContentType needs a special check
ctool = getToolByName(context, 'portal_catalog')
this_path = '/'.join(context.getPhysicalPath())
# Query the Catalog to see we already have an instance of this object here
results = ctool.searchResults({'portal_type': this_type, 'path': this_path})
if results:
context.plone_utils.addPortalMessage(_(
u'Sorry, but there already is an object of type %s here.' % this_type
))
# Redirect to the edit form of the first found object.
cv = results[0]
cv_path = cv.getPath()
return context.REQUEST.RESPONSE.redirect(cv_path + "/edit")
Provide the customized script, together with the associated .metadata file, in the skins/templates folder of your product.
Bonus tip: In Dexterity, you would add this check in dexterity.AddForm.update()