Saturday, June 30, 2018
Immigration Rallies
I can see how the average Trump supporter would view today's rallies as the product of uninformed liberals calling for open borders and lawlessness that will eventually lead to the demise of our country as we are overrun by people fleeing dysfunctional countries south of the border who will eventually deplete our financial and social reserves. I can see how the average anti-Trump supporter would view the events leading up to today's rallies as the product of uninformed conservatives forgetting what makes this country great, up to and including how the struggle to make it in America contributes to our very fabric, GDP and overall wealth and well being. To me, both points of view are correct and incorrect. We can't be completely open and we can't be completely closed. That being said, I think the more essential leit motif of today's rallies is that, either way, we cannot afford to lose our humanity as we implement the policy at hand. Whether we are open or closed, we have to remain uniquely 'American' in our ways.
Saturday, June 2, 2018
Suburban Shrimp Scampi
I think I’ve stumbled on to a near perfect Shrimp Scampi recipe for the average suburbanite, who, additionally, likes to avoid garlic and onions.
Here are the ingredients:
2 pounds of peeled and deveined medium shrimp. Of course, if you are a big fan of manual labor, you can peel and devein them yourself, but I would encourage you to research both comparative advantage and opportunity cost first.
2 cups of Pinot Grigio. There is no need for presumption here. Just buy any brand that comes from the Venice, Italy area in a large, 1.5L bottle for less than $10.
4 table spoons of salted butter
1/2 large (6g) Knorr chicken bouillon cube. Of course, you can use any brand.
1 cup of Italian parsley. This would be just the tops. When I say 1 cup, I mean if you lightly pat the leaves down. If you insist on pushing the leaves down with your foot, I am sure you could compress an entire bushel in a cup, but this is not my intent.
The juice from 1/2 lemon
In a large, wide bottomed pot over low to medium heat, combine the Pinot Grigio, lemon juice, butter, parsley and bouillon cube, and then let simmer until the very nearly all of the liquid has evaporated. Imagine you have an untreated urinary tract infection that has been festering for a few weeks, and then you take the darkest, thickest piss you’ve ever seen. When the ingredients in question here approximate that color and consistency, you are ready to move to the next step (and go to the ER).
Most recipes counsel you to cook shrimp over medium to high heat for 6 minutes, but, unless you have a centrifuge that you can use to drain the water from your shrimp, I find that it is better to simmer the shrimp, uncovered, for a longer period of time.
Thus, add the shrimp to the reduction and simmer over low-to-medium heat (i.e. the same level you used to create the reduction) uncovered for about 20 minutes or until the shrimp scampi has a reasonable amount of liquid, but not too much.
Enjoy :-)
Tuesday, May 29, 2018
Cracks In The Paint
When I worked at Boeing Helicopters, I recall talking to an Engineer on the shop floor about a special paint that they used on the CH-47 (Chinook). The paint would bond to the underlying frame at a molecular level, to the point where a fracture deep within the frame would manifest itself as a crack in the paint, thereby providing all those involved with a clear indication that the frame needed repair. Rosanne Barr is the crack in the paint. We should be thankful for her signal, even as we detest her.
Wednesday, May 23, 2018
Truth
If one endeavors to speak the truth, then one must know what the truth is, and this goes far beyond the simple truths. It is one thing to know if you are lying by commission or omission. It is another thing to understand how you feel, recognize a situation for what it is, and speak the truth without undue friction. Whether you are dealing with a relative, a friend or a coworker, and whether you are grappling with how you feel about them or how they feel about you, you might not really know what the truth (your truth) is. And even if you do, is the ugly truth better than a polite lie that might smooth things over? I’ve seen depictions of how a succession of truths turns out to be disastrous (Everybody Loves Raymond) as well as depictions of how a succession of lies turns out to be equally disastrous (Seinfeld). To the extent that it is not always practical to prioritize authenticity over expediency, I wonder if it might be better to say nothing at all, rather than to fabricate an insidious lie or deliver an explosive truth. With regard to this particular question, I would accept either an honest or a polite answer, and that’s not the truth.
x
Tuesday, May 15, 2018
Salesforce: Apex: Generate from WSDL
Problem
.
When trying to generate Apex from a WSDL in Salesforce, you have to do a few things to make the WSDL suitable for use with the OOTB 'Generate from WSDL' option. It is possible that the Open Source WSDL2Apex Generator (here) does not require similar preprocessing, but, as of this writing, I have not tried it, so I do not know. In this post, I am only going to focus on the two actions that I had to take to get a WSDL into a suitable form, but I am relatively certain that this is only a small subset of what one might have to do along the spectrum of WSDLs..
Solution
.
Step 1: Inline the Imports
.
Let's say you have a WSDL that looks something like this:
.
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="ServiceName" targetNamespace="http://[domain]/[namespace]" xmlns:tns="http://[domain]/[namespace]" [...etc...]>
<types>
<xsd:schema>
<xsd:import schemaLocation="https://[domain]/[schema]" namespace="http://[domain]/[namespace]"/>
</xsd:schema>
</types>
<message name="SomeMessage">
<part name="parameters" element="tns:SomeMessage"/>
</message>
<portType name="ServiceName">
<operation name="SomeMessage">
<input message="tns:SomeMessage" wsam:Action="http://[domain]/[namespace]/[method]"/>
<output message="tns:SomeMessageResponse" wsam:Action="http://[domain]/[namespace]/[method]"/>
<fault name="ServiceException" message="tns:ServiceException" wsam:Action="http://[domain]/[namespace]/[method]/fault/ServiceException"/>
</operation>
<xs:complexType name="ServiceException">
<xs:sequence>
<xs:element name="errorCode" type="xs:int"/>
<xs:element name="message" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
[...etc...]
</definitions>
<definitions name="ServiceName" targetNamespace="http://[domain]/[namespace]" xmlns:tns="http://[domain]/[namespace]" [...etc...]>
<types>
<xsd:schema>
<xsd:import schemaLocation="https://[domain]/[schema]" namespace="http://[domain]/[namespace]"/>
</xsd:schema>
</types>
<message name="SomeMessage">
<part name="parameters" element="tns:SomeMessage"/>
</message>
<portType name="ServiceName">
<operation name="SomeMessage">
<input message="tns:SomeMessage" wsam:Action="http://[domain]/[namespace]/[method]"/>
<output message="tns:SomeMessageResponse" wsam:Action="http://[domain]/[namespace]/[method]"/>
<fault name="ServiceException" message="tns:ServiceException" wsam:Action="http://[domain]/[namespace]/[method]/fault/ServiceException"/>
</operation>
<xs:complexType name="ServiceException">
<xs:sequence>
<xs:element name="errorCode" type="xs:int"/>
<xs:element name="message" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
[...etc...]
</definitions>
.
The 'xsd:import' is not supported, so you have to actually inline the related schema into this WSDL, which we will refer to as the 'Consolidated_WSDL', for clarity.
.
Let's say that related schema looks something like this:
.
<?xml version='1.0' encoding='UTF-8'?><xs:schema xmlns:tns="http://[domain]/[namespace_1]" version="1.0" targetNamespace="http://[domain]/[namespace_1]">
<xs:import namespace="http://[domain]/[namespace_2" schemaLocation="https://[domain]/[namespace_2]"/>
<xs:import namespace="http://[domain]/[namespace_3" schemaLocation="https://[domain]/[namespace_3]"/>
<xs:element name="SomeException" type="tns:SomeException]"/>
<xs:element name="SomeService" type="tns:SomeService"/>
[...etc...]
</xs:schema>
.
You would inline this schema by replacing the entire <xsd:import> block in the Consolidated_WSDL with just the <schema> block from this file, as follows, in blue:
.
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="ServiceName" targetNamespace="http://[domain]/[namespace]" xmlns:tns="http://[domain]/[namespace]" [...etc...]>
<types>
<xs:schema xmlns:tns="http://[domain]/[namespace_1]" version="1.0" targetNamespace="http://[domain]/[namespace_1]">
<xs:import namespace="http://[domain]/[namespace_2" schemaLocation="https://[domain]/[namespace_2]"/>
<xs:import namespace="http://[domain]/[namespace_3" schemaLocation="https://[domain]/[namespace_3]"/>
<xs:element name="SomeException" type="tns:SomeException]"/>
<xs:element name="SomeService" type="tns:SomeService"/>
[...etc...]
</xs:schema> </types>
<message name="SomeMessage">
<part name="parameters" element="tns:SomeMessage"/>
</message>
<portType name="ServiceName">
<operation name="SomeMessage">
<input message="tns:SomeMessage" wsam:Action="http://[domain]/[namespace]/[method]"/>
<output message="tns:SomeMessageResponse" wsam:Action="http://[domain]/[namespace]/[method]"/>
<fault name="ServiceException" message="tns:ServiceException" wsam:Action="http://[domain]/[namespace]/[method]/fault/ServiceException"/>
</operation>
<xs:complexType name="ServiceException">
<xs:sequence>
<xs:element name="errorCode" type="xs:int"/>
<xs:element name="message" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
[...etc...]
</definitions>
<definitions name="ServiceName" targetNamespace="http://[domain]/[namespace]" xmlns:tns="http://[domain]/[namespace]" [...etc...]>
<types>
<xs:schema xmlns:tns="http://[domain]/[namespace_1]" version="1.0" targetNamespace="http://[domain]/[namespace_1]">
<xs:import namespace="http://[domain]/[namespace_2" schemaLocation="https://[domain]/[namespace_2]"/>
<xs:import namespace="http://[domain]/[namespace_3" schemaLocation="https://[domain]/[namespace_3]"/>
<xs:element name="SomeException" type="tns:SomeException]"/>
<xs:element name="SomeService" type="tns:SomeService"/>
[...etc...]
</xs:schema> </types>
<message name="SomeMessage">
<part name="parameters" element="tns:SomeMessage"/>
</message>
<portType name="ServiceName">
<operation name="SomeMessage">
<input message="tns:SomeMessage" wsam:Action="http://[domain]/[namespace]/[method]"/>
<output message="tns:SomeMessageResponse" wsam:Action="http://[domain]/[namespace]/[method]"/>
<fault name="ServiceException" message="tns:ServiceException" wsam:Action="http://[domain]/[namespace]/[method]/fault/ServiceException"/>
</operation>
<xs:complexType name="ServiceException">
<xs:sequence>
<xs:element name="errorCode" type="xs:int"/>
<xs:element name="message" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
[...etc...]
</definitions>
.
You may have noticed the additional 'xs:import' elements in the schema that we just inlined. These would have to be inlined as well. You would simply navigate to the schema location for each import, and then copy-paste the <schema> block for each import as peers to the schema we just copy-pasted, and remove the import elements, as follows, with the new schemas in bold-blue, and the removed import elements in strikethrough (e.g. strikethrough):
.
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="ServiceName" targetNamespace="http://[domain]/[namespace]" xmlns:tns="http://[domain]/[namespace]" [...etc...]>
<types>
<xs:schema xmlns:tns="http://[domain]/[namespace_1]" version="1.0" targetNamespace="http://[domain]/[namespace_1]">
<xs:import namespace="http://[domain]/[namespace_2" schemaLocation="https://[domain]/[namespace_2]"/>
<xs:import namespace="http://[domain]/[namespace_3" schemaLocation="https://[domain]/[namespace_3]"/>
<xs:element name="SomeException" type="tns:SomeException]"/>
<xs:element name="SomeService" type="tns:SomeService"/>
[...etc...]
</xs:schema> <xs:schema xmlns:tns="http://[domain]/[namespace_2]" version="1.0" targetNamespace="http://[domain]/[namespace_2]">
[...etc...]
</xs:schema>
<definitions name="ServiceName" targetNamespace="http://[domain]/[namespace]" xmlns:tns="http://[domain]/[namespace]" [...etc...]>
<types>
<xs:schema xmlns:tns="http://[domain]/[namespace_1]" version="1.0" targetNamespace="http://[domain]/[namespace_1]">
<xs:element name="SomeException" type="tns:SomeException]"/>
<xs:element name="SomeService" type="tns:SomeService"/>
[...etc...]
</xs:schema> <xs:schema xmlns:tns="http://[domain]/[namespace_2]" version="1.0" targetNamespace="http://[domain]/[namespace_2]">
[...etc...]
</xs:schema>
<xs:schema xmlns:tns="http://[domain]/[namespace_3]" version="1.0" targetNamespace="http://[domain]/[namespace_3]">
[...etc...]
</xs:schema>
[...etc...]
</xs:schema>
</types>
<message name="SomeMessage">
<part name="parameters" element="tns:SomeMessage"/>
</message>
<portType name="ServiceName">
<operation name="SomeMessage">
<input message="tns:SomeMessage" wsam:Action="http://[domain]/[namespace]/[method]"/>
<output message="tns:SomeMessageResponse" wsam:Action="http://[domain]/[namespace]/[method]"/>
<fault name="ServiceException" message="tns:ServiceException" wsam:Action="http://[domain]/[namespace]/[method]/fault/ServiceException"/>
</operation>
<xs:complexType name="ServiceException">
<xs:sequence>
<xs:element name="errorCode" type="xs:int"/>
<xs:element name="message" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
[...etc...]
</definitions>
<message name="SomeMessage">
<part name="parameters" element="tns:SomeMessage"/>
</message>
<portType name="ServiceName">
<operation name="SomeMessage">
<input message="tns:SomeMessage" wsam:Action="http://[domain]/[namespace]/[method]"/>
<output message="tns:SomeMessageResponse" wsam:Action="http://[domain]/[namespace]/[method]"/>
<fault name="ServiceException" message="tns:ServiceException" wsam:Action="http://[domain]/[namespace]/[method]/fault/ServiceException"/>
</operation>
<xs:complexType name="ServiceException">
<xs:sequence>
<xs:element name="errorCode" type="xs:int"/>
<xs:element name="message" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
[...etc...]
</definitions>
.
You need not get trapped in recursion during this process ;-)
.
If, for example, the schema for namespace_3 imported namespace_2, then you can rely on the already copy-pasted namespace_2 in the Consolidated_WSDL.
.
Step 2: Take Exception with 'Exception'
.
The Apex compiler does not like it when a class ends with the keyword 'Exception' unless it extends the Exception Class. In the example above, you will notice the 'ServiceException' complex type, element, fault, etc. This would need to be renamed in an identifiable way, so that you can locate the renamed artifacts in the generated Apex later (see below). I simply appeneded 'WSDL' to the end of all such 'Exception' references in a rather large WSDL, taking care to replace "ServiceException" with "ServiceExceptionWSDL" and "tns:ServiceException" with "tns:ServiceExceptionWSDL", etc. Take care to be very specific about your find-and-replace operations, so as not to accidentially replace an 'Exception' reference in a URL. I suggest you use fully double-quoted strings in your find-and-replace logic, so that you avoid URLs altogether.
.
The final Consolidated_WSDL would look something like this:
.
<?xml version="1.0" encoding="UTF-8"?>
<definitions name="ServiceName" targetNamespace="http://[domain]/[namespace]" xmlns:tns="http://[domain]/[namespace]" [...etc...]>
<types>
<xs:schema xmlns:tns="http://[domain]/[namespace_1]" version="1.0" targetNamespace="http://[domain]/[namespace_1]">
<xs:element name="SomeExceptionWSDL" type="tns:SomeExceptionWSDL]"/>
<xs:element name="SomeService" type="tns:SomeService"/>
[...etc...]
</xs:schema>
<xs:schema xmlns:tns="http://[domain]/[namespace_2]" version="1.0" targetNamespace="http://[domain]/[namespace_2]">
[...etc...]
</xs:schema>
<definitions name="ServiceName" targetNamespace="http://[domain]/[namespace]" xmlns:tns="http://[domain]/[namespace]" [...etc...]>
<types>
<xs:schema xmlns:tns="http://[domain]/[namespace_1]" version="1.0" targetNamespace="http://[domain]/[namespace_1]">
<xs:element name="SomeExceptionWSDL" type="tns:SomeExceptionWSDL]"/>
<xs:element name="SomeService" type="tns:SomeService"/>
[...etc...]
</xs:schema>
<xs:schema xmlns:tns="http://[domain]/[namespace_2]" version="1.0" targetNamespace="http://[domain]/[namespace_2]">
[...etc...]
</xs:schema>
<xs:schema xmlns:tns="http://[domain]/[namespace_3]" version="1.0" targetNamespace="http://[domain]/[namespace_3]">
[...etc...]
</xs:schema>
[...etc...]
</xs:schema>
</types>
<message name="SomeMessage">
<part name="parameters" element="tns:SomeMessage"/>
</message>
<portType name="ServiceName">
<operation name="SomeMessage">
<input message="tns:SomeMessage" wsam:Action="http://[domain]/[namespace]/[method]"/>
<output message="tns:SomeMessageResponse" wsam:Action="http://[domain]/[namespace]/[method]"/>
<fault name="ServiceExceptionWSDL" message="tns:ServiceExceptionWSDL" wsam:Action="http://[domain]/[namespace]/[method]/fault/ServiceException"/>
</operation>
<xs:complexType name="ServiceExceptionWSDL">
<xs:sequence>
<xs:element name="errorCode" type="xs:int"/>
<xs:element name="message" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
[...etc...]
</definitions>
.
<message name="SomeMessage">
<part name="parameters" element="tns:SomeMessage"/>
</message>
<portType name="ServiceName">
<operation name="SomeMessage">
<input message="tns:SomeMessage" wsam:Action="http://[domain]/[namespace]/[method]"/>
<output message="tns:SomeMessageResponse" wsam:Action="http://[domain]/[namespace]/[method]"/>
<fault name="ServiceExceptionWSDL" message="tns:ServiceExceptionWSDL" wsam:Action="http://[domain]/[namespace]/[method]/fault/ServiceException"/>
</operation>
<xs:complexType name="ServiceExceptionWSDL">
<xs:sequence>
<xs:element name="errorCode" type="xs:int"/>
<xs:element name="message" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
[...etc...]
</definitions>
.
Generate from WSDL
.
When you generate new Apex code from the WSDL, you will be given the opportunity choose the same Apex class name for all inlined namespaces, or name them differently. Whatever you do, I suggest you pick a short name or names, just based on my experience of rather lengthy names in the WSDL that got truncated when I just accepted the defaults.
.
After you generate the Apex, you will need to refactor any 'Exception' classes and references to back to the original name, so that the final Apex conforms with the service contract. In the example we've been using so far, the ServiceExeption complex type renamed to ServiceExceptionWSDL would result in an Apex class that looks something like this:
.
public Integer errorCode;
public String message;
[...etc...]
.
After you generate the Apex, you will need to refactor any 'Exception' classes and references to back to the original name, so that the final Apex conforms with the service contract. In the example we've been using so far, the ServiceExeption complex type renamed to ServiceExceptionWSDL would result in an Apex class that looks something like this:
.
public class ServiceExceptionWSDL {
public Integer errorCode;
public String message;
[...etc...]
public Integer errorCode;
public String message;
[...etc...]
}
.
You need only remove whatever suffix (or prefix, or whatever) you added to the name (in this case, 'WSDL') and have the class extend the 'Exception' interface, as follows:
.
public class ServiceException extends Exception {public Integer errorCode;
public String message;
[...etc...]
}
.
In my particular case, I replaced 100s of references to ServiceException with ServiceExceptionWSDL in my Consolidated_WSDL, but all of those references amounted to a single, generated Apex class, so the refactoring was easy. Your mileage may vary.
.
In my particular case, I replaced 100s of references to ServiceException with ServiceExceptionWSDL in my Consolidated_WSDL, but all of those references amounted to a single, generated Apex class, so the refactoring was easy. Your mileage may vary.
.
References
.
Mr. Brent Schreibfeder, a Salesforce colleague, who graciously helped me with my general lack of understanding of WSDL structure and the process to inline imports.
.
.
Monday, May 14, 2018
Run with What You Brung
Today I had an experience that reminded me of one of Tony the Tenor's sayings: "Run with what you brung". It was a phrase originally pertaining to race cars - i.e. however it shakes out on race day, just race it - but he ported it over to singing, and used it as a way to counter the ever-present feeling that a singer has when it comes time to perform - i.e. that they are sub-par and not ready. In other words, just get into performance mode and deliver, and just let the voice do what the voice will do. You can't control everything... but you can control your thoughts.
Mother’s Day 2018
We judge our mothers by what we can remember, so I am struck by the wealth of love and attention I never committed to memory, just by the wealth of love and attention I see Val give to Nicholas every day. I think to myself, “did I come into the world that way? was my first caress like that? was I that helpless baby that cried in the night? was my only salvation in my mother’s arms? was I that toddler who needed constant company and supervision? was the totality of my experience so totally influenced by my mother?” The answer is yes, but it seems that appreciating it is a generational thing. My love and gratitude for Val grows each day, but even more so for the Mothers in my life, on Mother’s Day.
Subscribe to:
Posts (Atom)