get list of services implementations with OSGi declarative services - eclipse

I have a very simple example of declarative services. I'm following this tutorial http://www.eclipsezone.com/eclipse/forums/t97690.html?start=0. Every thing is working as expected. However, I cannot figure out how I can make the "SampleImporter" (which is the bundle that is expected to use other bundles' services) aware of the list of "SampleExporter" (bundle providing a service). In other words, I want the "SamlpeImporter" to see the ID of the bundle(s) that it is eventually using. This information is very useful for my application.
here is the XML file for SampleExporter:
<?xml version="1.0"?>
<component name="samplerunnable">
<implementation class="org.example.ds.SampleRunnable"/>
<property name="ID" value="expoter" />
<service>
<provide interface="java.lang.Runnable"/>
</service>
while for the SampleImporter:
<?xml version="1.0"?>
<component name="commandprovider1">
<implementation class="org.example.ds.SampleCommandProvider1"/>
<service>
<provide interface="org.eclipse.osgi.framework.console.CommandProvider"/>
</service>
<reference name="RUNNABLE"
interface="java.lang.Runnable"
bind="setRunnable"
unbind="unsetRunnable"
cardinality="0..1"
policy="dynamic"/>
</component>
In the Importer side, I have the following function:
public class SampleCommandProvider1 implements CommandProvider {
private Runnable runnable;
public synchronized void setRunnable(Runnable r) {
runnable = r;
}
public synchronized void unsetRunnable(Runnable r) {
runnable = null;
}
public synchronized void _run(CommandInterpreter ci) {
if(runnable != null) {
runnable.run();
} else {
ci.println("Error, no Runnable available");
}
}
public String getHelp() {
return "\trun - execute a Runnable service";
}
}
This works fine but then if I want to get the value of the property, using
public synchronized void setRunnable(Runnable r, Map properties)
or
public synchronized void setRunnable(Runnable r, ServiceReference reference)
the method run of the exporter is never called which means that the bind function (setRunnable is not called).Hwever, using the console command "services" I see that the exporter bundle is used by the imporeter one. Also, using ss and ls I can see that the component eporter is "satisfied".
What is wrong with my implementetion?
Thanks in advance
Cheers
Marie

The following bind signature is not supported by any version of DS:
public void setRunnable(Runnable r, ServiceReference ref)
Instead you will have to take only the ServiceReference and use either the ComponentContext or BundleContext to access the service instance object.
Alternatively if you want a more POJO-style way of accessing service properties, the following bind signature is allowed in DS 1.1 (but not in DS 1.0):
public void setRunnable(Runnable r, Map properties)
To access DS 1.1 features, you need to add the correct namespace to your XML as follows:
<component xmlns='http://www.osgi.org/xmlns/scr/v1.1.0' name='...'>
By the way, I wrote this original article a very long time ago! These days I would use bnd annotations to avoid having to write the XML document by hand.

Related

TimerTrigger does not inject EF Database Context

I have an Azure Function (v3) using Entity Framework (3.0.11).
I am attempting to run the code on a TimerTrigger however injecting the database within a timer trigger does not seem to work.
Here are some (rapidly anonymized) code samples.
the CSPROJ
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AzureFunctionsVersion>v3</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AzureFunctions.Extensions.DependencyInjection" Version="1.1.3" />
<PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.10" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.11" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
</Project>
a model and DBContext
namespace DataImport
{
public class Sample
{
public int SampleID { get; set; }
public string SampleField { get; set; }
}
public class MyDbContext : DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> options) : base(options) { }
public virtual DbSet<Sample> MyRecords { get; set; }
}
}
a startup class
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.EntityFrameworkCore;
[assembly: FunctionsStartup(typeof(DataImport.Startup))]
namespace DataImport
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
string con = builder.GetContext().Configuration.GetSection("ConnectionStrings:DefaultConnection").Value.ToString();
builder.Services.AddDbContext<MyDbContext>(config => config.UseSqlServer(con));
}
}
}
a Program.cs
using System;
using System.Linq;
using System.Threading.Tasks;
using AzureFunctions.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace DataImport
{
public class Program
{
private readonly MyDbContext db;
public Program(MyDbContext database)
{
db = database;
}
[FunctionName("SampleFunction_works")]
public async Task<IActionResult> HttpRun([HttpTrigger(AuthorizationLevel.Anonymous, "GET")] HttpRequest req, ILogger log, ExecutionContext context)
{
log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
var foo = db.MyRecords.Where(c => c.SampleField == "000").FirstOrDefault();
await db.MyRecords.AddAsync(new Sample());
log.LogInformation(foo.SampleField);
return new OkObjectResult(foo);
}
[FunctionName("SampleFunction_no_work")]
public static void Run([TimerTrigger("%TimerInterval%")] TimerInfo myTimer, ILogger log, ExecutionContext context)
{
log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
// tried dozens of things here, nothing works sofar.
// injecting IServiceProvider fails,
// what other ways to solve this?
// could a timer trigger perhaps make an HTTP call to the HttpRun function above?
}
}
}
when running the SampleFunction_works with a database connection we see the result of the function call as successful. Injection works within the context of an HTTP trigger. On a timertrigger however, this does not work.
I have tried a good 8 hours of different things at this point:
unsurprisingly accessing the db without injecting turns up a null property, no magic there.
adding MyDbContext to the Run function fails because it can't be injected public static void Run([TimerTrigger("%TimerInterval%")] TimerInfo myTimer, ILogger log, MyDbContext db)
Microsoft.Azure.WebJobs.Host: Error indexing method 'SampleFunction_no_work'. Microsoft.Azure.WebJobs.Host: Cannot bind parameter 'db' to type MyDbContext. Make sure the parameter Type is supported by the binding. If you're using binding MyDbContext(e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).
doing the same as the previous but by adding IServiceProvider services to the method signature results in a similar error message, adding the line db = services.GetRequiredService<MyDbContext>(); is irrelevant if it can't get injected
some variables DO seem to be injectable in this scope ExecutionContext for example, but there doesn't seem to be anything I can use on that object.
Is there a way to:
inject a timer trigger with a database?
use a timer trigger to CALL an HTTPtrigger located within the same function?
any other solution that will allow me to access an EF database within a timertrigger context?
update:
#StevePy's comment below was correct. You can make a timertrigger's RUN method non-static and leverage the power of injection. I'd previously read that this wasn't possible, but it appears that information was out of date.
See this BLOG post for more info: https://marcroussy.com/2019/05/31/azure-functions-built-in-dependency-injection/
Or grab this sample code to run for yourself locally:
[FunctionName("MY_FANCY_FUCNTION")]
public async Task Run([TimerTrigger("%TimerInterval%")] TimerInfo myTimer, ILogger ilog, ExecutionContext context)
{
ilog.LogInformation($"TIMER EXECUTED IS DB NULL? '{db == null}'");
// note that the key part of this DOES log out as NOT NULL
// which is what we want.
return;
await Main(ilog, context);
}
Try using a non-static Run method. Many examples use a static method which can be recommended where you don't have dependencies and the method is pure. (since Functional methods should strive to be pure) See https://marcroussy.com/2019/05/31/azure-functions-built-in-dependency-injection/ for an example of TimerTriggers /w DI.
#StevePy's comment below my questions was correct. You can make a timertrigger's RUN method non-static and leverage the power of injection. I'd previously read that this wasn't possible, but it appears that information was out of date.
See this BLOG post for more info: https://marcroussy.com/2019/05/31/azure-functions-built-in-dependency-injection/
Or grab this sample code to run for yourself locally:
[FunctionName("MY_FANCY_FUCNTION")]
public async Task Run([TimerTrigger("%TimerInterval%")] TimerInfo myTimer, ILogger ilog, ExecutionContext context)
{
ilog.LogInformation($"TIMER EXECUTED IS DB NULL? '{db == null}'");
// note that the key part of this DOES log out as NOT NULL
// which is what we want.
return;
await Main(ilog, context);
}
note that in the interests of giving credit where it is due, I'll switch the accepted answer to Steve's if and when he responds, but I'm marking as answered now to ensure that the question has an accepted answer.

Is it possible to apply xml Templates in JAVA DSL Runner

we have a lot of old citrus xml Testcases and templates in our Projects. After Upgrading to newer version I decided to make the switch to Java DSL. Is it possible to keep using the old templates? If i Try to do so, I get a "No bean named .. is defined" exception.
I tried the to import the template file via #ImportResource but without success.
You can write a simple custom test action that loads the template and executes it with current test context:
Given the following template in templates/hello-template.xml
<spring:beans xmlns="http://www.citrusframework.org/schema/testcase"
xmlns:spring="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.citrusframework.org/schema/testcase http://www.citrusframework.org/schema/testcase/citrus-testcase.xsd">
<template name="helloTemplate">
<echo>
<message>Hello ${user}</message>
</echo>
</template>
</spring:beans>
You can write a custom test action for loading that template:
public class TemplateTest extends TestNGCitrusTestRunner {
#Test
#CitrusTest
public void test() {
run(new CallTemplateAction("templates/hello-template.xml", "helloTemplate"));
}
private class CallTemplateAction extends AbstractTestAction {
private final String templateName;
private final String templateLocation;
public CallTemplateAction(String templateLocation, String templateName) {
this.templateLocation = templateLocation;
this.templateName = templateName;
}
#Override
public void doExecute(TestContext testContext) {
Template template = new ClassPathXmlApplicationContext(new String[] { templateLocation },
testContext.getApplicationContext())
.getBean(templateName, Template.class);
template.getParameter().put("user", "foo");
template.execute(testContext);
}
}
}
You should probably cache the template instance and/or close the application context when done with the action.

Spring3+mybatis3 generic dao(or mapper)

I have integrated spring3 + mybatis3,and it worked good.
Then I found that many SQLs will be written like this:
select * from table1 where id=#{id}
select * from table2 where id=#{id}
We don't need repeat as a programmer!
So,Can we defined a genric dao or mapper to avoid this repeat? Provide a demo is better.
Some links can help is kindly too.
It bothers me for a long time,need a hand.
I want to write my code like this:
Test.java:
just a enity.
TestMapper.java:
public interface TestMapper extends GenericMapper {
public void testMethod1(String..);
//other methods here
}
GenericMapper.java:
public interface GenericMapper<T, PK> {
public T select(PK id);
public boolean update(T t);
public boolean delete(PK id);
public boolean insert(T t);
}
defind bean in spring-xx.xml:
<bean id="testMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
<property name="mapperInterface" value="com.jackson.mapper.TestMapper" />
</bean>
Call in my service layer like this:
// Please**NOTICE**:method select is defined in GenericMapper.
TestService.java:
public TestMapper testMapper;
public Test get(Integer id) {
Test test = testMapper.select(id);
doSmth(test);
}
Just a few minutes ago,Someone said we can use a Interceptor interface. And I am trying now.
Thanks!
--jackson
One of the options is to use mybatis-generator.
http://classnotfound.net/blog/mybatisspringgenerics/
I think this tutorial has exactly what you are looking for. I am not sure what version of Java (or editor config) he is running but I had to add on the Dao methods and suppress the unchecked castings (T) and raw types warnings to get it work on eclipse mars 2 using java 8.
I know I might be late but this library from google will address your issue. I have been using it in over 10 projects.

How to consume a complex object from a sproc using WCF Data Services / OData?

Using WCF Data Services (and the latest Entity Framework), I want to return data from a stored procedure. The returned sproc fields do not match 1:1 any entity in my db, so I create a new complex type for it in the edmx model (rather than attaching an existing entity):
Right-click the *.edmx model / Add / Function Import
Select the sproc (returns three fields) - GetData
Click Get Column Information
Add the Function Import Name: GetData
Click Create new Complex Type - GetData_Result
In the service, I define:
[WebGet]
public List<GetData_Result> GetDataSproc()
{
PrimaryDBContext context = new PrimaryDBContext();
return context.GetData().ToList();
}
I created a quick console app to test, and added a reference to System.Data.Services and System.Data.Services.Client - this after running Install-Package EntityFramework -Pre, but the versions on the libraries are 4.0 and not 5.x.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Services.Client;
using ConsoleApplication1.PrimaryDBService;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DataServiceContext context = new DataServiceContext(new Uri("http://localhost:50100/PrimaryDataService1.svc/"));
IEnumerable<GetData_Result> result = context.Execute<GetData_Result>(new Uri("http://localhost:50100/PrimaryDataService1.svc/GetDataSproc"));
foreach (GetData_Result w in result)
{
Console.WriteLine(w.ID + "\t" + w.WHO_TYPE_NAME + "\t" + w.CREATED_DATE);
}
Console.Read();
}
}
}
I didn't use the UriKind.Relative or anything else to complicate this.
When I navigate in the browser to the URL, I see data, but when I consume it in my console app, I get nothing at all.
Adding tracing to the mix:
<system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true">
<listeners>
<add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData="c:\temp\WebWCFDataService.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
... and opening using the Microsoft Service Trace Viewer, I see two idential warnings:
Configuration evaluation context not found.
<E2ETraceEvent xmlns="http://schemas.microsoft.com/2004/06/E2ETraceEvent">
<System xmlns="http://schemas.microsoft.com/2004/06/windows/eventlog/system">
<EventID>524312</EventID>
<Type>3</Type>
<SubType Name="Warning">0</SubType>
<Level>4</Level>
<TimeCreated SystemTime="2012-04-03T14:50:11.8355955Z" />
<Source Name="System.ServiceModel" />
<Correlation ActivityID="{66f1a241-2613-43dd-be0c-341149e37d30}" />
<Execution ProcessName="WebDev.WebServer40" ProcessID="5176" ThreadID="10" />
<Channel />
<Computer>MyComputer</Computer>
</System>
<ApplicationData>
<TraceData>
<DataItem>
<TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Warning">
<TraceIdentifier>http://msdn.microsoft.com/en-US/library/System.ServiceModel.EvaluationContextNotFound.aspx</TraceIdentifier>
<Description>Configuration evaluation context not found.</Description>
<AppDomain>fd28c9cc-1-129779382115645955</AppDomain>
</TraceRecord>
</DataItem>
</TraceData>
</ApplicationData>
</E2ETraceEvent>
So why am I able to see data from the browser, but not when consumed in my app?
-- UPDATE --
I downloaded the Microsoft WCF Data Services October 2011 CTP which exposed DataServiceProtocolVersion.V3, created a new host and client and referenced Microsoft.Data.Services.Client (v4.99.2.0). Now getting the following error on the client when trying iterate in the foreach loop:
There is a type mismatch between the client and the service. Type
'ConsoleApplication1.WcfDataServiceOctCTP1.GetDataSproc_Result' is an
entity type, but the type in the response payload does not represent
an entity type. Please ensure that types defined on the client match
the data model of the service, or update the service reference on the
client.
I tried the same thing by referencing the actual entity - works fine, so same issue.
Recap: I want to create a high-performing WCF service DAL (data access layer) that returns strongly-typed stored procedures. I initially used a "WCF Data Services" project to accomplish this. It seems as though it has its limitations, and after reviewing performance metrics of different ORM's, I ended up using Dapper for the data access inside a basic WCF Service.
I first created the *.edmx model and created the POCO for my sproc.
Next, I created a base BaseRepository and MiscDataRepository:
namespace WcfDataService.Repositories
{
public abstract class BaseRepository
{
protected static void SetIdentity<T>(IDbConnection connection, Action<T> setId)
{
dynamic identity = connection.Query("SELECT ##IDENTITY AS Id").Single();
T newId = (T)identity.Id;
setId(newId);
}
protected static IDbConnection OpenConnection()
{
IDbConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["PrimaryDBConnectionString"].ConnectionString);
connection.Open();
return connection;
}
}
}
namespace WcfDataService.Repositories
{
public class MiscDataRepository : BaseRepository
{
public IEnumerable<GetData_Result> SelectAllData()
{
using (IDbConnection connection = OpenConnection())
{
var theData = connection.Query<GetData_Result>("sprocs_GetData",
commandType: CommandType.StoredProcedure);
return theData;
}
}
}
}
The service class:
namespace WcfDataService
{
public class Service1 : IService1
{
private MiscDataRepository miscDataRepository;
public Service1()
: this(new MiscDataRepository())
{
}
public Service1(MiscDataRepository miscDataRepository)
{
this.miscDataRepository = miscDataRepository;
}
public IEnumerable<GetData_Result> GetData()
{
return miscDataRepository.SelectAllData();
}
}
}
... and then created a simple console application to display the data:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Service1Client client = new Service1Client();
IEnumerable<GetData_Result> result = client.GetData();
foreach (GetData_Result d in result)
{
Console.WriteLine(d.ID + "\t" + d.WHO_TYPE_NAME + "\t" + d.CREATED_DATE);
}
Console.Read();
}
}
}
I also accomplished this using PetaPOCO, which took much less time to setup than Dapper - a few lines of code:
namespace PetaPocoWcfDataService
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
public class Service1 : IService1
{
public IEnumerable<GetData_Result> GetData()
{
var databaseContext = new PetaPoco.Database("PrimaryDBContext"); // using PetaPOCO for data access
databaseContext.EnableAutoSelect = false; // use the sproc to create the select statement
return databaseContext.Query<GetData_Result>("exec sproc_GetData");
}
}
}
I like how quick and simple it was to setup PetaPOCO, but using the repository pattern with Dapper will scale much better for an enterprise project.
It was also quite simple to create complex objects directly from the EDMX - for any stored procedure, then consume them.
For example, I created complex type return type called ProfileDetailsByID_Result based on the sq_mobile_profile_get_by_id sproc.
public ProfileDetailsByID_Result GetAllProfileDetailsByID(int profileID)
{
using (IDbConnection connection = OpenConnection("DatabaseConnectionString"))
{
try
{
var profile = connection.Query<ProfileDetailsByID_Result>("sq_mobile_profile_get_by_id",
new { profileid = profileID },
commandType: CommandType.StoredProcedure).FirstOrDefault();
return profile;
}
catch (Exception ex)
{
ErrorLogging.Instance.Fatal(ex); // use singleton for logging
return null;
}
}
}
So using Dapper along with some EDMX entities seems to be a nice quick way to get things going. I may be mistaken, but I'm not sure why Microsoft didn't think this all the way through - no support for complex types with OData.
--- UPDATE ---
So I finally got a response from Microsoft, when I raised the issue over a month ago:
We have done research on this and we have found that the Odata client
library doesn’t support complex types. Therefore, I regret to inform
you that there is not much that we can do to solve it.
*Optional: In order to obtain a solution for this issue, you have to use a Xml to Linq kind of approach to get the complex types.
Thank you very much for your understanding in this matter. Please let
me know if you have any questions. If we can be of any further
assistance, please let us know.
Best regards,
Seems odd.

MEF Contrib Provider Model Not Importing Parts

I have been trying to use the configurable provider model for handling my MEF imports and exports from MEF Contrib (link). I've read the Codeplex documentation and Code Junkie's blog post (link); however, I can't seem to get the container to create the parts. Where am I going wrong?
Program.cs
namespace MEFTest
{
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.Run();
}
// [ImportMany("command", typeof(IHelp))]
public IEnumerable<IHelp> Commands { get; set; }
void Run()
{
Compose();
foreach(IHelp cmd in Commands)
{
Console.WriteLine(cmd.HelpText);
}
Console.ReadKey();
}
void Compose()
{
var provider = new ConfigurableDefinitionProvider("mef.configuration");
var catalog = new DefinitionProviderPartCatalog<ConfigurableDefinitionProvider>(provider);
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}
}
TestCommand.cs
namespace MEFTest
{
//[Export("command", typeof(IHelp))]
public class TestCommand : IHelp
{
private string _helpText = "This is a test.";
public string CommandName
{
get { return "Test"; }
}
public string HelpText
{
get { return _helpText; }
}
}
}
App.Config section:
<mef.configuration>
<parts>
<part type="MEFTest.TestCommand, MEFTest">
<exports>
<export contract="IHelp" />
</exports>
</part>
<part type="MEFTest.Program, MEFTest">
<imports>
<import member="Commands" contract="IHelp" />
</imports>
</part>
</parts>
</mef.configuration>
I don't get any build errors and it runs fine if I switch to the typical attribute-based system that is part of the MEF core (with the appropriate catalog too). Program.Commands is always NULL in the above example. I tried to just use a singular property instead of a collection and get the same results.
When I debug I can get the provider.Parts collection so I know it's accessing the configuration information correctly; however, I get an InvalidOperationException whenever I debug and try to drill into catalog.Parts.
Anyone have any experience as to where I'm going wrong here?
As documented here, you also need this in your config file:
<configSections>
<section
name="mef.configuration"
type="MefContrib.Models.Provider.Definitions.Configurable.PartCatalogConfigurationSection, MefContrib.Models.Provider" />
</configSections>
If you already have that, then it might be interesting to show us the stack trace of the InvalidOperationException that you get when accessing provider.Parts.
I had the same problems and could not get it to work, but here are some details:
It seems that ComposeParts() does not work as expected (at least in the version I used) because it uses static methods, based on Reflection to find all required Imports (so it seems that this part cannot be changed from outside of MEF). Unfortunately we want to use xml configuration and not the MEF attributes.
It works if you add [Import] attributes to the members of the class you you use with ComposeParts(). In your case this would be "Programm". In this case all exports defined in the configuration file will be found.
I could not find any documentation or examples on the MEF Contrib page relating to that problem. Also there is no unittest in the MEF contrib projekt that uses ComposeParts().
A workaround would be to use container.GetExportedValues() to retrieve the values, but in this case you have to set the classes members manually.
Hope that helps.