I am using Unamanged dependencies (RGiesecke.DllExport.DllExport) and jna in a small C# function that should return a string consumed within another now java function.
Following the jna suggestions for mapping i crafted the code below:
My C# code:
[RGiesecke.DllExport.DllExport]
public static unsafe char* Test(string id)
{
unsafe
{
fixed (char *s = "test passed")
{
return s;
}
}
}
Java side:
public interface ITest extends Library{
public String Test(String id);
}
public static void main(String[] args) {
ITest nativeExample= (ITest)Native.loadLibrary("C:/native/JavaLib.dll", ITest.class);
String s = nativeExample.Test("id");
System.out.println(s);
}
So, all that is printed, is 't', because I bet all is being transmitted is the address to s[0].
Has anyone had luck mapping strings from C# to java through jna?
Plain strings in the C# code throws errors.
Have you tried returning a string instead of char? or changing char *s to char s[]
Related
I've successfully wrapped a C DLL library using JNA.
As I'm not the owner of the C development part, I would like to hide
some parameters of a C function that I've wrapped on java side.
To be more precise my java code is as follows :
public interface IJNALibrary extends Library {
// INIT FUNCTION
public int initFunction(int firstValue, int secondValue, int thirdValue);
}
On the C side I have in the *.h file :
extern "C" CSAMPLE_API int initFunction (
unsigned firstValue,
unsigned secondValue,
unsigned thirdValue);
My purpose is to directly set secondValue and thirdValue parameters to 1 and thus hide those parameters to the java API user.
I don't want the user to know that he could change the values of those parameters.
In fact I would like to have something like :
public interface IJNALibrary extends Library {
// INIT FUNCTION
public int initFunction(int firstValue);
}
and initFunction(int firstValue) calls initFunction(int firstValue, int secondValue, int thirdValue) from the C DLL part.
But this has to be done inside the java Wrapper and not from the code which calls the java Wrapper.
I'm afraid that It cannot be possible, is it?
Unless I create another C DLL (with public int initFunction(int firstValue) function) which calls the first C DLL(which embed initFunction(int firstValue, int secondValue, int thirdValue).But I would rather do it on the java side in order not to have manage 2 C DLLs.
See also below the Sample.java file which calls the mapped method defined in IJNALibrary interface.
public class Sample {
static IJNALibrary IJNAFunctions;
public static void main(String[] args) throws IOException {
System.setProperty("jna.library.path", "./librayPath");
// LOADING LIBRARY
IJNAFunctions = (IJNALibrary) Native.load("c", IJNALibrary.class);
int firstValue = 1;
int secondValue = 2;
int thirdValue = 3;
int initReturn = IJNAFunctions.initFunction(firstValue, secondValue, thirdValue);
}
}
Thanx for your help.
It depends on what you want to archive. If you want to make it easier for users to call the init, this is an option (demonstrated using gethostname from libc), which uses a Java 8 feature, which allows adding default methods to interfaces:
public class TestDefaultMethod {
public static interface LibC extends Library {
LibC INSTANCE = Native.load("c", LibC.class);
// Original binding of method
int gethostname(byte[] name, int len);
// Helper method to make it easier to call gethostname
default String gethostname() {
byte[] result = new byte[255];
LibC.INSTANCE.gethostname(result, result.length);
return Native.toString(result);
}
}
public static void main(String[] args) {
// Usage
System.out.println(LibC.INSTANCE.gethostname());
}
}
Java developers normally don't arrays to functions, which fill them and a java developer would never pass the length of the array in a separate parameter. These are artifacts of the C nature of the function. In the wrapped function an array is allocated, the native call done and the array then unwrapped. All the ugly C specialties are hidden in the default method.
If you don't want to expose the method on java at all (be warned, if your users can access the JNA library, they can circumvent your protections!), you can use a function pointer directly:
public class TestDefaultMethod {
public static interface LibC extends Library {
NativeLibrary libc = NativeLibrary.getInstance("c");
LibC INSTANCE = Native.load("c", LibC.class);
default String gethostname() {
byte[] result = new byte[255];
libc.getFunction("gethostname").invokeInt(new Object[] {result, result.length});
return Native.toString(result);
}
}
public static void main(String[] args) {
System.out.println(LibC.INSTANCE.gethostname());
}
}
Same idea as above, the default method will hide the ugly parts. In this case though the function is not accessed through the managed INSTANCE, but access through the function pointer directly.
I have one List box and I would like to set code type of it.
I create new AbstractCodeType :
public class MyCodeType extends AbstractCodeType<String, String> {
private static final long serialVersionUID = 6808664924551155395L;
public static final String ID = null;
#Override
public String getId() {
return ID;
}
#Order(10.0)
public static class UnknownCode extends AbstractCode<String> {
private static final long serialVersionUID = -1307260056726644943L;
public static final String ID = "Unknown";
#Override
protected String getConfiguredText() {
return TEXTS.get("Unknown");
}
#Override
public String getId() {
return ID;
}
}
}
and I set this code type in list box :
#Override
protected Class<? extends ICodeType<?, String>> getConfiguredCodeType() {
return MyCodeType.class;
}
But doesn't work. It return empty box.
While I was debugging I noticed that in AbstractListBox.class in initConfig method it call this code type and set code type in m_lookupCall inside setCodeTypeClass. Then inside execLoadTableData, it get call but this call return empty array when called call.getDataByAll().
I suspect that converting between code type and Lookup call does not work properly.
EDIT
I try to debug where is the problem and if follow the path :
initConfig() -> CodeLookupCall.newInstanceByService(m_codeTypeClass); (line 581)
and if you look inside CodeLookupCall ;
getDataByAll() in line 221 `resolveCodes(v)` -> BEANS.opt(m_codeTypeClass) -> bean.getInstance() -> m_producer.produce(this) -> return (T) getCache().get(createCacheKey(type));
This is in class CodeService.class in line 97 :
Class<T> type is right class and createCacheKey(type) return not null object but then getCache().get(...) return null. From this point on everything is null (what is reasonable regarding that getCodeType return null.)
This is what I found out while debugging, if it helps someone to figure out what is wrong.
It looks like your codetype class is not found by the bean manager. CodeService only finds CodeTypes in its classpath (accessible in the server).
-> You might need to move your class to the shared project.
You can find examples for code types in the contacts demo application:
https://github.com/BSI-Business-Systems-Integration-AG/org.eclipse.scout.docs/tree/releases/5.2.x/code/contacts
I tested your code snippet with Eclipse Scout Neon M4 and I could reproduce your described error.
However, it seems that this bug has been fixed with Scout Neon M5. So I suggest that you upgrade to the latest milestone version, which is recommended anyway.
So basically, I have a situation where I want to inject primitive types into a class (i.e. a String and an Integer). You can think of a URL and port number for an application as example inputs. I have three components:
Now say I have a class, which does take in these params:
public class PrimitiveParamsDIExample {
private String a;
private Integer b;
public PrimitiveParamsDIExample(String a, Integer b) {
this.a = a;
this.b = b;
}
}
So my question here is simple. How do I inject a and b into class PrimitiveParamsDIExample?
In general, this is also asking how to inject parameters that are decided on runtime as well. If I have a and b above, read from STDIN or from an input file, they're obviously going to be different from run to run.
All the more, how do I do the above within the HK2 framework?
EDIT[02/23/15]: #jwells131313, I tried your idea, but I'm getting the following error (this one for the String param; similar one for int):
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=String,parent=PrimitiveParamsDIExample,qualifiers
I set up classes exactly as you did in your answer. I also overrode the toString() method to print both variables a and b in PrimitiveParamsDIExample. Then, I added the following in my Hk2Module class:
public class Hk2Module extends AbstractBinder {
private Properties properties;
public Hk2Module(Properties properties){
this.properties = properties;
}
#Override
protected void configure() {
bindFactory(StringAFactory.class).to(String.class).in(RequestScoped.class);
bindFactory(IntegerBFactory.class).to(Integer.class).in(RequestScoped.class);
bind(PrimitiveParamsDIExample.class).to(PrimitiveParamsDIExample.class).in(Singleton.class);
}
}
So now, I created a test class as follows:
#RunWith(JUnit4.class)
public class TestPrimitiveParamsDIExample extends Hk2Setup {
private PrimitiveParamsDIExample example;
#Before
public void setup() throws IOException {
super.setupHk2();
//example = new PrimitiveParamsDIExample();
example = serviceLocator.getService(PrimitiveParamsDIExample.class);
}
#Test
public void testPrimitiveParamsDI() {
System.out.println(example.toString());
}
}
where, Hk2Setup is as follows:
public class Hk2Setup extends TestCase{
// the name of the resource containing the default configuration properties
private static final String DEFAULT_PROPERTIES = "defaults.properties";
protected Properties config = null;
protected ServiceLocator serviceLocator;
public void setupHk2() throws IOException{
config = new Properties();
Reader defaults = Resources.asCharSource(Resources.getResource(DEFAULT_PROPERTIES), Charsets.UTF_8).openBufferedStream();
load(config, defaults);
ApplicationHandler handler = new ApplicationHandler(new MyMainApplication(config));
final ServiceLocator locator = handler.getServiceLocator();
serviceLocator = locator;
}
private static void load(Properties p, Reader r) throws IOException {
try {
p.load(r);
} finally {
Closeables.close(r, false);
}
}
}
So somewhere, the wiring is messed up for me to get an UnsatisfiedDependencyException. What have I not correctly wired up?
Thanks!
There are two ways to do this, but one isn't documented yet (though it is available... I guess I need to work on documentation again...)
I'll go through the first way here.
Basically, you can use the HK2 Factory.
Generally when you start producing Strings and ints and long and scalars like this you qualify them, so lets start with two qualifiers:
#Retention(RUNTIME)
#Target( { TYPE, METHOD, FIELD, PARAMETER })
#javax.inject.Qualifier
public #interface A {}
and
#Retention(RUNTIME)
#Target( { TYPE, METHOD, FIELD, PARAMETER })
#javax.inject.Qualifier
public #interface B {}
then write your factories:
#Singleton // or whatever scope you want
public class StringAFactory implements Factory<String> {
#PerLookup // or whatever scope, maybe this checks the timestamp?
#A // Your qualifier
public String provide() {
// Write your code to get your value...
return whatever;
}
public void dispose(String instance) {
// Probably do nothing...
}
}
and for the Integer:
#Singleton // or whatever scope you want
public class IntegerBFactory implements Factory<Integer> {
#PerLookup // or whatever scope, maybe this checks the timestamp?
#B // Your qualifier
public Integer provide() {
// Write your code to get your value...
return whatever;
}
public void dispose(String instance) {
// Probably do nothing...
}
}
Now lets re-do your original class to accept these values:
public class PrimitiveParamsDIExample {
private String a;
private int b;
#Inject
public PrimitiveParamsDIExample(#A String a, #B int b) {
this.a = a;
this.b = b;
}
}
Note I changed Integer to int, well... just because I can. You can also just use field injection or method injection in the same way. Here is field injection, method injection is an exercise for the reader:
public class PrimitiveParamsDIExample {
#Inject #A
private String a;
#Inject #B
private int b;
public PrimitiveParamsDIExample() {
}
}
There are several ways to bind factories.
In a binder: bindFactory
Using automatic class analysis: addClasses
An EDSL outside a binder: buildFactory
public interface Kernel32 extends StdCallLibrary {
int GetComputerNameW(Memory lpBuffer, IntByReference lpnSize);
}
public class Kernel32Test {
private static final String THIS_PC_NAME = "tiangao-160";
private static Kernel32 kernel32;
#BeforeClass
public static void setUp() {
System.setProperty("jna.encoding", "GBK");
kernel32 = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
}
#AfterClass
public static void tearDown() {
System.setProperty("jna.encoding", null);
}
#Test
public void testGetComputerNameW() {
final Memory lpBuffer = new Memory(1024);
final IntByReference lpnSize = new IntByReference();
final int result = kernel32.GetComputerNameW(lpBuffer, lpnSize);
if (result != 0) {
throw new IllegalStateException(
"calling 'GetComputerNameW(lpBuffer, lpnSize)'failed,errorcode:" + result);
}
final int bufferSize = lpnSize.getValue();
System.out.println("value of 'lpnSize':" + bufferSize);
Assert.assertEquals(THIS_PC_NAME.getBytes().length + 1, bufferSize);
final String name = lpBuffer.getString(0);
System.out.println("value of 'lpBuffer':" + name);
Assert.assertEquals(THIS_PC_NAME, name);
}
}
The offical instructions says use byte[]、char[]、Memory or NIO Buffer for mapping char pointer in c native function.But I tried all of above, and String、WString、StringArrays、class extends PointType etc, all of them are no use.
Out parameter 'lpnSize' can return the corret buffer size,but 'lpBuffer' return 'x>'(i think it's random memory) or nothing no matter I mapping any java type.If i wrote someting to the 'lpBuffer' memory first, it would read the same things after calling native function.
How can I solve the problem?
You need to use Pointer.getString(0, true) to extract the unicode string returned by GetComputerNameW.
EDIT
You'll also need to call GetComputerNameW again with the length parameter initialized before the function will fill in the result. Either pass back the same IntByReference to a second call, or initialize the IntByReference to the size of your Memory buffer to have the buffer written to in the first call.
The problem I have is that I need to do about 40+ conversions to convert loosely typed info into strongly typed info stored in db, xml file, etc.
I'm plan to tag each type with a tuple i.e. a transformational form like this:
host.name.string:host.dotquad.string
which will offer a conversion from the input to an output form. For example, the name stored in the host field of type string, the input is converted into a dotquad notation of type string and stored back into host field. More complex conversions may need several steps, with each step being accomplished by a method call, hence method chaining.
Examining further the example above, the tuple 'host.name.string' with the field host of name www.domain.com. A DNS lookup is done to covert domain name to IP address. Another method is applied to change the type returned by the DNS lookup into the internal type of dotquad of type string. For this transformation, there is 4 seperate methods called to convert from one tuple into another. Some other conversions may require more steps.
Ideally I would like an small example of how method chains are constructed at runtime. Development time method chaining is relatively trivial, but would require pages and pages of code to cover all possibilites, with 40+ conversions.
One way I thought of doing is, is parsing the tuples at startup, and writing the chains out to an assembly, compiling it, then using reflection to load/access. Its would be really ugly and negate the performance increases i'm hoping to gain.
I'm using Mono, so no C# 4.0
Any help would be appreciated.
Bob.
Here is a quick and dirty solution using LINQ Expressions. You have indicated that you want C# 2.0, this is 3.5, but it does run on Mono 2.6. The method chaining is a bit hacky as i didn't exactly know how your version works, so you might need to tweak the expression code to suit.
The real magic really happens in the Chainer class, which takes a collection of strings, which represent the MethodChain subclass. Take a collection like this:
{
"string",
"string",
"int"
}
This will generate a chain like this:
new StringChain(new StringChain(new IntChain()));
Chainer.CreateChain will return a lambda that calls MethodChain.Execute(). Because Chainer.CreateChain uses a bit of reflection, it's slow, but it only needs to run once for each expression chain. The execution of the lambda is nearly as fast as calling actual code.
Hope you can fit this into your architecture.
public abstract class MethodChain {
private MethodChain[] m_methods;
private object m_Result;
public MethodChain(params MethodChain[] methods) {
m_methods = methods;
}
public MethodChain Execute(object expression) {
if(m_methods != null) {
foreach(var method in m_methods) {
expression = method.Execute(expression).GetResult<object>();
}
}
m_Result = ExecuteInternal(expression);
return this;
}
protected abstract object ExecuteInternal(object expression);
public T GetResult<T>() {
return (T)m_Result;
}
}
public class IntChain : MethodChain {
public IntChain(params MethodChain[] methods)
: base(methods) {
}
protected override object ExecuteInternal(object expression) {
return int.Parse(expression as string);
}
}
public class StringChain : MethodChain {
public StringChain(params MethodChain[] methods):base(methods) {
}
protected override object ExecuteInternal(object expression) {
return (expression as string).Trim();
}
}
public class Chainer {
/// <summary>
/// methods are executed from back to front, so methods[1] will call method[0].Execute before executing itself
/// </summary>
/// <param name="methods"></param>
/// <returns></returns>
public Func<object, MethodChain> CreateChain(IEnumerable<string> methods) {
Expression expr = null;
foreach(var methodName in methods.Reverse()) {
ConstructorInfo cInfo= null;
switch(methodName.ToLower()) {
case "string":
cInfo = typeof(StringChain).GetConstructor(new []{typeof(MethodChain[])});
break;
case "int":
cInfo = typeof(IntChain).GetConstructor(new[] { typeof(MethodChain[]) });
break;
}
if(cInfo == null)
continue;
if(expr != null)
expr = Expression.New(cInfo, Expression.NewArrayInit( typeof(MethodChain), Expression.Convert(expr, typeof(MethodChain))));
else
expr = Expression.New(cInfo, Expression.Constant(null, typeof(MethodChain[])));
}
var objParam = Expression.Parameter(typeof(object));
var methodExpr = Expression.Call(expr, typeof(MethodChain).GetMethod("Execute"), objParam);
Func<object, MethodChain> lambda = Expression.Lambda<Func<object, MethodChain>>(methodExpr, objParam).Compile();
return lambda;
}
[TestMethod]
public void ExprTest() {
Chainer chainer = new Chainer();
var lambda = chainer.CreateChain(new[] { "int", "string" });
var result = lambda(" 34 ").GetResult<int>();
Assert.AreEqual(34, result);
}
}
The command pattern would fit here. What you could do is queue up commands as you need different operations performed on the different data types. Those messages could then all be processed and call the appropriate methods when you're ready later on.
This pattern can be implemented in .NET 2.0.
Do you really need to do this at execution time? Can't you create the combination of operations using code generation?
Let me elaborate:
Assuming you have a class called Conversions which contains all the 40+ convertions you mentioned like this:
//just pseudo code..
class conversions{
string host_name(string input){}
string host_dotquad(string input){}
int type_convert(string input){}
float type_convert(string input){}
float increment_float(float input){}
}
Write a simple console app or something similar which uses reflection to generate code for methods like this:
execute_host_name(string input, Queue<string> conversionQueue)
{
string ouput = conversions.host_name(input);
if(conversionQueue.Count == 0)
return output;
switch(conversionQueue.dequeue())
{
// generate case statements only for methods that take in
// a string as parameter because the host_name method returns a string.
case "host.dotquad": return execute_host_dotquad(output,conversionQueue);
case "type.convert": return execute_type_convert(output, conversionQueue);
default: // exception...
}
}
Wrap all this in a Nice little execute method like this:
object execute(string input, string [] conversions)
{
Queue<string> conversionQueue = //create the queue..
case(conversionQueue.dequeue())
{
case "host.name": return execute_host_name(output,conversionQueue);
case "host.dotquad": return execute_host_dotquad(output,conversionQueue);
case "type.convert": return execute_type_convert(output, conversionQueue);
default: // exception...
}
}
This code generation application need to be executed only when your method signatures changes or when you decide to add new transformations.
Main advantages:
No runtime overhead
Easy to add/delete/change the conversions (code generator will take care of the code changes :) )
What do you think?
I apologize for the long code dump and the fact that it is in Java, rather than C#, but I found your problem quite interesting and I do not have much C# experience. Hopefully you will be able to adapt this solution without difficulty.
One approach to solving your problem is to create a cost for each conversion -- usually this is related to the accuracy of the conversion -- and then perform a search to find the best possible conversion sequence to get from one type to another.
The reason for needing a cost function is to choose among multiple conversion paths. For example, converting from an integer to a string is lossless, but there is no guarantee that every string can be represented by an integer. So, if you had two conversion chains
string -> integer -> float -> decimal
string -> float -> decimal
You would want to select the second one because it will reduce the chance of a conversion failure.
The Java code below implements such a scheme and performs a best-first search to find an optimal conversion sequence. I hope you find it useful. Running the code produces the following output:
> No conversion possible from string to integer
> The optimal conversion sequence from string to host.dotquad.string is:
> string to host.name.string, cost = -1.609438
> host.name.string to host.dns, cost = -1.609438 *PERFECT*
> host.dns to host.dotquad, cost = -1.832581
> host.dotquad to host.dotquad.string, cost = -1.832581 *PERFECT*
Here is the Java code.
/**
* Use best-first search to find an optimal sequence of operations for
* performing a type conversion with maximum fidelity.
*/
import java.util.*;
public class TypeConversion {
/**
* Define a type-conversion interface. It converts between to
* user-defined types and provides a measure of fidelity (accuracy)
* of the conversion.
*/
interface ITypeConverter<T, F> {
public T convert(F from);
public double fidelity();
// Could use reflection instead of handling this explicitly
public String getSourceType();
public String getTargetType();
}
/**
* Create a set of user-defined types.
*/
class HostName {
public String hostName;
public HostName(String hostName) {
this.hostName = hostName;
}
}
class DnsLookup {
public String ipAddress;
public DnsLookup(HostName hostName) {
this.ipAddress = doDNSLookup(hostName);
}
private String doDNSLookup(HostName hostName) {
return "127.0.0.1";
}
}
class DottedQuad {
public int[] quad = new int[4];
public DottedQuad(DnsLookup lookup) {
String[] split = lookup.ipAddress.split(".");
for ( int i = 0; i < 4; i++ )
quad[i] = Integer.parseInt( split[i] );
}
}
/**
* Define a set of conversion operations between the types. We only
* implement a minimal number for brevity, but this could be expanded.
*
* We start by creating some broad classes to differentiate among
* perfect, good and bad conversions.
*/
abstract class PerfectTypeConversion<T, F> implements ITypeConverter<T, F> {
public abstract T convert(F from);
public double fidelity() { return 1.0; }
}
abstract class GoodTypeConversion<T, F> implements ITypeConverter<T, F> {
public abstract T convert(F from);
public double fidelity() { return 0.8; }
}
abstract class BadTypeConversion<T, F> implements ITypeConverter<T, F> {
public abstract T convert(F from);
public double fidelity() { return 0.2; }
}
/**
* Concrete classes that do the actual conversions.
*/
class StringToHostName extends BadTypeConversion<HostName, String> {
public HostName convert(String from) { return new HostName(from); }
public String getSourceType() { return "string"; }
public String getTargetType() { return "host.name.string"; }
}
class HostNameToDnsLookup extends PerfectTypeConversion<DnsLookup, HostName> {
public DnsLookup convert(HostName from) { return new DnsLookup(from); }
public String getSourceType() { return "host.name.string"; }
public String getTargetType() { return "host.dns"; }
}
class DnsLookupToDottedQuad extends GoodTypeConversion<DottedQuad, DnsLookup> {
public DottedQuad convert(DnsLookup from) { return new DottedQuad(from); }
public String getSourceType() { return "host.dns"; }
public String getTargetType() { return "host.dotquad"; }
}
class DottedQuadToString extends PerfectTypeConversion<String, DottedQuad> {
public String convert(DottedQuad f) {
return f.quad[0] + "." + f.quad[1] + "." + f.quad[2] + "." + f.quad[3];
}
public String getSourceType() { return "host.dotquad"; }
public String getTargetType() { return "host.dotquad.string"; }
}
/**
* To find the best conversion sequence, we need to instantiate
* a list of converters.
*/
ITypeConverter<?,?> converters[] =
{
new StringToHostName(),
new HostNameToDnsLookup(),
new DnsLookupToDottedQuad(),
new DottedQuadToString()
};
Map<String, List<ITypeConverter<?,?>>> fromMap =
new HashMap<String, List<ITypeConverter<?,?>>>();
public void buildConversionMap()
{
for ( ITypeConverter<?,?> converter : converters )
{
String type = converter.getSourceType();
if ( !fromMap.containsKey( type )) {
fromMap.put( type, new ArrayList<ITypeConverter<?,?>>());
}
fromMap.get(type).add(converter);
}
}
public class Tuple implements Comparable<Tuple>
{
public String type;
public double cost;
public Tuple parent;
public Tuple(String type, double cost, Tuple parent) {
this.type = type;
this.cost = cost;
this.parent = parent;
}
public int compareTo(Tuple o) {
return Double.compare( cost, o.cost );
}
}
public Tuple findOptimalConversionSequence(String from, String target)
{
PriorityQueue<Tuple> queue = new PriorityQueue<Tuple>();
// Add a dummy start node to the queue
queue.add( new Tuple( from, 0.0, null ));
// Perform the search
while ( !queue.isEmpty() )
{
// Pop the most promising candidate from the list
Tuple tuple = queue.remove();
// If the type matches the target type, return
if ( tuple.type == target )
return tuple;
// If we have reached a dead-end, backtrack
if ( !fromMap.containsKey( tuple.type ))
continue;
// Otherwise get all of the possible conversions to
// perform next and add their costs
for ( ITypeConverter<?,?> converter : fromMap.get( tuple.type ))
{
String type = converter.getTargetType();
double cost = tuple.cost + Math.log( converter.fidelity() );
queue.add( new Tuple( type, cost, tuple ));
}
}
// No solution
return null;
}
public static void convert(String from, String target)
{
TypeConversion tc = new TypeConversion();
// Build a conversion lookup table
tc.buildConversionMap();
// Find the tail of the optimal conversion chain.
Tuple tail = tc.findOptimalConversionSequence( from, target );
if ( tail == null ) {
System.out.println( "No conversion possible from " + from + " to " + target );
return;
}
// Reconstruct the conversion path (skip dummy node)
List<Tuple> solution = new ArrayList<Tuple>();
for ( ; tail.parent != null ; tail = tail.parent )
solution.add( tail );
Collections.reverse( solution );
StringBuilder sb = new StringBuilder();
Formatter formatter = new Formatter(sb);
sb.append( "The optimal conversion sequence from " + from + " to " + target + " is:\n" );
for ( Tuple tuple : solution ) {
formatter.format( "%20s to %20s, cost = %f", tuple.parent.type, tuple.type, tuple.cost );
if ( tuple.cost == tuple.parent.cost )
sb.append( " *PERFECT*");
sb.append( "\n" );
}
System.out.println( sb.toString() );
}
public static void main(String[] args)
{
// Run two tests
convert( "string", "integer" );
convert( "string", "host.dotquad.string" );
}
}