Olingo OData V2 Read Property not implemented - jpa

I implemented an OData V2 Service with Apache Olingo V2 in connectin with JPA using EclipseLink. All requests are working fine, but when it comes to the point, where I want to access a single property via GET request from an entity set like for the following URL:
http://localhost:8080/MyODataService/XXXXXX.svc/EntitySet(12345)/Property
the response in return is:
<error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<code/>
<message xml:lang="de-DE">Not implemented</message>
</error>
The class which extends the ODataJPASeviceFactory looks as follows:
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.apache.olingo.odata2.jpa.processor.api.ODataJPAContext;
import org.apache.olingo.odata2.jpa.processor.api.ODataJPAServiceFactory;
import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPARuntimeException;
public class JPAODataServiceFactory extends ODataJPAServiceFactory
{
private static final String PERSISTENCE_UNIT_NAME = "MyPersistenceUnitName";
#Override
public ODataJPAContext initializeODataJPAContext() throws ODataJPARuntimeException
{
ODataJPAContext oDatJPAContext = this.getODataJPAContext();
try
{
EntityManagerFactory emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
oDatJPAContext.setEntityManagerFactory(emf);
oDatJPAContext.setPersistenceUnitName(PERSISTENCE_UNIT_NAME);
return oDatJPAContext;
} catch (Exception e)
{
throw new RuntimeException(e);
}
}
My question now is:
How do I implement the functionality, so that I can do GET and POST requests not only for a whole entity set, but also for a single property of an entity set like I tried with the mentioned URL?

Accessing a single property from one entity is currently not implemented if you use the Olingo JPA Extension.
If you want to support this behaviour you can register a custom processor and only override the "readEntityComplexProperty" and "readEntitySimpleProperty" methods. There you can have your custom code where you specifically get back the value.
Every method you don`t override will result in the standard Olingo functionality being executed.
Here is a tutorial on how to register a custom JPA processor: http://olingo.apache.org/doc/odata2/tutorials/CustomODataJPAProcessor.html
Here is the example on how your code can look like if you implement the functionality yourself: https://github.com/apache/olingo-odata2/blob/597465569fdd15976d0486711d4a38f93a7c6696/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ListsProcessor.java#L592

You need to create an association between your entity sets.
For example, to access the following URL: http://localhost:8080/myService.svc/Cars('6')/Manufacturer, you need to create an assocation between your car and your manufacturer association sets.
Have a look at the documentation: https://olingo.apache.org/doc/odata2/tutorials/basicread.html

Hegg,
you can use
http://localhost:8080/MyODataService/XXXXXX.svc/EntitySet(12345)/?$select=Property
Bye
Domenico

Related

Using interfaces in dependency injection in .Net MAUI

I am trying to implement dependency injection for the first time in my new project in .Net MAUI. For testing purposes, I want to fetch data from a local source in my ViewModel. The production scenario will fetch data from the remote data source using HttpClient.
Below is my code base structure:
I have an Interface:
public interface IApiService
{
Task<bool> GetSomething(string parameter);
Task<string> GetSomethingElse(string parameter);
}
I have two classes that derive from it.
public class LocalDataStore: IApiService
public class RemoteDataStore: IApiService
In my MauiProgram.cs, when I want to use Local Data Store:
builder.Services.AddSingleton<LocalDataStore>()
builder.Services.AddSingleton<IApiService>()
And for Remote Data Store
builder.Services.AddSingleton<RemoteDataStore>()
builder.Services.AddSingleton<IApiService>()
In my ViewModel:
public class Page1ViewModel
{
public Page1ViewModel(IApiService localDataStore)
{
var items = Task.Run(async () => await localDataStore.GetSomething(true));
}
}
While running the app, I get an error :
System.InvalidOperationException: 'Unable to resolve service for type '...IApiService' while attempting to activate 'ViewModels.Page1ViewModel'.'
What am I doing wrong or what else should I be doing?
Kindly help.
Thanks, and regards.
Edit*
Of course, it works if I use LocalDataStore or RemoteDataStore instead of IApiService, when I register the services with the builder. But then if I have to change from one data store to another, I will have to change that in all the ViewModel classes?
It was trivial.
I needed to register the service like so :
builder.Services.AddSingleton<IApiService,LocalDataStore>();
Thanks to https://youtu.be/paZNvvUNFi0, I realised that.
Hope this helps someone.

How to specify EntityFramework ProviderName in an Azure Function

I'm trying to port some webjob code to the new Azure Functions. So far I've managed to import my DLL's and reference them succesfully, but when I use the connection string in my code, I get an error saying I have to add the ProviderName:
The connection string 'ConnectionString' in the application's
configuration file does not contain the required providerName
attribute."
Which is normally not a problem because in a webjob (or web app), this will be in the App or Web.config, and the connectionstring will simply be overwritten with whatever I entered in Azure.
With Azure Functions, I don't have a web.config (Although I tried adding one to no avail), so naturally the providername is missing.
How do I specify that?
EDIT:
After some playing around and some helpful tips by people below, I've almost managed to get it working.
What I do now is the following:
var connString = **MY CONN STRING FROM CONFIG**; // Constring without metadata etc.
EntityConnectionStringBuilder b = new EntityConnectionStringBuilder();
b.Metadata = "res://*/Entities.MyDB.csdl|res://*/Entities.MyDB.ssdl|res://*/Entities.MyDB.msl";
b.ProviderConnectionString = connString.ConnectionString;
b.Provider = "System.Data.SqlClient";
return new MyDB(b.ConnectionString);
Which gives me what I need for calling the database. I use a static method in a partial class to get an instance of the Database which runs the above code, and I decorate my MyDB Partial with [DbConfigurationType(typeof(MyDbConfiguration))]
I define that configuration as:
public class MyDBConfiguration: DbConfiguration
{
public MyDBConfiguration()
{
SetProviderFactory("System.Data.EntityClient", EntityProviderFactory.Instance);
}
}
My problem remains when I want to actually use the EF Entities. Here, it will try to initialize the database type using the original configuration, giving me the original error once again. As per this stack trace:
at Void Initialize()
at System.Data.Entity.Internal.EntitySetTypePair GetEntitySetAndBaseTypeForType(System.Type)
at Void InitializeContext()
at System.Data.Entity.Core.Objects.ObjectContext CreateObjectContextFromConnectionModel()
at Void Initialize()
at Boolean TryInitializeFromAppConfig(System.String, System.Data.Entity.Internal.AppConfig)
at Void InitializeFromConnectionStringSetting(System.Configuration.ConnectionStringSettings)
So how do I avoid this? I guess I need a way to hook into everything and run my custom setter..
In the end, Stephen Reindel pushed me in the right direction; Code-based Configuration for Entity Framework.
[DbConfigurationType(typeof(MyDBConfiguration))]
public partial class MyDB
{
public static MyDB GetDB()
{
var connString = **MY CONN STRING FROM SOMEWHERE**; // Constring without metadata etc.
EntityConnectionStringBuilder b = new EntityConnectionStringBuilder();
b.Metadata = "res://*/Entities.MyDB.csdl|res://*/Entities.MyDB.ssdl|res://*/Entities.MyDB.msl";
b.ProviderConnectionString = connString.ConnectionString;
b.Provider = "System.Data.SqlClient";
return new MyDB(b.ConnectionString);
}
public MyDB(string connectionString) : base(connectionString)
{
}
}
With MyDbConfiguration like this:
public class MyDBConfiguration: DbConfiguration
{
public MyDBConfiguration()
{
SetProviderServices("System.Data.SqlClient", SqlProviderServices.Instance);
SetDefaultConnectionFactory(new SqlConnectionFactory());
}
}
With the above code, EF never asks for AppConfig-related config files. But remember, if you have EF entries in your config file, it will attempt to use them, so make sure they're gone.
In terms of azure functions, this means I used the Azure Functions configuration panel in azure to punch in my ConnectionString without the Metadata and providername, and then loaded that in GetDB.
Edit: As per request, here is some explanatory text of the above:
You can't add EF metadata about the connection in Azure Functions, as they do not use an app.config in which to specify it. This is not a part of the connection string, but is metadata about the connection besides the connection string that EF uses to map to a specific C# Class and SQL Provider etc. To avoid this, you hardcode it using the above example. You do that by creating a class inheriting from DBConfiguration, and you mark (with an attribute on a partial class) your EF database class with that.
This DBConfiguration contains a different kind of way to instantiate a new database object, in which this metadata is hardcoded, but the connectionstring is retrieved from your app settings in Azure. In this example I just used a static method, but I guess it could be a new constructor also.
Once you have this static method in play, you can use that to get a new database in your database code, like this:
using (var db = MyDB.GetDB()) {
// db code here.
}
This allows you to use EntityFramework without an APP.Config, and you can still change the connectionstring using Azure Functions APP settings.
Hope that helps
Using this question you can set your default factory before opening the connection by having your personal DbConfiguration class (see this link also for usage):
public class MyDbConfiguration : DbConfiguration
{
public MyDbConfiguration()
{
SetDefaultConnectionFactory(new SqlConnectionFactory());
}
}
Now you need to tell your DbContext to use the new configuration. As using web.config or app.config is no option, you may use an attribute to add the configuration:
[DbConfigurationType(typeof(MyDbConfiguration))]
public class MyContextContext : DbContext
{
}
Now using a connection string on your DbContext will use the SQL provider by default.
Provided answer is perfect and it helped me a lot but it is not dynamic as I dont want to hardcode my connectionstring. if you are working the slots in azure functions. I was looking for a solution where I can use more than 1 connection strings. Here is my alternative approach step by step for anybody else struggling with this problem.
most important thing is that we understand local.settings.json file
IS NOT FOR AZURE. it is to run your app in the local as the name is
clearly saying. So solution is nothing to do with this file.
App.Config or Web.Config doesnt work for Azure function connection strings. If you have Database Layer Library you cant overwrite connection string using any of these as you would do in Asp.Net applications.
In order to work with, you need to define your connection string on the azure portal under the Application Settings in your Azure function. There is
Connection strings. there you should copy your connection string of your DBContext. if it is edmx, it will look like as below. There is Connection type, I use it SQlAzure but I tested with Custom(somebody claimed only works with custom) works with both.
metadata=res:///Models.myDB.csdl|res:///Models.myDB.ssdl|res://*/Models.myDB.msl;provider=System.Data.SqlClient;provider
connection string='data source=[yourdbURL];initial
catalog=myDB;persist security info=True;user
id=xxxx;password=xxx;MultipleActiveResultSets=True;App=EntityFramework
After you set this up, You need to read the url in your application and provide the DBContext. DbContext implements a constructor with connection string parameter. By default constructor is without any parameter but you can extend this. if you are using POCO class, you can amend DbContext class simply. If you use Database generated Edmx classes like me, you dont want to touch the auto generated edmx class instead of you want to create partial class in the same namespace and extend this class as below.
This is auto generated DbContext
namespace myApp.Data.Models
{
public partial class myDBEntities : DbContext
{
public myDBEntities()
: base("name=myDBEntities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
}
this is the new partial class, you create
namespace myApp.Data.Models
{
[DbConfigurationType(typeof(myDBContextConfig))]
partial class myDBEntities
{
public myDBEntities(string connectionString) : base(connectionString)
{
}
}
public class myDBContextConfig : DbConfiguration
{
public myDBContextConfig()
{
SetProviderServices("System.Data.EntityClient",
SqlProviderServices.Instance);
SetDefaultConnectionFactory(new SqlConnectionFactory());
}
}
}
After all you can get the connection string from azure settings, in your Azure Function project with the code below and provide to your DbContext
myDBEntities is the name you gave in the azure portal for your connection string.
var connString = ConfigurationManager.ConnectionStrings["myDBEntities"].ConnectionString;
using (var dbContext = new myDBEntities(connString))
{
//TODO:
}
Adding an answer in the event you cannot simply change the way you instantiate you DbContext. This would occur if you are calling code that has DbContexts being instatiated with the parameter-less constructor.
It involves using a static constructor to read your connection string from the appsettings in the azure portal and passing it in to your DbContext base constructor. This allows you to circumvent the need for a providerName and also allows you to retain use of the portal configuration without needing to hardcode anything.
Please refer to my accepted answer here: Missing ProviderName when debugging AzureFunction as well as deploying azure function
Stumbled upon this and solved it like this, inside of the Azure Function.
public static class MyFunction
{
// Putting this in more than one place in your project will cause an exception,
// if doing it after the DbConfiguration has been loaded.
static MyFunction() =>
DbConfiguration.Loaded += (_, d) =>
d.AddDefaultResolver(new global::MySql.Data.Entity.MySqlDependencyResolver());
// The rest of your function...
//[FunctionName("MyFunction")]
//public static async Task Run() {}
}
You can access the site's App Settings by going to the portal, clicking Function app settings and then Configure app settings. That will open up a blade that allows you to set all the app settings for your function app. Just use the same key and value that you'd use for your web.config.

WCF - Entity Framework - ERR_CONNECTION_RESET

I got a problem with my WCF service. Here is the
[OperationContract]
[WebGet(UriTemplate = "/needs", ResponseFormat = WebMessageFormat.Json)]
List<CustomerNeed> getAllCustomerNeeds();
When I go on the page which call this service, I got this error
GET http://localhost:666/rest/Service1.svc/needs net::ERR_CONNECTION_RESET
When I'm trying to return a string instead of a List, it works.
CustomerNeed is a class generate from my database via EntityFramework.
In my service, I'm only calling an other method which is in an other class;
public List<CustomerNeed> getAllCustomerNeeds()
{
var needs = from cn in db.CustomerNeeds
select cn;
List<CustomerNeed> list = new List<CustomerNeed>();
foreach (CustomerNeed cusN in needs)
{
list.Add(cusN);
}
return list;
}
Maybe is it because I have a foreign key in my table CustomerNeed ?
When I do "LINQ to entities" to import my database, do I have to import tables that were created because of many to many relation ?
I will recommend you to create a simple custom class which will represent your CustomerNeeds database entity, initiate this object on the server side and pass to the client application. It can help you to avoid this problem and also it is recommended way to transfer data accross the WCF services.
In this case you need to do the next steps:
1) Create a public class CustomerNeeds and mark it with the DataContract attribute. For example:
[DataContract]
public class CustomerNeeds
{
[DataMember]
public SomeDataType PropertyName {get; set;}
}
2) Initiate this object on the service, change return datatype in getAllCustomerNeeds() method from the entity class to the newly created class CustomerNeed and pass this data to the clien
And that`s all.
You haven't shown where/what db is, but I'm assuming if you're using entity framework as your tag implies it's a entities context. You might be having some issues with the context already being disposed or not newed up correctly (though I would have expected you to receive a slightly different error if that's the case.)
It looks like you're going through some unnecessary steps in your function, I would think something like this would work:
public List<CustomerNeed> getAllCustomerNeeds()
{
using (var db = new YourContext()) // plug in your context object
{
return db.CustomerNeeds.ToList();
}
}
Additionally when you say it "works as a string" are you returning something small like "hello world"? you might need to take a look at your WCF configuration to make sure it can handle the amount of data you're trying to pass back and forth.
Hope this helps!

Send localized email in GWT [duplicate]

I have an interface that extends the com.google.gwt.i18n.client.Messages class, which I use for retrieving i18n messages in my GWT application. It looks like this:
public interface MyMessages extends com.google.gwt.i18n.client.Messages {
#DefaultMessage("Hello world")
#Key("message1")
String message1();
#DefaultMessage("Hello again")
#Key("message2")
String message2();
//...
}
Normally, I create an instance of it using GWT.create() like so:
private MyMessages messages = GWT.create(MyMessages.class);
However, this does not work with server-side code, only client-side code (it throws an error saying that GWT.create() is only usable in client-side code).
The answer to a similar question points to a separate library that you can download which will let you access the i18n messages on the server, but I don't want to download any extra libraries (this seems like a simple problem, there must be a simple solution).
In summary: How can I access my i18n messages in server-side code? Thanks.
On the server side you can use the standard Java localization tools like ResourceBundle.
Look here for a tutorial how to use it.
// Create a ResourceBundle out of your property files
ResourceBundle labels =
ResourceBundle.getBundle("LabelsBundle", currentLocale);
// Get localized value
String value = labels.getString(key);
The GWT specific way of creating an interface out of your property files and providing implementations via deferred binding can not be used on sever side Java.
If you are fearless and willing to spend the time, you can implement a code generation step to read your property files and generate implementation classes for your message interface. That's exactly what the Google GWT compiler does behind the scene.
I agree with Michael.. I was having this problem of trying to "localize" messages generated on the server.... but I decided to instead just throw an Exception on the server (because it is an error message which should only happen exceptionally) which contains the message code, which the client code can then look up and show the correct localized message to the user.
There's a great library for GWT internationalization gwt-dmesg. It allows you to 'share' .properties files between clent and server. However, project looks to be abandoned by author and you must recompile it manually for use with GWT versio >= 2.1.0.
GWT.create() can only be used in client-side code.
The good thing to do is that you provide your own I18NProvider class/interface, from which then you can extend to server side I18N factory and client side I18N factory read the same resource bundle.
After that you can simply use it all over your system, unify your code.
Hope that helps.
Following vanje's answer, and considering the encoding used for the properties files (which can be troublesome as ResourceBundle uses by default "ISO-8859-1", here is the solution I came up with:
import java.io.UnsupportedEncodingException;
import java.util.Locale;
import java.util.ResourceBundle;
public class MyResourceBundle {
// feature variables
private ResourceBundle bundle;
private String fileEncoding;
public MyResourceBundle(Locale locale, String fileEncoding){
this.bundle = ResourceBundle.getBundle("com.app.Bundle", locale);
this.fileEncoding = fileEncoding;
}
public MyResourceBundle(Locale locale){
this(locale, "UTF-8");
}
public String getString(String key){
String value = bundle.getString(key);
try {
return new String(value.getBytes("ISO-8859-1"), fileEncoding);
} catch (UnsupportedEncodingException e) {
return value;
}
}
}
The way to use this would be very similar than the regular ResourceBundle usage:
private MyResourceBundle labels = new MyResourceBundle("es", "UTF-8");
String label = labels.getString(key)
Or you can use the alternate constructor which uses UTF-8 by default:
private MyResourceBundle labels = new MyResourceBundle("es");

Spring DefaultMessageListenerContainer/SimpleMessageListenerContainer (JMS/AMQP) Annotation configuration

So I'm working on a project where many teams are using common services and following a common architecture. One of the services in use is messaging, currently JMS with ActiveMQ. Pretty much all teams are required to follow a strict set of rules for creating and sending messages, namely, everything is pub-subscribe and the messages that are sent are somewhat like the following:
public class WorkDTO {
private String type;
private String subtype;
private String category;
private String jsonPayload; // converted custom Java object
}
The 'jsonPayload' comes from a base class that all teams extend from so it has common attributes.
So basically in JMS, everyone is always sending the same kind of message, but to different ActiveMQ Topics. When the message (WorkDTO) is sent via JMS, first it is converted into a JSON object then it is sent in a TextMessage.
Whenever a team wishes to create a subscriber for a topic, they create a DefaultMessageListenerContainer and configure it appropriately to receive messages (We are using Java-based Spring configuration). Basically every DefaultMessageListenerContainer that a team defines is pretty much the same except for maybe the destination from which to receive messages and the message handler.
I was wondering how anyone would approach further abstracting the messaging configuration via annotations in such a case? Meaning, since everyone is pretty much required to follow the same requirements, could something like the following be useful:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface Listener {
String destination();
boolean durable() default false;
long receiveTimeout() default -1; // -1 use JMS default
String defaultListenerMethod() default "handleMessage";
// more config details here
}
#Listener(destination="PX.Foo", durable=true)
public class FooListener {
private ObjectMapper mapper = new ObjectMapper(); // converts JSON Strings to Java Classes
public void handleMessage(TextMessage message){
String text = message.getText();
WorkDTO dto = mapper.readValue(text, WorkDto.class);
String payload = dto.getPayload();
String type = dto.getType();
String subType = dto.getSubType();
String category = dto.getCategory();
}
}
Of course I left out the part on how to configure the DefaultMessageListenerContainer by use of the #Listener annotation. I started looking into a BeanFactoryPostProcessor to create the necessary classes and add them to the application context, but I don't know how to do all that.
The reason I ask the question is that we are switching to AMQP/RabbitMQ from JMS/ActiveMQ and would like to abstract the messaging configuration even further by use of annotations. I know AMQP is not like JMS so the configuration details would be slightly different. I don't believe we will be switching from AMQP to something else.
Here teams only need to know the name of the destination and whether they want to make their subscription durable.
This is just something that popped into my head just recently. Any thoughts on this?
I don't want to do something overly complicated though so the other alternative is to create a convenience method that returns a pre-configured DefaultMessageListenerContainer given a destination and a message handler:
#Configuration
public class MyConfig{
#Autowired
private MessageConfigFactory configFactory;
#Bean
public DefaultMessageListenerContainer fooListenerContainer(){
return configFactory.getListenerContainer("PX.Foo", new FooListener(), true);
}
}
class MessageConfigFactory {
public DefaultMessageListenerContainer getListener(String destination, Object listener, boolean durable) {
DefaultMessageListenerContainer l = new DefaultMessageListenerContainer();
// configuration details here
return l;
}
}