I wanto to try the web service of dflservice entry into the web service portal
http://localhost:8080/api/jsonws
but the parameter used obc just explain as obc with the type com.liferay.portal.kernel.util.OrderByComparator, I try null, 0, +obc:com.liferay.portlet.documentlibrary.util.comparator.FolderNameComparator, but always have the same result:
Conversion failed: com.liferay.portal.kernel.util.OrderByComparator
What is the correct parameter
According to documentation:
You can't pass 0, as obc is an object type parameter.
To pass a null value for obc, you need to prefix it with a dash like: /-obc.
And to pass an instance of an object parameter, you need to prefix the parameter with a plus sign like: /+obc:com.liferay.portlet.documentlibrary.util.comparator.FolderNameComparator (Should work as well).
As com.liferay.portal.kernel.util.OrderByComparator is an abstract class, you need to pass a concrete implementation. Check the implementation of DLImpl.getRepositoryModelOrderByComparator method for further concrete implementations of OrderByComparator class for document library.
Also, I would like you to share the URI(s), you are trying. So, I can also try them.
Reference:
INVOKING JSON WEB SERVICES
Update:
There is bug in JSONWS GUI, which is already fixed in:
https://issues.liferay.com/browse/LPS-76955?page=com.atlassian.jira.plugin.system.issuetabpanels%3Aall-tabpanel
However, the URL access is working for me:
http://localhost:8080/api/jsonws/dlfileentry/get-file-entries/group-id/10184/folder-id/0/status/0/start/-1/end/-1/+obc:com.liferay.portlet.documentlibrary.util.comparator.RepositoryModelNameComparator
Here, com.liferay.portlet.documentlibrary.util.comparator.RepositoryModelNameComparator is a concrete implementation of obc.
Related
One of my tasks it to configure network adapters for DHCP/static IP, and the only way I found to do this is using Win32_NetworkAdapterConfiguration class.
WMI is new to me, and it seems to use it in C++ (Qt/MinGW) is not that easy, and most things I found in the WWW deal with .NET, PowerShell or VBScript. However, I already succeeded in querying information, for example the MAC address for a specific adapter.
I already read the MSDN: Calling a Provider method on MSDN, but in looking forware to WIn32_NetworkAdapterConfiguration there is one thing I don't unstand.
My IEnumWbemClassObject is the result of a SELECT * FROM Win32_NetworkAdapterConfiguration WHERE InterfaceIndex=n (n is a number, of course), and returns IWbemClassObject for the specific adapter.
How to I tell ExecMethod which instance of Win32_NetworkAdapterConiguration to use when calling the EnableDHCP()/EnableStatic() methods (in meaning of the IWbemClassObject I will recieve when i enumerate the result of my query)?
While looking for a example for passing string arrays to ExecMethod() if found this thread at CodeProject which execatly fit to my tasks. As stated in the comments above, the path of the object instance (not the class path!) must be passed to the "strObjectPath" parameter of ExecMethod.
Is it possible to use JavaLoader to get objects returned by CF-called web services, and JavaLoader-loaded objects to be the same classpath context? I mean, without a lot of difficulty?
// get a web service
ws = createObject("webservice", local.lms.wsurl);
// user created by coldfusion
user = ws.GenerateUserObject();
/* user status created by java loader.
** this api provider requires that you move the stubs
** (generated when hitting the wsdl from CF for the first time)
** to the classpath.
** this is one of the stubs/classes that gets called from that.
*/
UserStatus = javaLoader.create("com.geolearning.geonext.webservices.Status");
// set user status: classpath context clash
user.setStatus(UserStatus.Active);
Error:
Detail: Either there are no methods with the specified method name and
argument types or the setStatus method is overloaded with argument
types that ColdFusion cannot decipher reliably. ColdFusion found 0
methods that match the provided arguments. If this is a Java object
and you verified that the method exists, use the javacast function to
reduce ambiguity.
Message: The setStatus method was not found.
MethodName setStatus
Even though the call, on the surface, matches a method signature on user--setStatus(com.geolearning.geonext.webservices.Status)--the class is on a different classpath context. That's why I get the error above.
Jamie and I worked on this off-line and came up with a creative solution :)
(Apologies for the long answer, but I thought a bit of an explanation was warranted for those who find class loaders as confusing as I do. If you are not interested in the "why" aspect, feel free to jump to the end).
Issue:
The problem is definitely due to multiple class loaders/paths. Apparently CF web services use a dynamic URLClassLoader (just like the JavaLoader). That is how it can load the generated web service classes on-the-fly, even though those classes are not in the core CF "class path".
(Based on my limited understanding...) Class loaders follow a hierarchy. When multiple class loaders are involved, they must observe certain rules or they will not play well together. One of the rules is that child class loaders can only "see" objects loaded by an ancestor (parent, grandparent, etcetera). They cannot see classes loaded by a sibling.
If you examine the object created by the JavaLoader, and the other by createObject, they are indeed siblings ie both children of the CF bootstrap class loader. So the one will not recognize objects loaded by the other, which would explain why the setStatus call failed.
Given that a child can see objects loaded by a parent, the obvious solution is to change how the objects are constructed. Structure the calls so that one of the class loaders ends up as a parent of the other. Curiously that turned out to be trickier than it sounded. I could not find a way to make that happen, despite trying a number of combinations (including using the switchThreadContextClassLoader method).
Solution:
Finally I had a crazy thought: do not load any jars. Just use the web service's loader as the parentClassLoader. It already has everything it needs in its own individual "class path":
// display class path of web service class loader
dynamicLoader = webService.getClass().getClassLoader();
dynamicClassPath = dynamicLoader.getURLS();
WriteDump("CLASS PATH: "& dynamicClassPath[1].toString() );
The JavaLoader will automatically delegate calls for classes it cannot find to parentClassLoader - and bingo - everything works. No more more class loader conflict.
webService = createObject("webservice", webserviceURL, webserviceArgs);
javaLoader = createObject("component", "javaloader.JavaLoader").init(
loadPaths = [] // nothing
, parentClassLoader=webService.getClass().getClassLoader()
);
user = webService.GenerateUserObject();
userStatus = javaLoader.create("com.geolearning.geonext.webservices.Status");
user.setStatus(userStatus.Active);
WriteDump(var=user.getStatus(), label="SUCCESS: user.getStatus()");
I have been researching this, and cannot seem to find anything about it.
We work on CF8. When my coworker tried installing my latest code updates, he started seeing errors that the argument supplied to a function was not of the specified interface type. Worked fine for me. Same set up. Sometimes it works for him. Also have the problem on our dev server.
I have since been able to isolate and reproduce the problem locally.
Here is the set up.
I have 2 mappings on the server:
"webapp/" goes to c:\webroot\
"packages/" goes to c:\webroot\[domain]
Then I created an interface, call it ISubject and a component that implements it, called Person, and saved both under packages. Here is the declaration for Person:
cfcomponent implements="packages.ISubject"
Finally, there is a component, called SubjectMediator with a function, called setSubject, that wants an object of the ISubject interface type. Here is the argument declaration for setSubject:
cfargument name="subject_object" type="packages.ISubject"
To implement:
variables.person = createObject("component", "packages.Person").Init();
variables.subjectMediator = createObject("component", "packages.SubjectMediator ").Init();
variables.subjectMediator.setSubject(variables.person);
That last line throws the error that Person is not of type ISubject. If I do isInstanceOf() on Person against ISubject it validates fine.
So the reason this is happening? Dumping getMetaData(variables.person) shows me that the interface path is webapp.[domain].ISubject. And indeed, if I change the type attribute of the argument to use this path instead of packages.ISubject, all is fine again.
Coldfusion seems to be arbitrarily choosing which mapping to resolve the interface to, and then simply doing a string comparison for check the type argument?
Anyone had to contend with this? I need the webapp mapping, and I cannot change all references to "packages" to "webapp.[domain]." I also am not able in this instance to use an application-specific mapping for webapp. While any of these 3 options would circumvent the issue, I'm hoping someone has some insight...
The best I've got is to set argument type to "any" and then check isInstanceOf() inside the function... Seems like poor form.
Thanks,
Jen
Can you move the contents of the packages mapping to outside the webroot? This seems like the easiest way to fix it.
I'm using the decorator pattern to implement caching for my Repositories as such:
IFooRepository()
IFooRepository FooRepository()
IFooRepository CachedFooRepository(IFooRepository fooRepository)
The Cached repository checks the cache for the requested object and if it doesn't exist, calls the FooRepository to retrieve and store it. I'm currently registering these types with StructureMap using the following method:
For<IFooRepository>().Use<CachedFooRepository()
.Ctor<IFooRepository>().Use<FooRepository>();
This works fine, but as the number of cached repositories grows, registering each one individually is becoming unwieldy and is error prone. Seeing as I have a common convention, I'm trying to scan my assembly using a custom IRegistrationConvention, but I can't seem to figure out how to pass the FooRepository to the constructor of CachedFooRepository in the void Process(Type type, Registry registry) function.
I've found examples to do something like:
Type interfaceType = type.GetInterface(type.Name.Replace("Cached", "I"));
registry.AddType(interfaceType, type);
or
Type interfaceType = type.GetInterface(type.Name.Replace("Cached", "I"));
registry.For(interfaceType).Use(type);
But neither method will allow me to chain the .Ctor. What am I missing? Any ideas?
I have a web service that sends a struct to a client program.
I need to pass an arraylist of string values as one of the properties of this struct, but by the time it gets to the client program its type is 'object'. Once it gets back to the client program, how can I convert this Object datatype back into the arraylist?
Unless you're stuck at .NET 1.1, don't use ArrayList. Try returning a List<YourStruct> instead.
The problem was the way I was attempting to explicitly create an arraylist and then setting it equal to the returned property from the struct; here's the correct way to do it - some weird VB implicit thingy. (sorry, never drank the VB kool-aid)
Dim ReturnedArrList As New ArrayList(structReturned.arrReturnedArrayList)