Cloud endpoints methods visibility - java

I'm developing an Android app with Google Cloud Endpoints, I have read a lot of documentation and tutorials about it, but there is still one information missing: How can I choose which backend's methods will be visible for Android client?
Let's say I have a FriendshipEndpoint, FriendshipEndpoint has this method:
#ApiMethod(name = "listFriendship", path = "listFriendship")
public CollectionResponse<Friendship> listFriendship(
#Nullable #Named("cursor") String cursorString,
#Nullable #Named("limit") Integer limit)
EDIT FriendshipEndpoint is annotated with #Api annotation
This method should be visible only in the backend (not by Android client).
I have tried to remove #ApiMethod anotation -> doesn't work, the method is still visible in the api explorer in my browser.
Setting access modifier to private is not a solution for me, because I want to call this method from other Endpoint.
Removing access modifier is also no solution for me, because I need this method to be visible from other packages (test package).
Is there a solution for this problem at all?

Unfortunately, this scenario is not supported right now. The best solution is to move the method to a helper class and have it shared among all the endpoint classes.

Related

Is it possible to create necessary / required interfaces?

i have a little kont in my brain about structuring our code. We have a REST Backend based on SpringBoot. To handle requests regarding to security checks we use HandlerInterceptors. In some specific cases we need a specific interceptor and not our default one. The default one is registered in a 3rd party lib that no one can forget it. But i want all coders to think about this specific interceptor.
Actually, i just said it to them to achieve this.
Here's my question: Is there an option to create required (or necessary) interfaces which must be implemented? This would be a way to provide our security code by lib and to have the security that every coder implemented our specific interface (also if he just does nothing with it).
pseudo code:
public interface thinkForIt(){
Object SecBean specificSecBean;
public void methodToThinkOn();
}
public SecImpl implements thinkForIt(){
#Override
public void methodToThinkOn(){
return null; // i thought about it but i do not need to do anyting!
}
If the interface thinkForIt would have any annotations like #required, users could get warning or error if they did not implement it...
Looking for a solution and thanks for your comments in advance!
Your overall design is questionable; you are reinventing security code, which is always a red flag. Use Spring Security instead.
However, there's a simple way to ensure that "some bean of type Foo" has been registered with the context:
#Component
#RequiredArgsConstructor
public class ContextConfigurationVerifier {
final Foo required;
}

Spring-boot location variables in urls

I'm trying to set up my website to allow location additions to the urls.
EG: mysite.com/us/ca/sanfrancisco/home
While also still allowing mysite.com/home and everything in between.
Spring boot parent so you know what version of spring I'm using:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
</parent>
If there's another piece of versioning you need, let me know.
I get that I can add in regex variables to the request mapping, but how would I go about persisting those urls across more requests?
So right now for an example, the testing error page I have:
#RequestMapping({"/error/501", "/{state:[a-z]{2}}/error/501", "/{state:[a-z]{2}}/{city:[a-z]+}/error/501"})
public ModelAndView testingLocations(ModelMap model, #PathVariable(value="state", required = false) String state,
#PathVariable(value="city", required=false) String city){
getLogger().info("State: {}", state);
model.addAttribute("stateTest",state+":"+city);
model.addAttribute("view", "error");
return new ModelAndView("error/501", model);
}
But when I'm on my testing page, and I click the home button, it takes me back to mysite.com/home
So My Questions
Is there a way for me to persist it so that if they're currently on a location based url, it will apply that base to the future navigations? (unless they manually enter the url to not include them)
Then as a follow-up, is there a way for me to globally apply these request variables without requiring me to add the #PathVariable to every request mapping method? I get that I can just add the request mapping variable strings themselves to the controller class, so that I don't need those on every method. But is there a way for me to utilize those without needing the #PathVariable annotations?
Finally, is there a way for me to make this not as hardcoded, like a way for me to say /{*location}/error to cover as deep as the locations will allow? While still having the verification on the location formatting, so verifying that 1 we support the locations given, 2 the format is correct (/ca/sanfrancisco vs /anything/anything
The last one I can live with, if I need to have the /state/city/municipality/actualtarget
As far as verifying that we support the locations given, I understand that's on my end, which I'll probably just have a small database to keep track of where we do and do not support for the given variables.
Is there a best practice for building this system? I tried to find something on this, but googling "spring boot location url" is not the best at giving me what I need, since "location" can apply to a pretty wide range of topics. I've gotten to where I am from searching, but I can't seem to pin down these last few steps.
Any help/advice/suggestions is appreciated. If upgrading versions is required, I'm not sure how viable that is at the moment, I'd have to look into it. Preferably I'd like the solution to be able to be done on the current spring version I'm running.
The best way here is:
#RequestMapping("/some/{foo}/{baz}")
public String hi(CompositeObject compositeObject) {
return "hi";
}
#Data
public class CompositeObject {
private String foo;
private String baz;
}
Spring provides functionality for request path and request parameters to collect it into a composite object. It doesn' work either with body or headers.
If you have something optional like state, then just keep it null at the controller and handle later

Google Cloud Endpoints call one endpoint from another

Let's say I have the following Google Cloud Endpoints:
#ApiMethod(name = "account.insert")
public Account insertAccount(Account account, #Named("userId") Long userId)
#ApiMethod(name = "user.get")
public User getUser(#Named("id") Long id)
Let's assume Account has a reference to User, which shall be created when the account is inserted. So what I need to do is look up the user by userId first to make sure it exists, then set the reference in Account.
To avoid redundancy, I decided it would be good to call getUser(userId) as this functionality exists as another endpoint.
This would work fine as long as both methods/endpoints are in the same class/file. As soon as I cross the class boundaries, I receive the following message:
"non-static method (...) cannot be referenced from a static content"
First of all, I don't understand why the content is static if it isn't marked as static in the method signature, but maybe the #ApiMethod annotation does its job here, because it is understandable that the API is exposed as a static method.
Second, I would probably be able to get around this by using a delegate function, but then I would like to know if it is considered good practice to call into one of my own endpoints from another endpoint.
Let me know what you think, please.

Dynamically set the authority of a ContentProvider

Perhaps the title is a bit misleading. My problem is that I have an Android library project which is shared between two standard Android projects: one for a free version of the app and the other for a paid version. The library currently has the code for a ContentProvider, including a contract class with several static String variables for things such as the URI and column names. Now I want the "authority" for the URI to change depending on which app is using the library. One solution that comes to mind is storing the authority as a string resource and loading that string at run-time into the static final String variable. However, I'm not sure how to do this as the contract class has a private constructor and no Context object in order to load the string resource. What other options are available to solve my problem?
Here's a better solution for those using newer versions of the build tools: make the authority relative to your application ID. You can do this automatically using ${applicationId}, which is expanded into your app's application ID during the build process.
<provider
android:name=".MyContentProvider"
android:authorities="${applicationId}.provider"/>
Let's say your application IDs are com.example.app.paid and com.example.app.free. When you build your app, the authority will become com.example.app.paid.provider and com.example.app.free.provider, correspondingly.
To reference the provider authority in your code, use BuildConfig.APPLICATION_ID + ".provider".
Using different authorities for the free and the paid version makes sense in case the user tries to install both versions.
I'm defining a different authority for the two versions in the manifest like so:
<provider
android:name="MyApp.MyProvider"
android:authorities="MyApp.MyProvider.free"
android:grantUriPermissions="true"/>
Then I configure the provider in an xml file (I use a special config.xml file because I have more configuration data like the provider authority, but you can use strings.xml of course):
<string name="my_provider_authority">MyApp.MyProvider.free</string>
The code retrieves the provider authority as any other string resource. To access string resources without a context use the application context. I'm using an application class to have access to the application context from anywhere in my app (there are two exceptions though):
public class MyApplication extends Application {
private static Context sContext;
#Override
public void onCreate() {
super.onCreate();
sContext = this;
}
public static Context getContext() {
return sContext;
}
}
Of course you need to define MyApplication in your manifest.
This allows you to access string and other resources from anywhere in your app.
There are two exception though:
ContentProviders. ContentProviders can be started before Application starts and so you won't have an Application context available. That's no problem though because ContentProviders get their own context through getContext().
Static code: the context might not be available outside the life cycle of Android components (Activities, Fragments, BroadcastReceivers, Services etc.). Static initializers that are relying on the application context are therefore not a good idea. But that's also not a real issue because using a context outside the life cycle of Android components isn't allowed anyway and static methods accessing a context would always be called from within that life cycle. E.g. if an Activity needs to know a ContentProvider's authority it would call a static method in your contract class and that call would be from one of the activity's onXYZ() methods like onCreate() or onStart() which would make sure that the context is initialized. So all you need to do is lazy initialize the variables in your contract class and make sure the caller does retrieve the variables only when it's clear that Application.onCreate() has been called before. Of course from within an activity you could retrieve the string resources directly. The real advantage of my method will become obvious when you need the resources in other classes/objects. These objects would still be tied to the life cycle of some Android component but you wouldn't have to pass around the context to all these objects, which is 1) very cumbersome and 2) very error prone when it comes to leaking the context which could lead to memory usage issues (one of the most common problems with Android apps).
Why change the authority at all? You're not required to export the provider, which means that nobody could even see the authority name except by deconstructing the app. Even then, they wouldn't be able to access the provider.
If it's for your own internal convenience, then I'd use the same authority but put different security on the URIs.
In short, your idea is interesting, but I wouldn't do it that way. Too much of a mess.

OSGI Declarative Services (DS): What is a good way of using service component instances

I am just getting started with OSGI and Declarative Services (DS) using Equinox and Eclipse PDE.
I have 2 Bundles, A and B.
Bundle A exposes a component which is consumed by Bundle B. Both bundles also expose this service to the OSGI Service registry again.
Everything works fine so far and Equinox is wireing the components together, which means the Bundle A and Bundle B are instanciated by Equinox (by calling the default constructor) and then the wireing happens using the bind / unbind methods.
Now, as Equinox is creating the instances of those components / services I would like to know what is the best way of getting this instance?
So assume there is third class class which is NOT instantiated by OSGI:
Class WantsToUseComponentB{
public void doSomethingWithComponentB(){
// how do I get componentB??? Something like this maybe?
ComponentB component = (ComponentB)someComponentRegistry.getComponent(ComponentB.class.getName());
}
I see the following options right now:
1. Use a ServiceTracker in the Activator to get the Service of ComponentBundleA.class.getName() (I have tried that already and it works, but it seems to much overhead to me) and make it available via a static factory methods
public class Activator{
private static ServiceTracker componentBServiceTracker;
public void start(BundleContext context){
componentBServiceTracker = new ServiceTracker(context, ComponentB.class.getName(),null);
}
public static ComponentB getComponentB(){
return (ComponentB)componentBServiceTracker.getService();
};
}
2. Create some kind of Registry where each component registers as soon as the activate() method is called.
public ComponentB{
public void bind(ComponentA componentA){
someRegistry.registerComponent(this);
}
or
public ComponentB{
public void activate(ComponentContext context){
someRegistry.registerComponent(this);
}
}
}
3. Use an existing registry inside osgi / equinox which has those instances? I mean OSGI is already creating instances and wires them together, so it has the objects already somewhere. But where? How can I get them?
Conclusion
Where does the class WantsToUseComponentB (which is NOT a Component and NOT instantiated by OSGI) get an instance of ComponentB from? Are there any patterns or best practises? As I said I managed to use a ServiceTracker in the Activator, but I thought that would be possible without it.
What I am looking for is actually something like the BeanContainer of Springframework, where I can just say something like Container.getBean(ComponentA.BEAN_NAME). But I don't want to use Spring DS.
I hope that was clear enough. Otherwise I can also post some source code to explain in more detail.
Thanks
Christoph
UPDATED:
Answer to Neil's comment:
Thanks for clarifying this question against the original version, but I think you still need to state why the third class cannot be created via something like DS.
Hmm don't know. Maybe there is a way but I would need to refactor my whole framework to be based on DS, so that there are no "new MyThirdClass(arg1, arg2)" statements anymore.
Don't really know how to do that, but I read something about ComponentFactories in DS. So instead of doing a
MyThirdClass object = new MyThirdClass(arg1, arg2);
I might do a
ComponentFactory myThirdClassFactory = myThirdClassServiceTracker.getService(); // returns a
if (myThirdClassFactory != null){
MyThirdClass object = objectFactory.newInstance();
object.setArg1("arg1");
object.setArg2("arg2");
}
else{
// here I can assume that some service of ComponentA or B went away so MyThirdClass Componenent cannot be created as there are missing dependencies?
}
At the time of writing I don't know exactly how to use the ComponentFactories but this is supposed to be some kind of pseudo code :)
Thanks
Christoph
Christoph,
Thanks for clarifying this question against the original version, but I think you still need to state why the third class cannot be created via something like DS.
DS causes components to be published as services, therefore the only way to "get" any component from DS is to access it via the service registry. Unfortunately the service registry can be hard to use correctly using the lower level APIs because it is dynamic, so you have to cope with the possibility of services going away or not being available at precisely the moment you want them to be available, and so on. This is why DS exists: it gives you an abstraction for depending on services and managing the lifecycle of your components based on the availability of services that they reference.
If you really need to access a service without using DS or something like it (and there is quite a choice of "things like it" e.g. Spring-DM, iPOJO, Guice/Peaberry, etc) then you should use ServiceTracker. I agree there is a lot of overhead -- again, this is why DS exists instead.
To answer your suggestion no (2), no you should not create your own registry of services because the service registry already exists. If you created a separate parallel registry then you would still have to handle all the dynamics, but you would have to handle it in two places instead of one. The same applies to suggestion (3).
I hope this helps.
Regards,
Neil
UPDATED: Incidentally, although Spring has the Container.getBean() backdoor, you notice that in all Spring documentation it is strongly recommended not to use that backdoor: to get hold of a Spring bean, just create another bean that references it. The same applies to DS, i.e. the best way to get hold of a DS component is to create another DS component.
Also note that in the OSGi world, even if you're using Spring-DM there is no easy way to just call getBean() because you need to get hold of the Spring ApplicationContext first. That is itself an OSGi service, so how to you get that service?
christoph,
dont know if I really understand your problem.
per ex.
Bundle A is providing a service using DS component:
<service>
<provide interface="org.redview.lnf.services.IRedviewLnfSelectedService"/>
Bundle B requires this service using DS component:
<implementation class="ekke.xyz.rcp.application.internal.XyzApplicationLnfComponent"/>
as soon as Bundle A provides the Service, Bundle B "gets" it through the bind() methode of the implementation class:
public class XyzApplicationLnfComponent {
public void bind(IRedviewLnfSelectedService lnfSelectedService) {
// here it is
}
hope this helps
ekke
Easy way: Inject the DS component into your Activator class with Riena:
http://wiki.eclipse.org/Riena_Getting_Started_with_injecting_services_and_extensions
Then you can call it from everywhere: Activator.getDefault().getWhateverService()

Categories