I have a config.properties files with names like this:
names=john,jane
Then I have a class that access that file and loads the names. And I have another class that get a name from somewhere and if that name is in the config.properties prints "SUCCESS". The problem is that if I add names to the config.properties, I have to run again the program, it doesn´t load dynamically. What is the alternative to this?
public class PropertiesFile {
private static final char OPENFILES_CONFIG_DELIMITER = ',';
private static final String OPENFILES_CONFIG = "config.properties";
private static org.apache.commons.configuration2.Configuration config;
static {
try {
Parameters params = new Parameters();
FileBasedConfigurationBuilder<FileBasedConfiguration> builder = new FileBasedConfigurationBuilder<FileBasedConfiguration>(PropertiesConfiguration.class)
.configure(params.properties()
.setFileName(OPENFILES_CONFIG)
.setListDelimiterHandler(new DefaultListDelimiterHandler(OPENFILES_CONFIG_DELIMITER)));
config = builder.getConfiguration(); }
catch (ConfigurationException cE) {
//...
}
}
public static Set<String> load() {
String[] thingsToExecute = config.getStringArray("names");
return new HashSet<String>(Arrays.asList(thingsToExecute));
}
}
public class OpenFiles {
private static Set<String> toExecute;
public static void main(String[] args) {
updateToExecute();
connect();
}
private static void connect() {
//code that obatins JSONObject
if (obj4.has("name")) {
String personName = obj4.get("name").toString();
updateToExecute();
if (toExecute.contains(personName)) {
System.out.println("SUCCESS");
} else {
System.out.println(personName+"is not in the list");
}
}
}
private static void updateToExecute() {
toExecute = PropertiesFile.load();
}
}
Related
We used a special database,so i want to write a database connection Pool,there is something wrong with the code, when i debug into the static block,at first JVM worked in the Properties properties = new Properties(); but next step is int i = 0; i dont know why it ingored the other code in the static block
public class GoldDataSource {
private static String goldip;
private static int goldport;
private static String username;
private static String password;
private static int maxPollSize;
private static LinkedList<Server> list = new LinkedList<Server>();
private static Logger logger = LoggerFactory.getLogger(GoldDataSource.class);
static {
try {
Properties properties = new Properties();
InputStream is = GoldDataSource.class.getClassLoader().getResourceAsStream("/conf/db/gold.properties");
properties.load(is);
goldip = properties.getProperty("gold.ip");
goldport = Integer.parseInt(properties.getProperty("gold.port"));
username = properties.getProperty("gold.username");
password = properties.getProperty("gold.password");
maxPollSize = Integer.parseInt(properties.getProperty("gold.pool.maxPollSize"));
for (int i = 0; i < maxPollSize; i++) {
Server server = new ServerImpl(goldip, goldport, username, password);
server.connect();
server.login();
list.add(server);
}
} catch (Exception e) {
....
}
}
public synchronized static Server getServer() {
try {
int i = 0;
while (true) {
Server aServer = list.removeFirst();
if (aServer != null) {
return aServer;
} else {
if (i >= 3) {
return aServer;
}
Thread.sleep(500);
i++;
}
}
} catch (Exception e) {
...
return null;
}
}
public static void closeServer(Server aServer) {
list.addLast(aServer);
}}
I used Server server = GoldDataSource.getServer(); to get connection,but when it executed Properties properties = new Properties();then jump into the code int i = 0; which in the getServer() method
I edited the code with singleton pattern,it worked ,but i still do not understand why the old code didn't worked , and i catched "java.lang.reflect.InvocationTargetException" in the first catch block old code.
public class GoldDataSource {
private static String goldip;
private static int goldport;
private static String username;
private static String password;
private static int maxPollSize;
private static LinkedList<Server> list = new LinkedList<Server>();
private static InputStream is;
private static GoldDataSource aDataSource = new GoldDataSource();
private static Logger logger = LoggerFactory.getLogger(GoldDataSource.class);
private goldDataSource() {
try {
Properties properties = new Properties();
is = GoldDataSource.class.getClassLoader().getResourceAsStream("/conf/db/gold.properties");
properties.load(is);
goldip = properties.getProperty("gold.ip");
goldport = Integer.parseInt(properties.getProperty("gold.port"));
username = properties.getProperty("gold.username");
password = properties.getProperty("gold.password");
maxPollSize = Integer.parseInt(properties.getProperty("gold.pool.maxPollSize"));
for (int i = 0; i < maxPollSize; i++) {
Server server = new ServerImpl(goldip, goldport, username, password);
server.connect();
server.login();
list.add(server);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static goldDataSource getDateSource() {
return aDataSource;
}
public synchronized Server getServer() {
try {
int i = 0;
while (true) {
Server aServer = list.removeFirst();
if (aServer != null) {
return aServer;
} else {
if (i >= 3) {
return aServer;
}
Thread.sleep(500);
i++;
}
}
} catch (Exception e) {
logger.error("get connection error:" + e.toString());
return null;
}
}
public void closeServer(Server aServer) {
list.addLast(aServer);
}
}
I have a Vaadin 6 application, in which I want to display several images in a table.
To do this, I define following data model.
private BeanContainer<byte[],UserProductImageBean> productImageData;
productImageData = new BeanContainer<byte[],
UserProductImageBean>(UserProductImageBean.class);
productImageData.setBeanIdProperty("userProductImageId");
Table is defined as follows.
productImagesTable = new Table("Product images", productImageData);
productImagesTable.setItemIconPropertyId("imageResource");
I get the image data from the server in form of UserProductImage instances:
public class UserProductImage {
private byte[] userProductImageId;
private byte[] imageData;
private byte[] userProductId;
private String fileName;
private String creatorEmail;
private String mimeType;
public byte[] getImageData() {
return imageData;
}
public void setImageData(final byte[] aImageData) {
imageData = aImageData;
}
public byte[] getUserProductId() {
return userProductId;
}
public void setUserProductId(final byte[] aUserProductId) {
userProductId = aUserProductId;
}
public String getFileName() {
return fileName;
}
public void setFileName(final String aFileName) {
fileName = aFileName;
}
public String getCreatorEmail() {
return creatorEmail;
}
public void setCreatorEmail(final String aCreatorEmail) {
creatorEmail = aCreatorEmail;
}
public String getMimeType() {
return mimeType;
}
public void setMimeType(final String aMimeType) {
mimeType = aMimeType;
}
public byte[] getUserProductImageId() {
return userProductImageId;
}
public void setUserProductImageId(final byte[] aUserProductImageId) {
userProductImageId = aUserProductImageId;
}
}
When I update the table data, I convert UserProductImage instances into UserProductImageBean:
final List<UserProductImage> userProductImages = response.getUserImages();
for (final UserProductImage curImage : userProductImages)
{
productImageData.addBean(UserProductImageBean.create(curImage,
My.getInstance()));
}
UserProductImageBean adds an image resource property:
public class UserProductImageBean extends UserProductImage {
private UserProductImageResource imageResource;
private UserProductImageBean()
{
}
public UserProductImageResource getImageResource() {
return imageResource;
}
public static UserProductImageBean create(final UserProductImage aUserProductImage,
final Application aApplication)
{
final UserProductImageBean result = new UserProductImageBean();
result.setImageData(aUserProductImage.getImageData());
result.setUserProductId(aUserProductImage.getUserProductId());
result.setCreatorEmail(aUserProductImage.getCreatorEmail());
result.setMimeType(aUserProductImage.getMimeType());
result.setFileName(aUserProductImage.getFileName());
result.setUserProductImageId(aUserProductImage.getUserProductImageId());
result.imageResource = new UserProductImageResource(aUserProductImage, aApplication);
return result;
}
}
public class UserProductImageResource implements ApplicationResource, Resource {
private final UserProductImage userProductImage;
private final Application application;
public UserProductImageResource(final UserProductImage aUserProductImage,
final Application aApplication) {
userProductImage = aUserProductImage;
application = aApplication;
}
public String getMIMEType() {
return userProductImage.getMimeType();
}
public DownloadStream getStream() {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(userProductImage
.getImageData());
final DownloadStream downloadStream = new DownloadStream(byteArrayInputStream,
userProductImage.getMimeType(), userProductImage.getFileName());
return downloadStream;
}
public Application getApplication() {
return application;
}
public String getFilename() {
return userProductImage.getFileName();
}
public long getCacheTime() {
return 0;
}
public int getBufferSize() {
return userProductImage.getImageData().length;
}
}
As a result of these operations I get a table like shown below.
How can I change the code so that the property imageResource is displayed as an image?
Update 1 (16.10.2014 22:21 MSK):
I've implemented the class ImageColumnGenerator as suggested by Zigac.
public class ImageColumnGenerator implements Table.ColumnGenerator {
private static final Logger LOGGER = LoggerFactory.getLogger(ImageColumnGenerator.class);
public final static String IMAGE_FIELD = "image";
public Object generateCell(final Table aTable, final Object aItemId, final Object aColumnId) {
if (!IMAGE_FIELD.equals(aColumnId))
{
return null;
}
final BeanItem<UserProductImageBean> beanItem = (BeanItem<UserProductImageBean>)
aTable.getItem(aItemId);
final UserProductImageResource imageResource = beanItem.getBean().getImageResource();
LOGGER.debug("imageResource: " + imageResource);
final Embedded embedded = new Embedded("", imageResource);
return embedded;
}
}
When I create the table, I specify the column generator like this:
productImagesTable.addGeneratedColumn(ImageColumnGenerator.IMAGE_FIELD,
new ImageColumnGenerator());
But when I open the page, I get the following exception.
java.lang.NullPointerException: Parameters must be non-null strings
at com.vaadin.terminal.gwt.server.JsonPaintTarget.addAttribute(JsonPaintTarget.java:420)
at com.vaadin.terminal.gwt.server.JsonPaintTarget.addAttribute(JsonPaintTarget.java:387)
at com.vaadin.ui.Embedded.paintContent(Embedded.java:142)
at com.vaadin.ui.AbstractComponent.paint(AbstractComponent.java:781)
at com.vaadin.ui.Table.paintRow(Table.java:3356)
at com.vaadin.ui.Table.paintRows(Table.java:3169)
at com.vaadin.ui.Table.paintContent(Table.java:2776)
at com.vaadin.ui.AbstractComponent.paint(AbstractComponent.java:781)
at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.writeUidlResponce(AbstractCommunicationManager.java:1044)
at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.paintAfterVariableChanges(AbstractCommunicationManager.java:925)
at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.doHandleUidlRequest(AbstractCommunicationManager.java:792)
at com.vaadin.terminal.gwt.server.CommunicationManager.handleUidlRequest(CommunicationManager.java:318)
at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.service(AbstractApplicationServlet.java:501)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
Update 2 (17.10.2014 12:16): I managed to fix that problem (NPE), but now I have another one - see this question.
Update 3 (19.10.2014 00:02 MSK): This is what the table looks like, when the window is opened for the first time.
When the list of images is received from a web service, the table shrinks so that no images are visible.
Following code is executed in order to update the table.
productImageData.removeAllItems();
for (final UserProductImage curImage : userProductImages)
{
productImageData.addBean(UserProductImageBean.create(curImage,
InwtApplication.getInstance(), this));
}
productImagesTable.setColumnWidth(ImageColumnGenerator.IMAGE_FIELD, 1000);
productImagesTable.setWidth("100%");
productImagesTable.requestRepaint();
You may use a Layout as type for Container column, and create a Layout with image (standard vaadin way to add image: vaadin.com/book/vaadin6/-/page/components.embedded.html) inside of it... you'll only have to build the Layouts with the image inside.
To be sure to have the right size of the table, don't fix the width of the column, but just the size of the layout, the table will sizes itself on the size of the content.
D.
I'm trying to run this java code:
public class Lector{
public static void main(String[] args) {
int numVentaint;
try{
List<Guardar> guardar = new ArrayList<Guardar>();
CsvReader ventas_import = new CsvReader("C:\\Users\\Karen Jaure\\Downloads\\Kubii-Sushi-Ventas.csv"); // ac· se agrega la ruta de csv
ventas_import.readHeaders();
while (ventas_import.readRecord()){
String numVenta= ventas_import.get(0);
String fechaVenta= ventas_import.get(1);
String horaVenta= ventas_import.get(2);
String nombreProducto = ventas_import.get(4);
String montoTotal= ventas_import.get(7);
String codProducto= ventas_import.get(3);
String precioUnitarioProducto= ventas_import.get(5);
String cantidadUnidades = ventas_import.get(6);
guardar.add(new Guardar(numVenta, fechaVenta, horaVenta, codProducto, nombreProducto, precioUnitarioProducto, cantidadUnidades));
}
ventas_import.close();
for(Guardar us:guardar){
System.out.println(us.getNumVenta());
}
}
catch (FileNotFoundException e){
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
I want to show only "numVenta" attribute of "Guardar" class but when I run it, the system out print method doesn't filter the attribute given by the "Guardar" class method ".getNumVenta()".
I just can't find the error! Help will be very appreciated.
UPDATED
Here is the "Guardar" class:
public class Guardar {
private String numVenta;
private String fechaVenta;
private String horaVenta;
private String codProducto;
private String nomProducto;
private String precioUnitario;
private String cantidadUnidades;
public Guardar(String numVenta, String fechaVenta, String horaVenta, String codProducto, String nomProducto, String precioUnitario, String cantidadUnidades) {
this.numVenta = numVenta;
this.fechaVenta = fechaVenta;
this.horaVenta = horaVenta;
this.codProducto = codProducto;
this.nomProducto = nomProducto;
this.precioUnitario = precioUnitario;
this.cantidadUnidades = cantidadUnidades;
}
public String getNumVenta() {
return numVenta;
}
public void setNumVenta(String numVenta) {
this.numVenta = numVenta;
}
public String getFechaVenta() {
return fechaVenta;
}
public void setFechaVenta(String fechaVenta) {
this.fechaVenta = fechaVenta;
}
public String getHoraVenta() {
return horaVenta;
}
public void setHoraVenta(String horaVenta) {
this.horaVenta = horaVenta;
}
public String getCodProducto() {
return codProducto;
}
public void setCodProducto(String codProducto) {
this.codProducto = codProducto;
}
public String getNomProducto() {
return nomProducto;
}
public void setNomProducto(String nomProducto) {
this.nomProducto = nomProducto;
}
public String getPrecioUnitario() {
return precioUnitario;
}
public void setPrecioUnitario(String precioUnitario) {
this.precioUnitario = precioUnitario;
}
public String getCantidadUnidades() {
return cantidadUnidades;
}
public void setCantidadUnidades(String cantidadUnidades) {
this.cantidadUnidades = cantidadUnidades;
}
}
I'm really a newbie to JAVA, spring mvc.
And my understanding for "code" is so poor that I can't even think of how I'm going to get through with upcoming errors.
So this question will sound like " Do this for me!". ( It will do, actually )
Anyway, I'm trying to make a two-depth menu. Its structure looks like this below.
TopMenu
::: menuNo
::: menuName
::: memberType
::: url
::: sort
::: subMenus
::: menuNo
::: menuName
::: memberType
::: url
::: sort
TopMenu2
::: menuNo2
::: menuName2
::: memberType2
::: url2
.
.
.
.
So I made a bean class for this.
public class MenuInfoBean {
private String menuNo;
private String menuName;
private String memberType;
private String url;
private int sort;
List<MenuInfoBean> subMenus;
public MenuInfoBean() {
}
public String getMenuNo() {
return menuNo;
}
public void setMenuNo(String menuNo) {
this.menuNo = menuNo;
}
public String getMenuName() {
return menuName;
}
public void setMenuName(String menuName) {
this.menuName = menuName;
}
public String getMemberType() {
return memberType;
}
public void setMemberType(String memberType) {
this.memberType = memberType;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getSort() {
return sort;
}
public void setSort(int sort) {
this.sort = sort;
}
public List<MenuInfoBean> getSubMenus() {
return subMenus;
}
public void setSubMenus(MenuInfoBean subMenus) {
subMenus.menuName = subMenus.menuName;
subMenus.memberType = subMenus.memberType;
subMenus.url = subMenus.url;
subMenus.sort = subMenus.sort;
}
}
Which database will be used is not decided yet, so I'm temporarily using properties for menu data.
#TopMenu List
topmenu = M1000,M9000
#SubMenu List
M1000.submenu =
M9000.submenu = M9001,M9002,M9003,M9004
#TopMenu Info
#M1000 APPLICATION
M1000.menuName=APPLICATION
M1000.url=
M1000.memberType=00,10
M1000.sort=1
#M9000 ADMIN
M9000.menuName=ADMIN
M9000.url=/SYS01/memberList.mon
M9000.memberType=00,10
M9000.sort=1
#SubMenu Info
#M9000 ADMIN's
M9001.menuName=Member mgmt
M9001.url=/SYS01/memberList.mon
M9001.memberType=00,10
M9001.sort=1
M9002.menuName=menu2
M9002.url=/SYS01/memberList.mon
M9002.memberType=00,10
M9002.sort=1
M9003.menuName=menu3
M9003.url=/SYS01/memberList.mon
M9003.memberType=00,10
M9003.sort=1
M9004.menuName=menu4
M9004.url=/SYS01/memberList.mon
M9004.memberType=00,10
M9004.sort=1
And here I fetch the data and try to put them into a List.
public class MenuManager {
public List<MenuInfoBean> getMenus(String permissionCode) {
LabelProperties msgResource = LabelProperties.getInstance();
MenuInfoBean menuInfo = new MenuInfoBean();
List<MenuInfoBean> menuList = new ArrayList<MenuInfoBean>();
String topMenu = msgResource.getProperty("topmenu");
String[] topMenuItems = topMenu.split(",");
for (int i = 0; topMenuItems.length > i; i++ ) {
String subMenuName = msgResource.getProperty(topMenuItems[i] + ".submenu");
if ( subMenuName.isEmpty() == false ) {
menuInfo.setMenuName(msgResource.getProperty(subMenuName + ".menuName"));
menuInfo.setMemberType(msgResource.getProperty(subMenuName + ".memberType"));
menuInfo.setUrl(msgResource.getProperty(subMenuName + ".url"));
menuInfo.setSort(Integer.parseInt(msgResource.getProperty(subMenuName + ".sort")));
menuInfo.setSubMenus(menuInfo);
} else {
menuInfo.setMenuName("");
menuInfo.setSubMenus(menuInfo);
}
menuInfo.setMenuNo("");
menuInfo.setMenuName(msgResource.getProperty(topMenuItems[i] + ".menuName"));
menuInfo.setMemberType(msgResource.getProperty(topMenuItems[i] + ".memberType"));
menuInfo.setUrl(msgResource.getProperty(topMenuItems[i] + ".url"));
menuInfo.setSort(Integer.parseInt(msgResource.getProperty(topMenuItems[i] + ".sort")));
menuList.add(menuInfo);
}
return menuList;
}
}
getProperty method works great. It gets the properties value correctly.
But as you may noticed, there's some null data is being made.
to ignore this NullPointerException, I made
List<MenuInfoBean> menuList = new ArrayList<MenuInfoBean>();
So the exception has been successfully avoided. But another error comes up which isn't important in this post....
Anyway, while trying to solve the new error, I looked into the menuInfo data and found out something wrong was going on.
The subMenus was holding the topMenu's data!
Here's the question, How can I make this menu with MenuInfoBean like the structure I mentioned on the top of this post?
And why subMenus data was holding topMenu's properties?
I set subMenus data first, and topMenu data later! why this happens?
First of all I am updating the domain object by adding a additional method add(Meun)
import java.util.ArrayList;
import java.util.List;
public class MenuInfoBean
{
private String menuNo;
private String menuName;
private String memberType;
private String url;
private int sort;
List<MenuInfoBean> subMenus;
public MenuInfoBean()
{
}
public String getMenuNo()
{
return menuNo;
}
public void setMenuNo(String menuNo)
{
this.menuNo = menuNo;
}
public String getMenuName()
{
return menuName;
}
public void setMenuName(String menuName)
{
this.menuName = menuName;
}
public String getMemberType()
{
return memberType;
}
public void setMemberType(String memberType)
{
this.memberType = memberType;
}
public String getUrl()
{
return url;
}
public void setUrl(String url)
{
this.url = url;
}
public int getSort()
{
return sort;
}
public void setSort(int sort)
{
this.sort = sort;
}
public List<MenuInfoBean> getSubMenus()
{
return subMenus;
}
// This is new method added to the bean
public void addSubMenuItem(MenuInfoBean menuInfoBean)
{
if (subMenus == null)
subMenus = new ArrayList<MenuInfoBean>();
subMenus.add(menuInfoBean);
}
}
Here is the class that generate the menu and return (look at the get menu method):
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang.StringUtils;
public class MenuExtractionComponent
{
public List<MenuInfoBean> getMenus(String permissionCode)
{
LabelProperties msgResource = LabelProperties.getInstance();
List<MenuInfoBean> menuList = new ArrayList<MenuInfoBean>();
String topMenu = msgResource.getProperty("topmenu");
List<String> topMenuItems = new ArrayList<String>();
// Checking is top menu empty
if (StringUtils.isNotBlank(topMenu))
{
topMenuItems.addAll(Arrays.asList(topMenu.split(",")));
}
for (String topMenuItem : topMenuItems)
{
// Setting top menu details
MenuInfoBean menuInfo = new MenuInfoBean();
menuInfo.setMenuNo("");
menuInfo.setMenuName(msgResource.getProperty(topMenuItem + ".menuName"));
menuInfo.setMemberType(msgResource.getProperty(topMenuItem + ".memberType"));
menuInfo.setUrl(msgResource.getProperty(topMenuItem + ".url"));
menuInfo.setSort(Integer.parseInt(msgResource.getProperty(topMenuItem + ".sort")));
String subMenu = msgResource.getProperty(topMenuItem + ".submenu");
List<String> subMenuItems = new ArrayList<String>();
// Checking is sub menu empty
if (StringUtils.isNotBlank(subMenu))
{
subMenuItems.addAll(Arrays.asList(subMenu.split(",")));
}
for (String subMenuItem : subMenuItems)
{
MenuInfoBean subMenuInfo = new MenuInfoBean();
subMenuInfo.setMenuName(msgResource.getProperty(subMenuItem + ".menuName"));
subMenuInfo.setMemberType(msgResource.getProperty(subMenuItem + ".memberType"));
subMenuInfo.setUrl(msgResource.getProperty(subMenuItem + ".url"));
subMenuInfo.setSort(Integer.parseInt(msgResource.getProperty(subMenuItem + ".sort")));
menuInfo.addSubMenuItem(subMenuInfo);
}
menuList.add(menuInfo);
}
return menuList;
}
}
Has anyone an idea about what is wrong with my attempt to call a method from a C# dll in my Java code?
Here is my example:
Java code:
public class CsDllHandler {
public interface IKeywordRun extends Library {
public String KeywordRun(String action, String xpath, String inputData,
String verifyData);
}
private static IKeywordRun jnaInstance = null;
public void runDllMethod(String action, String xpath, String inputData,
String verifyData) {
NativeLibrary.addSearchPath(${projectDllName},
"${projectPath}/bin/x64/Debug");
jnaInstance = (IKeywordRun) Native.loadLibrary(
${projectDllName}, IKeywordRun.class);
String csResult = jnaInstance.KeywordRun(action, xpath, inputData,
verifyData);
System.out.println(csResult);
}
}
And in C#:
[RGiesecke.DllExport.DllExport]
public static string KeywordRun(string action, string xpath, string inputData, string verifyData) {
return "C# here";
}
The Unmanaged Exports nuget should be enough for me to call this method (in theory) but I have some strange error:
Exception in thread "main" java.lang.Error: Invalid memory access
at com.sun.jna.Native.invokePointer(Native Method)
at com.sun.jna.Function.invokePointer(Function.java:470)
at com.sun.jna.Function.invokeString(Function.java:651)
at com.sun.jna.Function.invoke(Function.java:395)
at com.sun.jna.Function.invoke(Function.java:315)
at com.sun.jna.Library$Handler.invoke(Library.java:212)
at com.sun.proxy.$Proxy0.KeywordRun(Unknown Source)
at auto.test.keywords.utils.CsDllHandler.runDllMethod(CsDllHandler.java:34)
at auto.test.keywords.runner.MainClass.main(MainClass.java:24)
Well, after another day of research and "trial and error" I have found the cause of my problem and a solution.
The cause was that my C# dll had a dependency on log4net.dll. For running a static method from a standalone C# dll the code from the question is all you need.
The solution for using C# dll with dependencies is to create another dll with no dependency and to load the original dll in this adapter with reflection. In Java you should load the adapter dll with jna and call any exported method. I was able not only to execute methods from the adapter but also to configure log4net with reflection and Java
Here is my code:
(C#)
public class CSharpDllHandler {
private static Logger log = Logger.getLogger(CSharpDllHandler.class);
public interface IFrameworkAdapter extends Library {
public String runKeyword(String action, String xpath, String inputData,
String verifyData);
public String configureLog4net(String log4netConfigPath);
public String loadAssemblies(String frameworkDllPath,
String log4netDllPath);
}
private static IFrameworkAdapter jnaAdapterInstance = null;
private String jnaSearchPath = null;
public CSharpDllHandler(String searchPath) {
this.jnaSearchPath = searchPath;
// add to JNA search path
System.setProperty("jna.library.path", jnaSearchPath);
// load attempt
jnaAdapterInstance = (IFrameworkAdapter) Native.loadLibrary(
"FrameworkAdapter", IFrameworkAdapter.class);
}
public String loadAssemblies(String frameworkDllPath, String log4netDllPath) {
String csResult = jnaAdapterInstance.loadAssemblies(frameworkDllPath,
log4netDllPath);
log.debug(csResult);
return csResult;
}
public String runKeyword(String action, String xpath, String inputData,
String verifyData) {
String csResult = jnaAdapterInstance.runKeyword(action, xpath,
inputData, verifyData);
log.debug(csResult);
return csResult;
}
public String configureLogging(String log4netConfigPath) {
String csResult = jnaAdapterInstance
.configureLog4net(log4netConfigPath);
log.debug(csResult);
return csResult;
}
public String getJnaSearchPath() {
return jnaSearchPath;
}
}
In the main method just use something like this:
CSharpDllHandler dllHandler = new CSharpDllHandler(
${yourFrameworkAdapterDllLocation});
dllHandler.loadAssemblies(
${yourOriginalDllPath},${pathToTheUsedLog4netDllFile});
dllHandler.configureLogging(${log4net.config file path});
dllHandler.runKeyword("JAVA Action", "JAVA Xpath", "JAVA INPUT",
"JAVA VERIFY");
dllHandler.runKeyword("JAVA Action2", "JAVA Xpath2", "JAVA INPUT2",
"JAVA VERIFY2");
In C# I have the desired methods on the original dll:
public static string KeywordRun(string action, string xpath, string inputData, string verifyData) {
log.Debug("Action = " + action);
log.Debug("Xpath = " + xpath);
log.Debug("InputData = " + inputData);
log.Debug("VerifyData = " + verifyData);
return "C# UserActions result: "+ action+" "+xpath+" "+inputData+" "+verifyData;
}
and all the magic is in the DLL Adapter:
namespace FrameworkAdapter {
[ComVisible(true)]
public class FwAdapter {
private const String OK="OK";
private const String frameworkEntryClassName = "${nameOfTheDllClass with method to run }";
private const String log4netConfiguratorClassName = "log4net.Config.XmlConfigurator";
private static Assembly frameworkDll = null;
private static Type frameworkEntryClass = null;
private static MethodInfo keywordRunMethod = null;
private static Assembly logDll = null;
private static Type logEntryClass = null;
private static MethodInfo logConfigureMethod = null;
private static String errorMessage = "OK";
[RGiesecke.DllExport.DllExport]
public static string loadAssemblies(string frameworkDllPath, string log4netDllPath) {
try {
errorMessage = LoadFrameworkDll(frameworkDllPath, frameworkEntryClassName);
LoadFrameworkMethods("KeywordRun", "Setup", "TearDown");
errorMessage = LoadLogAssembly(log4netDllPath, log4netConfiguratorClassName);
if (errorMessage.CompareTo(OK) == 0)
errorMessage = LoadLogMethods("Configure");
}
catch (Exception e) {
return e.Message;
}
return errorMessage;
}
[RGiesecke.DllExport.DllExport]
public static string configureLog4net(string log4netConfigPath) {
if (errorMessage.CompareTo("OK") == 0) {
StringBuilder sb = new StringBuilder();
sb.AppendLine("Try to configure Log4Net");
try {
FileInfo logConfig = new FileInfo(log4netConfigPath);
logConfigureMethod.Invoke(null, new object[] { logConfig });
sb.AppendLine("Log4Net configured");
}
catch (Exception e) {
sb.AppendLine(e.InnerException.Message);
}
return sb.ToString();
}
return errorMessage;
}
[RGiesecke.DllExport.DllExport]
public static string runKeyword(string action, string xpath, string inputData, string verifyData) {
StringBuilder sb = new StringBuilder();
object result = null;
try {
result = keywordRunMethod.Invoke(null, new object[] { action, xpath, inputData, verifyData });
sb.AppendLine(result.ToString());
}
catch (Exception e) {
sb.AppendLine(e.InnerException.Message);
}
return sb.ToString();
}
private static String LoadFrameworkDll(String dllFolderPath, String entryClassName) {
try {
frameworkDll = Assembly.LoadFrom(dllFolderPath);
Type[] dllTypes = frameworkDll.GetExportedTypes();
foreach (Type t in dllTypes)
if (t.FullName.Equals(entryClassName)) {
frameworkEntryClass = t;
break;
}
}
catch (Exception e) {
return e.InnerException.Message;
}
return OK;
}
private static String LoadLogAssembly(String dllFolderPath, String entryClassName) {
try {
logDll = Assembly.LoadFrom(dllFolderPath);
Type[] dllTypes = logDll.GetExportedTypes();
foreach (Type t in dllTypes)
if (t.FullName.Equals(entryClassName)) {
logEntryClass = t;
break;
}
}
catch (Exception e) {
return e.InnerException.Message;
}
return OK;
}
private static String LoadLogMethods(String logMethodName) {
try {
logConfigureMethod = logEntryClass.GetMethod(logMethodName, new Type[] { typeof(FileInfo) });
}
catch (Exception e) {
return e.Message;
}
return OK;
}
private static void LoadFrameworkMethods(String keywordRunName, String scenarioSetupName, String scenarioTearDownName) {
///TODO load the rest of the desired methods here
keywordRunMethod = frameworkEntryClass.GetMethod(keywordRunName);
}
}
}
Running this code will provide all the logged messages from the original C# DLL to the Java console output (and to a file if configured). In a similar way, we can load any other needed dll files for runtime.
Please forgive my [very probable wrong] way of doing things in C# with reflection, I'm new to this language.