Search code examples
springspring-bootodataolingo

OData (Olingo) "inhibit" endpoint


My question is about what is best way to inhibit an endpoint that is automatically provided by Olingo?

I am playing with a simple app based on Spring boot and using Apache Olingo.On short, this is my servlet registration:

@Configuration
public class CxfServletUtil{

@Bean
public ServletRegistrationBean getODataServletRegistrationBean() {
    ServletRegistrationBean odataServletRegistrationBean = new ServletRegistrationBean(new CXFNonSpringJaxrsServlet(), "/user.svc/*");
    Map<String, String> initParameters = new HashMap<String, String>();
    initParameters.put("javax.ws.rs.Application", "org.apache.olingo.odata2.core.rest.app.ODataApplication");
    initParameters.put("org.apache.olingo.odata2.service.factory", "com.olingotest.core.CustomODataJPAServiceFactory");
    odataServletRegistrationBean.setInitParameters(initParameters);
    return odataServletRegistrationBean;
} ...

where my ODataJPAServiceFactory is

@Component
public class CustomODataJPAServiceFactory extends ODataJPAServiceFactory implements ApplicationContextAware {

private static ApplicationContext context;

private static final String PERSISTENCE_UNIT_NAME = "myPersistenceUnit";
private static final String ENTITY_MANAGER_FACTORY_ID = "entityManagerFactory";

@Override
public ODataJPAContext initializeODataJPAContext()
        throws ODataJPARuntimeException {
    ODataJPAContext oDataJPAContext = this.getODataJPAContext();
    try {
        EntityManagerFactory emf = (EntityManagerFactory) context.getBean(ENTITY_MANAGER_FACTORY_ID);
        oDataJPAContext.setEntityManagerFactory(emf);
        oDataJPAContext.setPersistenceUnitName(PERSISTENCE_UNIT_NAME);
        return oDataJPAContext;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

...

My entity is quite simple ...

@Entity
public class User {
@Id
private String id;

@Basic
private String firstName;

@Basic
private String lastName;
....

Olingo is doing its job perfectly and it helps me with the generation of all the endpoints around CRUD operations for my entity.

My question is : how can I "inhibit" some of them? Let's say for example that I don't want to enable the delete my entity.

I could try to use a Filter - but this seems a bit harsh. Are there any other, better ways to solve my problem?

Thanks for the help.


Solution

  • As you have said, you could use a filter, but then you are really coupled with the URI schema used by Olingo. Also, things will become complicated when you have multiple, related entity sets (because you could navigate from one to the other, making the URIs more complex).

    There are two things that you can do, depending on what you want to achieve:

    1. If you want to have a fined grained control on what operations are allowed or not, you can create a wrapper for the ODataSingleProcesor and throw ODataExceptions where you want to disallow an operation. You can either always throw exceptions (i.e. completely disabling an operation type) or you can use the URI info parameters to obtain the target entity set and decide if you should throw an exception or call the standard single processor. I have used this approach to create a read-only OData service here (basically, I just created a ODAtaSingleProcessor which delegates some calls to the standard one + overridden a method in the service factory to wrap the standard single processor in my wrapper).

    2. If you want to completely un-expose / ignore a given entity or some properties, then you can use a JPA-EDM mapping model end exclude the desired components. You can find an example of such a mapping here: github. The mapping model is just an XML file which maps the JPA entities / properties to EDM entity type / properties. In order for olingo to pick it up, you can pass the name of the file to the setJPAEdmMappingModel method of the ODataJPAContext in your initialize method.