MKNetworkKit - Host Name and apiPath parameters - ios

I was thinking of using MKNetworkKit as base for Network operations for an iOS App. I'm a bit confused about using the initWithHostName:customerHeaders: and initWithHostName: apiPath:customerHeaders: methods.
In the App, I need to communicate to a number of hosts and they have different ways of specifying the Host Name and URL. For example:
HostNameX.com - The Domain Name for HostX,
The first host has the service prepended to the Hostname as so:
serviceA.HostNameX.com?someparam=value The Path for ServiceA (returns info)
serviceB.HostNameX.com?someparam=value The Path for ServiceB (returns info)
HostNameY.com - The Domain Name for HostY
The second host has the service or command appended to the Hostname as so:
HostNameY.com/serviceA?someparam =value The Path for ServiceA (returns info)
HostNameY.com/serviceB?someparam =value The Path for ServiceB (returns info)
For the HostNameY.com case, I was thinking of creating one MKEngine Instance and then passing in the "serviceA?someparam=value" or "serviceB?someparam=value" string as the Path parameter to the operationWithPath:params:httpMethod:ssl: method.
This would work well for what I want to do, however for HostNameX.com I'm not sure how to prepend "serviceA." or "serviceB." to the host name? The only way I can see of doing it is to create two separate MKEngine Instances one for "serviceA" and one for "serviceB". Is this the case?
Am I missing something or is there a way to be able to prepend the service to the domain name after calling initWithHostName:apiPath:customerHeaders: ?
Thanks in advance for any suggestions.
All the Best
Dave

For HostNameY.com, you are right. The service name can be part of the path.
And as you mentioned, you should use multiple instances of MKEngine to manage HostNameX.com.
Why you should use multiple instances :
Hostname is a private property of MKNetworkEngine and the only way to change the hostname is to create a new instance of MKNetworkEngine (without modifying MKNetworkEngine). Hostname property is used by MKNetworkEngine to observe Reachability changes and freeze/restore operations. If you change the hostname at runtime for a single instance of MKNetworkEngine (by making hostname property public for example), this feature won't work well on all situations. Just take a look at freezeOperations (called when you loose network) method in MKNetworkEngine.m. It checks if and operation url contains the current hostname. If you have changed the hostname and the operation was created for another host, the operation will not be archived to restore it later when the network is back.

I solved this problem by using the operationWithURLString and building my own URL String. To me anyway, this seems a much better solution than allocating a number of MKEngine Instances just to handle something that can be passed as a parameter. This way I can also append path components as well as parameters to the URL String, for example:
http://serviceA.hostname.com/fred/simmons?isvip=true&hasBooked=false
Interestingly, the parameter dictionary that is passed to operationWithURLString:params:httpMethod: works in two ways:
if the httpMethod is GET, then the dictionary is used to pass parameters in the URL, if the httpMethod is POST or PUT (or DELETE?) then the Dictionary is formatted and sent as the Request Body.
Question - is it valid to have a POST Command with parameters?
For example:
http://bookingservice.hostname.com/bookings?isvip=true&lastname=simmons
Is this a valid URL as a POST not a GET?

Related

Zf2 Redis Adapter, getItems using wildcards

I'm making my first steps in using Redis under ZF2.
I was wondering if there is a method to retrieve keys by pattern.
e.g.:
after setting multiple values with keys like: 'stackOverflow_'.time(), i would like to retrieve later all keys matching the 'stackOverflow_' pattern.
tried using getItems(array $keys) with wildcard in: \vendor\zendframework\zendframework\library\Zend\Cache\Storage\Adapter\AbstractAdapter.php
$redisKeyPattern = 'stackOverflow_';
$redis = $this->getServiceLocator()->get('Redis');
$values = $redis->getItems(array($redisKeyPattern.'*'));
with no succces.
any ideas?
UDPATE:
thanks guys. i ended up with duplicating the Redis adapter and adding my own functionality that utilizes the 'keys' function in the Redis extension:
public function getItemsByKeyPattern($pattern) {
$keys = $this->getRedisResource()->keys('*'.$pattern.'*');
if(empty($keys)) return null;
foreach($keys as &$key){
$key = explode(':', $key)[1];
}
$items = parent::getItems($keys);
return $items;
}
and it works for me :)
sadly to say there is no method present to return items with a wildcard, also redis don't support namespaces for stored items.
you need to define each item you want to receive, maybe you should look at a implementation like this
$receiveRedisKeys = [];
foreach($resultSet as $result)
{
$receiveRedisKeys[] = 'predefined_prefix_' . $result->getId();
}
$redisCacheResultSet = $redis->getItems($receiveRedisKeys);
i know that someone on github made a new repository where he modified redis to allow namespaces but this requires that you build the redis binarys by yourself from source. this leeds to a redis version you can't update anymore over apt-get
It's not possible, but there are some alternatives.
One idea is to keep a set with the keys you are interested in. That is the most common approach to this problem: each time you create one of the keys you will want to retrieve later, you add its name to a set. Then when you need to operate on one of those keys, you can grab it from the set. Read this article to get a general idea about this approach.
Another idea is to use the SCAN command to walk the keyspace with the pattern you are using, and as a second step retrieve the values with MGET followed by the keys you collected. This approach is good for administrative processes, but not as something that should be included in an application because the performance will be worse than that of the first idea. More about SCAN.
Finally, an option that is not recommended but I'm listing it just for completeness is to use the KEYS command to collect the keys you want, then proceed to get the values with MGET, as in the SCAN approach. This is not recommended as KEYS shouldn't be used in production environments. More about KEYS.

Can I manually apply Grails routing logic to a String containing a URL?

At runtime, my app will be provided receive a String that may be a valid URL that my app serves (per UrlMappings.groovy), or it may not. I'd like to determine which is the case.
Is there a way for me to apply Grails routing logic manually to a URL, and see what controller/params (if any) it maps to?
Just to be clear, let's say my UrlMappings are:
"/path/one" (controller:"api", action:"one")
"/path/two" (controller:"api", action:"two")
"/variable/$segment/1" (controller:"api", action:"var")
Now my app receives a string at runtime with the value "/path/fake" -- can I test "/path/fake" against the list of all known routes to determine that it's not a match? (Or alternatively, can I test "/variable/segA/1" and determine that it's associated with the "var" action of my API controller?"
Note: I'm looking for a solution that will work for paths with variables, etc -- and will populate a params array with those variables.
Check whether the mapping is present from the list of mappings available in UrlMappings using grailsApplication which can be injected easily in artefacts like controller/service.
def allMappings = grailsApplication.allClasses
.find{it.name == "UrlMappings"}.mappings.urlMappings
assert '/path/one' == allMappings.find{it.toString() == "/path/one"}?.toString()
assert !allMappings.find{it.toString() == "/path/fake"}?.toString()

SWFAddress used to change INDIVIDUAL params in the url

I am using SWFAddress in actionscript 3 to control urls for navigation and controls, and while I am able to target and change specific parameters, I feel like I am missing a cleaner and more consistent way of handling it, perhaps even a feature or method I am not aware of.
Say I have a url and I want to change just the second param of def to xyz.
http://localhost/some-page/#/?param1=abc&param2=def&param3=ghi changed to
http://localhost/some-page/#/?param1=abc&param2=xyz&param3=ghi
I currently am doing:
if (SWFAddress.getParameterNames().indexOf("param2") >= 0) {
SWFAddress.setValue(SWFAddress.getPath() + "?"
+ SWFAddress.getQueryString().replace("param2=" + SWFAddress.getParameter("param2"), "param2=xyz"))
Essentially, checking if the param exists, checking what its current value is, then recreating the whole url using base, '?", and query, making sure I replace the the parameter and the parameter's value, making sure I don't miss the equal sign. This get's sloppy, and is error prone if the param exists but is not set to anything, or whether or not there is an equal sign, and a host of other pitfalls.
So, I can not just tell SWFAddress to update that one parameter in the url? A theoretical function of SWFAddress.setParam("param2, "xyz").
Has anyone coded their own method to micro-manipulate SWFAddress and the url, beyond the single function they supply you with of setValue(val:String)?
I think the short answer is no. According to the documentation there is no setParameter to go with the getParameter method. Looking at the code, it seems that the URL is not cached as a property in the class and therefore cannot be manipulated other than via the setValue method which, of course, updates the URL in the browser.
Presumably you're already parsing the URL in your onChange event so you can use the values to set your application state? If so, you shouldn't need to do so again when you come to rebuild the URL prior to updating it from Flash. If you store the deep-link properties on a Model class somewhere you can handle the defaulting, updating, and error checking without needing to resort to String manipulation. You would then rebuild the URL using those properties, a process you could abstract into a method in your Model class if required.
You should also note that the following line is not particularly robust since it will return true for properties such as param22 and sparam2:
if (SWFAddress.getParameterNames().indexOf("param2") >= 0) { }

A way to exclude self from Bonjour search results

When the same app acts as a Bonjour-enabled service and client at the same time, browsing for self-like services while listening on a socket, what's a good way to exclude self from service search results?
In your NSNetServiceBrowserDelegate you can just ask the incoming service if it is the same as the one you have published:
-(void)netServiceBrowser:(NSNetServiceBrowser *)netServiceBrowser didFindService:(NSNetService *)netService moreComing:(BOOL)moreComing
{
if ([netService isEqual:self.publishedNetService])
return;
…
}
In the server part, when I register my service with Bonjour, I generate a 10 character random alphanumeric string - a cookie. I make it a part of the advertised service name, as provided in call to [NSNetService initWithDomain:type:name:port:]. The resulting name is something like "MyApp on Joe's iPhone\txYbG56HjaE". The part before the tab character is for display, the part after is the cookie. I then store the cookie is a globally visible variable. Since server initialization takes place on app startup, the cookie value is available early on.
In the service discovery part, when I find a service, I check its name; if the cookie is the same as the stored global one, I skip this service. The idea is that other running instances of the program would have different cookie values, because randomness.
Naturally, when displaying discovered service names in the UI, I skip the part after the tab character.

BizTalk 2010: Access Context In Map

This could be a very basic question, but hopefully someone will be able to answer it.
I am receiving messages (HL7) using a custom receive pipeline. Inside my custom pipeline, I am promoting properties into the context. I have set up a map where I need to access these properties. However, I would like to access these properties on the send side. The reason why it needs to be on the send side is because I am attaching my map to the send port, so I assume that the message will have already hit the MessageBox and will be mapped on the send side. Hopefully that makes sense...
I know that there are a few 3rd party tools I can use, but I was hoping that there's a simple functoid, or some code I can enter in a scripting functoid that will access the context for me.
Would someone be able to point me in the right direction with this?
There is, indeed a C# functoid that allows access to context properties but it seems to only work with maps on a Receive Port or inside an Orchestration.
You can use the Context Accessor Functiod to do this... Combine it's pipeline component with yours and it should work... Beware it should be handled within the same thread...
http://contextaccessor.codeplex.com/
I don't know if this is possible. However, I had a similar requirement to access message context properties and I was able to populate a message with the context properties in an orchestration thanks to
Greg.Forsythe's excellent instructions
I had a similar situation to access the context properties to get the filename property in the my map. I did the below steps without using any external functoids. Hope this helps someone
Steps:
create a new schema say "FileSchema"
FileNode(rootNode)
-FileName (fieldElement)
Click the schema and in the properties target namespace - clear the namespace.
make the FileName property distinguished. Rt.Click FileName and show promotions and add FileName to Distinguished property tab.
In your target schema, add the field FileName. for me I added it to a SQL schema, since I need the filename for every row in the database
In your orchestration, use the message assignment shape and type the below
// create a variable varFileXML of type System.XML.XMLDocument
// I'm creating a xml same like the file schema and loading that to the XML variable and then assigning that to the Message of type FileSchema
varFileXML = new System.Xml.XmlDocument();
varFileXML.LoadXml("<FileNode><FileName>FileName_0</FileName></FileNode>");
Msg_FileSchema = varFileXML;
//Get the FileName to a variable of string type
varFileName = Msg_FlatFileSchema(FILE.ReceivedFileName);
varFileName = System.IO.Path.GetFileName(varFileName);
//Access the filename property from the message and assign the variable to that
Msg_File.FileName = varFileName;
Now that we got the FileName in to the message you can use that in mapping to your target schema
I used a transform shape to create a new inline map with source as your target schema and fileschema together and the destination as the target schema.I mapped the filename from the fileschema to my target schema the filename property
this is one of the many ways to get the context property. Hope it helps
thanks & regards
Silam

Resources