How would I get a hold of a singleton in the main application from a SIMBL plugin? When I try to call something like [ProcessControl sharedInstance], I get an error that ProcessControl is undefined (even though it is declared in a header file).
Use NSClassFromString to look up the class at run time, then send it the sharedInstance message as normal.
Be prepared for NSClassFromString to return Nil or for the message to the class to fail. Either one will happen if the application developer removes or renames the class or its singleton method. You assume this risk whenever you write a plug-in for an application that doesn't have a documented, supported plug-in API.
Your “plug-in” will be most robust if all of your code that interacts with the application's classes and instances thereof looks thoroughly paranoid.
Related
I'm trying to implement integration testing in my app and have test class like that:
#ExtendWith(value={MyDockerExtension.class})
#ExtendWith(value={SpringExtension.class})
#WebAppConfiguration
#ContextConfiguration(classes={...})
#TestInstance(TestInstance.LifeCycle.PER_CLASS)
public class TestClass{ ... }
Is there any way to make MyDockerExtension execute some code, before whole SpringExtension start working and generate whole Context with Configurationc classes?
I've heard that order in which we declare extensions is the key, but sadly MyDockerExtension that implements BeforeAllCallback, AfterAllCallback executes right before test method and after whole context is loaded. In that situation it's to late to start containers with docker, becuase since whole context is loaded my app already tried to connect to the container.
At first I was skeptical about the order being fixed but you're correct:
Extensions registered declaratively via #ExtendWith will be executed in the order in which they are declared in the source code.
Regarding the MyDockerExtension, you may want to look at the extension point TestInstancePostProcessor, which is called before #BeforeAll. SpringExtension implements it and I guess it's there where it sets up the application context. If you also implement it, you should be able to act before it does.
I always got problems with the private variable declaration.
For example FlatFileItemWrite. I would like to extend these class and overwrite the 'doRead' method. This would not work because some of the used variables are declared private. This leads to copying the complete code in an own class for overwriting one method.
Sometime even this does not work because the class extends an other class which has variables declared visible only for the same package. Then you need to copy this class also.
Then I will miss updates in the original classes with new versions. So would it not be better to use protected instead?
I can imaging only a very few reasons to use private instead of protected. For my own programs this is not an issue, I could change it on demand. But for a framework it is a pain.
with kind regards
Torsten
If something is declared private within the Spring framework (or any framework for that matter), it's not considered part of the public API. Because of that, you really shouldn't be looking to work with it directly. Doing so really means you're forking the framework and risking not being able to upgrade seamlessly.
As the project lead for Spring Batch, I'd be interested in hearing what you had to do with the FlatFileItemWriter that required you to change things that are marked private.
If the idea behind the framework was to override or extend these methods, they should have been written as being public. (be careful if a framework does not provide these methods or properties as public, since it might depend on them working in a specific way. this would be the primary reason for them being private i can think of. the secondary being that they don't matter outside that class.)
In some cases, you might not need to copy the entire class, but simply inheriting or extending it might be enough.
I'm also looking to extend certain ItemReaders/ItemWriters to support decryption/encryption on i/o. For example, I'd like to extend StaxEventItemReaderStaxEventItemReader in order to read an encrypted stream from the resource, but the FragmentEventReader is private, so I'm unable to wrap its XMLEventReader's InputStream in a decrypter.
I faced the same issue with FlatFileItemWriter.
So, I am creating a class library that handles user information like username, password, etc. I want to do this so that I can just reference this library with any of my web apps and not have to continuously rewrite the user information part.
In, the user information class library, I want to handle the login. I've done this before in app_code that was a part of the web project by using HttpContext.Current.Session. But, when I try to use it in my class library (even while using System.Web) it throws a compile error saying that HttpContext does not exist in this context. How can I get access to it?
When creating a utility type class that works with a dependency like HttpContext, your best bet is to pass the context or the session into the class either via a constructor or the method call. That way, it is explicit to the consumers of your class that it requires this object to function. This also allows you to test your class in isolation.
Even better, if you are working with a few specific properties that have basic types then you can accept those properties as inputs. That way, you are not creating any dependencies on a UI framework for your utility library.
I'm developing my first Tapestry application with a login system based on a Hibernate database.
On one page with a session object, I want to call my Authenticator service class, which also gets the session injected and does some stuff. My problem is, I can't get any services to run, it's been very frustrating, despite me following simple guides like this one: http://code.google.com/p/shams/wiki/Service
In my services package, I got the Authenticator.java and AuthenticatorImpl.java interface and implemented class. In the AppModule class, I call
binder.bind(Authenticator.class, AuthenticatorImpl.class);
And in my page 'ShowAllUsers' I inject my Authenticator service object:
...
public class ShowAllUsers{
#Inject
private Session session;
#Inject
private Authenticator authenticator;
...
}
But when I load the page on my server, I receive following error:
org.apache.tapestry5.ioc.internal.OperationException
Error obtaining injected value for field de.webtech2.pages.user.ShowAllUsers.authenticator: No service implements the interface de.webtech2.services.Authenticator.
trace:
- Creating instantiator for component class de.webtech2.pages.user.ShowAllUsers
- Running component class transformations on de.webtech2.pages.user.ShowAllUsers
- Injecting field de.webtech2.pages.user.ShowAllUsers.authenticator
But my AppModule does bind the class to the interface successfully. In the Maven build console I can read "Authenticator: DEFINED" and if I try to bind it in another module, it complains because it's bound in AppMopule already.
Why doesn't tapestry see the implementation? What am I doing wrong?
Glad you checked the startup log output, that's certainly the first "sanity check" towards addressing this problem.
I think uklance has the right idea: do a clean build, make sure you don't have multiple classes named Authenticator floating around ... perhaps from a 3rd party library. I'm always having problems where I accidentally import a non-Tapestry class that happens to be named "Resource" or something.
I haven't solved the issue itself but I found a workaround that fixes it. As you might find on the internet, Tapestry allows for auto-reloading classes. Pages and components do work fine, services have some limitations -- this is where there seem to arise issues. Tomcat doesn't link the interface to the implementation.
Fix: A simple restart of eclipse solves this. Meh.
(This also fixes the "method not found" error if you added a new method to an existing service)
Also, when I execute mvn clean, everything gets screwed many times over. Eclipse can no longer resolve the simplest class and package references. Classes in the same package can no longer be found, or references to the javax.internet package lead into eternal nothingness -- whereas everything was working just fine a moment ago.
Fix:
Right-click eclipse project -> Properties -> Maven
Tick the checkbox for "Resolve dependencies from Workspace projects" and hit Apply.
If it is already checked, uncheck -> apply, then recheck -> apply. Eclipse should go sane again -- until next time...
I'm in the process of upgrading my application the latest release of Eclipse Equinox 3.7 and associated libraries. I'm excited to have the generic support in OSGi 4.3 and digging the new Bundle.adapt() concepts. I've run into one stumbling block.
Previously, I've used PackageAdmin.getBundle(Class) to find out which bundle loaded which classes. I have to do this due to some RMI object serialization usage.
QUESTION: Is there an way to accomplish the same result, mapping Class to Bundle, using the new BundleWiring API?
I realize that PackageAdmin is probably not going away anytime soon, but I hate deprecation warnings.
Kinda embarrassed that I didn't find this the first time I looked through the document. Answering my own question for completeness.
From the core specification PDF ...
Section 3.9.9 - Finding an Object’s Bundle
There are scenarios where a bundle is required in code that has no access to a Bundle Context. For this
reason, the framework provides the following methods:
Framework Util – Through the FrameworkUtil class with the getBundle(Class) method. The
framework provides this method to allow code to find the bundle of an object without having the
permission to get the class loader. The method returns null when the class does not originate from
a bundle.
Class Loader – An OSGi framework must ensure that the class loader of a class that comes from a
bundle implements the BundleReference interface. This allows legacy code to find an object’s
bundle by getting its class loader and casting it to a BundleReference object, which provides
access to the Bundle. However, this requires the code to have the permission to access the class
loader. The following code fragment shows how to obtain a Bundle object from any object.
ClassLoader cl = target.getClassLoader();
if ( cl instanceof BundleReference ) {
BundleReference ref = (BundleReference) cl;
Bundle b = ref.getBundle();
...
}
In an OSGi system, not all objects belong to the framework. It is therefore possible to get hold of a
class loader that does not implement the BundleReference interface, for example the boot class path
loader.