How to programatically invoke a maven dependency plugin - java

I am trying to invoke maven-dependency-plugin programatically. i am using maven 3 version. the problem is that when i invoke it through pluginManager.executeMojo(session, execution), i receive the following error message:
[ERROR] **The parameters 'project', 'local', 'remoteRepos',
'reactorProjects' for goal
org.apache.maven.plugins:maven-dependency-plugin:2.1:unpack are
missing or invalid**
**org.apache.maven.plugin.PluginParameterException: The parameters 'project',
'local', 'remoteRepos', 'reactorProjects' for goal
org.apache.maven.plugins:maven-dependency-plugin:2.1:unpack are missing or
invalid**
at org.apache.maven.plugin.internal.DefaultMavenPluginManager
.populatePluginFields(DefaultMavenPluginManager.java:518)
at org.apache.maven.plugin.internal.DefaultMavenPluginManager
.getConfiguredMojo(DefaultMavenPluginManager.java:471)
at org.apache.maven.plugin.DefaultBuildPluginManager
.executeMojo(DefaultBuildPluginManager.java:99)
at com.sap.ldi.qi.osgi.OSGiManifesrMfHandlerMojo
.invokeMavenDependencyPlugin(OSGiManifesrMfHandlerMojo.java:139)
at com.sap.ldi.qi.osgi.OSGiManifesrMfHandlerMojo
.execute(OSGiManifesrMfHandlerMojo.java:100)
at org.apache.maven.plugin.DefaultBuildPluginManager
.executeMojo(DefaultBuildPluginManager.java:110)
at org.apache.maven.lifecycle.internal.MojoExecutor
.execute(MojoExecutor.java:144)
at org.apache.maven.lifecycle.internal.MojoExecutor
.execute(MojoExecutor.java:87)
at org.apache.maven.lifecycle.internal.MojoExecutor
.execute(MojoExecutor.java:79)
-- many lines stripped from stack trace --
[INFO] ----------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ----------------------------------------------------------------------
[INFO] Total time: 17.938s
[INFO] Finished at: Mon Nov 22 10:27:42 EET 2010
[INFO] Final Memory: 12M/23M
[INFO] ----------------------------------------------------------------------
[ERROR] Failed to execute goal
com.sap.ldi.qi:osgi-manifest-handler-plugin:0.0.1-SNAPSHOT:handle
(osgi-manifest-handler plugin) on project com.sap.ldi.demo.calc
.cmd.tests: The parameters 'project', 'local', 'remoteRepos',
'reactorProjects' for goal
org.apache.maven.plugins:maven-dependency-plugin:2.1:unpack are missing
or invalid -> [Help 1]
-- stripped rest --
As I know, the only required parameter for the unpack goal of maven dependency plugin is artifactItems. I set the plugin configuration by using PluginExecution.setConfiguration() method. It seems that this plugin configuration is not correctly set.
Do you have any idea why this exception is thrown?
Here is the configuration that I am using:
<configuration>
<artifactItems>
<artifactItem>
<groupId>com.sap.ldi.demo.calc</groupId>
<artifactId>com.sap.ldi.demo.calc.cmd</artifactId>
<version>0.1.2-SNAPSHOT</version>
<type>jar</type>
<overWrite>true</overWrite>
<outputDirectory>target/demo-calc-stuff</outputDirectory>
<includes>**/*.*</includes>
</artifactItem>
</artifactItems>
</configuration>
Thanks
One correction from my side. The used Maven version is not Maven 3.0 but Maven 3.0-beta-1. I see that BuildPluginManager.loadPlugin() in version 3.0-beta-1 has two args, and the same method in version 3.0 has three.
I am wondering, does anyone tried to invoke a maven plugin programatically with maven 3.0 or maven 3.0-beta-1. I am still trying to invoke it with maven 3.0-beta-1, but it still returns the same exception as pasted above.

Here is an updated version of Mojo Executor designed for Maven 3:
package com.googlecode.boostmavenproject;
import java.util.Collections;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Plugin;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.apache.maven.plugin.BuildPluginManager;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.codehaus.plexus.configuration.PlexusConfiguration;
import org.codehaus.plexus.util.xml.Xpp3DomUtils;
import org.sonatype.aether.repository.RemoteRepository;
/**
* Executes an arbitrary mojo using a fluent interface. This is meant to be executed within the context of a Maven 2
* mojo.
*
* Here is an execution that invokes the dependency plugin:
* <pre>
* executeMojo(
* plugin(
* groupId("org.apache.maven.plugins"),
* artifactId("maven-dependency-plugin"),
* version("2.0")
* ),
* goal("copy-dependencies"),
* configuration(
* element(name("outputDirectory"), "${project.build.directory}/foo")
* ),
* executionEnvironment(
* project,
* session,
* pluginManager
* )
* );
* </pre>
* #see http://code.google.com/p/mojo-executor/
*/
public class MojoExecutor
{
/**
* Entry point for executing a mojo
*
* #param plugin The plugin to execute
* #param goal The goal to execute
* #param configuration The execution configuration
* #param env The execution environment
* #throws MojoExecutionException If there are any exceptions locating or executing the mojo
*/
public static void executeMojo(Plugin plugin, String goal, Xpp3Dom configuration,
ExecutionEnvironment env) throws MojoExecutionException
{
if (configuration == null)
throw new NullPointerException("configuration may not be null");
try
{
MavenSession session = env.getMavenSession();
PluginDescriptor pluginDescriptor = env.getPluginManager().loadPlugin(plugin,
Collections.<RemoteRepository>emptyList(), session.getRepositorySession());
MojoDescriptor mojo = pluginDescriptor.getMojo(goal);
if (mojo == null)
{
throw new MojoExecutionException("Could not find goal '" + goal + "' in plugin "
+ plugin.getGroupId() + ":"
+ plugin.getArtifactId() + ":"
+ plugin.getVersion());
}
configuration = Xpp3DomUtils.mergeXpp3Dom(configuration,
toXpp3Dom(mojo.getMojoConfiguration()));
MojoExecution exec = new MojoExecution(mojo, configuration);
env.getPluginManager().executeMojo(session, exec);
}
catch (Exception e)
{
throw new MojoExecutionException("Unable to execute mojo", e);
}
}
/**
* Converts PlexusConfiguration to a Xpp3Dom.
*
* #param config the PlexusConfiguration
* #return the Xpp3Dom representation of the PlexusConfiguration
*/
private static Xpp3Dom toXpp3Dom(PlexusConfiguration config)
{
Xpp3Dom result = new Xpp3Dom(config.getName());
result.setValue(config.getValue(null));
for (String name: config.getAttributeNames())
result.setAttribute(name, config.getAttribute(name));
for (PlexusConfiguration child: config.getChildren())
result.addChild(toXpp3Dom(child));
return result;
}
/**
* Constructs the {#link ExecutionEnvironment} instance fluently
* #param mavenProject The current Maven project
* #param mavenSession The current Maven session
* #param pluginManager The Build plugin manager
* #return The execution environment
* #throws NullPointerException if mavenProject, mavenSession or pluginManager
* are null
*/
public static ExecutionEnvironment executionEnvironment(MavenProject mavenProject,
MavenSession mavenSession,
BuildPluginManager pluginManager)
{
return new ExecutionEnvironment(mavenProject, mavenSession, pluginManager);
}
/**
* Builds the configuration for the goal using Elements
* #param elements A list of elements for the configuration section
* #return The elements transformed into the Maven-native XML format
*/
public static Xpp3Dom configuration(Element... elements)
{
Xpp3Dom dom = new Xpp3Dom("configuration");
for (Element e: elements)
dom.addChild(e.toDom());
return dom;
}
/**
* Defines the plugin without its version
* #param groupId The group id
* #param artifactId The artifact id
* #return The plugin instance
*/
public static Plugin plugin(String groupId, String artifactId)
{
return plugin(groupId, artifactId, null);
}
/**
* Defines a plugin
* #param groupId The group id
* #param artifactId The artifact id
* #param version The plugin version
* #return The plugin instance
*/
public static Plugin plugin(String groupId, String artifactId, String version)
{
Plugin plugin = new Plugin();
plugin.setArtifactId(artifactId);
plugin.setGroupId(groupId);
plugin.setVersion(version);
return plugin;
}
/**
* Wraps the group id string in a more readable format
* #param groupId The value
* #return The value
*/
public static String groupId(String groupId)
{
return groupId;
}
/**
* Wraps the artifact id string in a more readable format
* #param artifactId The value
* #return The value
*/
public static String artifactId(String artifactId)
{
return artifactId;
}
/**
* Wraps the version string in a more readable format
* #param version The value
* #return The value
*/
public static String version(String version)
{
return version;
}
/**
* Wraps the goal string in a more readable format
* #param goal The value
* #return The value
*/
public static String goal(String goal)
{
return goal;
}
/**
* Wraps the element name string in a more readable format
* #param name The value
* #return The value
*/
public static String name(String name)
{
return name;
}
/**
* Constructs the element with a textual body
* #param name The element name
* #param value The element text value
* #return The element object
*/
public static Element element(String name, String value)
{
return new Element(name, value);
}
/**
* Constructs the element containg child elements
* #param name The element name
* #param elements The child elements
* #return The Element object
*/
public static Element element(String name, Element... elements)
{
return new Element(name, elements);
}
/**
* Element wrapper class for configuration elements
*/
public static class Element
{
private final Element[] children;
private final String name;
private final String text;
public Element(String name, Element... children)
{
this(name, null, children);
}
public Element(String name, String text, Element... children)
{
this.name = name;
this.text = text;
this.children = children;
}
public Xpp3Dom toDom()
{
Xpp3Dom dom = new Xpp3Dom(name);
if (text != null)
{
dom.setValue(text);
}
for (Element e: children)
{
dom.addChild(e.toDom());
}
return dom;
}
}
/**
* Collects Maven execution information
*/
public static class ExecutionEnvironment
{
private final MavenProject mavenProject;
private final MavenSession mavenSession;
private final BuildPluginManager pluginManager;
public ExecutionEnvironment(MavenProject mavenProject, MavenSession mavenSession,
BuildPluginManager pluginManager)
{
if (mavenProject == null)
throw new NullPointerException("mavenProject may not be null");
if (mavenSession == null)
throw new NullPointerException("mavenSession may not be null");
if (pluginManager == null)
throw new NullPointerException("pluginManager may not be null");
this.mavenProject = mavenProject;
this.mavenSession = mavenSession;
this.pluginManager = pluginManager;
}
public MavenProject getMavenProject()
{
return mavenProject;
}
public MavenSession getMavenSession()
{
return mavenSession;
}
public BuildPluginManager getPluginManager()
{
return pluginManager;
}
}
}
I will attempt to contribute my changes back into the official Mojo Executor plugin.

Folks, I think I get it.
The problem is not in the version of Maven that I am using. It is in the configuration that I am using for invoking maven-dependency-plugin. The unpack goal of maven-dependency-plugin requires the following parameters: artifactItems, local, project, reactorProjects and remoteRepos. Here is the correct version of the configuration used for invoking the plugin:
<configuration>
<artifactItems>
<artifactItem>
<groupId>com.sap.ldi.demo.calc</groupId>
<artifactId>com.sap.ldi.demo.calc.cmd</artifactId>
<version>0.1.3-SNAPSHOT</version>
<type>jar</type>
<overWrite>true</overWrite>
<outputDirectory>target/demo-calc-stuff</outputDirectory>
<includes>**/*.*</includes>
</artifactItem>
</artifactItems>
<local>${localRepository}</local>
<project>${project}</project>
<reactorProjects>${reactorProjects}</reactorProjects>
<remoteRepos>${project.remoteArtifactRepositories}</remoteRepos>
</configuration>`

Maven Plugins are not meant to be invoked programmatically.
They rely on values that are injected by the underlying plexus container.
So either you will have to find out how to inject those values or you will have to rely on the default mechanism.
One thing you can use is the Maven Invoker. With that, you can programmatically launch maven lifecycles, but they will execute in a separate VM. So if you need to change the model dynamically beforehand, you will need to serialize the model out to a temporary pom.xml and use that with maven invoker. This is heavy stuff, but I have done it successfully some two years ago.

Related

Submit Spark job in Azure Synapse from Java

Azure Synapse provides managed spark pool, where the spark jobs can be submitted.
How do submit spark-job (as jars) along with dependencies to the pool2 using Java
If multiple jobs are submitted (each along with its own set of dependencies), then are the dependencies shared across the jobs. Or are they agnostic of each other?
For (1):
Add the following dependency:
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-analytics-synapse-spark</artifactId>
<version>1.0.0-beta.4</version>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
</dependency>
With below sample code:
import com.azure.analytics.synapse.spark.SparkBatchClient;
import com.azure.analytics.synapse.spark.SparkClientBuilder;
import com.azure.analytics.synapse.spark.models.SparkBatchJob;
import com.azure.analytics.synapse.spark.models.SparkBatchJobOptions;
import com.azure.identity.DefaultAzureCredentialBuilder;
import java.util.*;
public class SynapseService {
private final SparkBatchClient batchClient;
public SynapseService() {
batchClient = new SparkClientBuilder()
.endpoint("https://xxxx.dev.azuresynapse.net/")
.sparkPoolName("TestPool")
.credential(new DefaultAzureCredentialBuilder().build())
.buildSparkBatchClient();
}
public SparkBatchJob submitSparkJob(String name, String mainFile, String mainClass, List<String> arguments, List<String> jars) {
SparkBatchJobOptions options = new SparkBatchJobOptions()
.setName(name)
.setFile(mainFile)
.setClassName(mainClass)
.setArguments(arguments)
.setJars(jars)
.setExecutorCount(3)
.setExecutorCores(4)
.setDriverCores(4)
.setDriverMemory("6G")
.setExecutorMemory("6G");
return batchClient.createSparkBatchJob(options);
}
/**
* All possible Livy States: https://learn.microsoft.com/en-us/rest/api/synapse/data-plane/spark-batch/get-spark-batch-jobs#livystates
*
* Some of the values: busy, dead, error, idle, killed, not_Started, recovering, running, shutting_down, starting, success
* #param id
* #return
*/
public SparkBatchJob getSparkJob(int id, boolean detailed) {
return batchClient.getSparkBatchJob(id, detailed);
}
/**
* Cancels the ongoing synapse spark job
* #param jobId id of the synapse job
*/
public void cancelSparkJob(int jobId) {
batchClient.cancelSparkBatchJob(jobId);
}
}
And finally submit the spark-job:
SynapseService synapse = new SynapseService();
synapse.submitSparkJob("TestJob",
"abfss://builds#xxxx.dfs.core.windows.net/core/jars/main-module_2.12-1.0.jar",
"com.xx.Main",
Collections.emptyList(),
Arrays.asList("abfss://builds#xxxx.dfs.core.windows.net/core/jars/*"));
Finally, you will need to provide the necessary role in:
Open Synapse Analytics Studio
Manage -> Access Control
Provide the role Synapse Compute Operator and Synapse Compute Operator to the caller
To answer question-2:
When jobs are submitted in synapse via jars, they are equivalent to spark-submit. So all the jobs are agnostic of each other and do not share each other's dependencies.

Spring Integration Java DSL: Remote filter is not applied on handle method

I want to read specific files from a SFTP server and get only compressed files only once.
I encounter a problem when handling message because the defined filter on the remote server seems to not be applied in handle method.
Dependencies:
SpringBoot: 2.2.1
spring-integration: 5.2.1
spring-integration-jdbc: 5.2.1
spring-integration-sftp: 5.2.1
public IntegrationFlow buildSftpInboundIntegrationFlow() {
return IntegrationFlows
.from(
Sftp
.inboundStreamingAdapter(buildSftpRemoteFileTemplate())
.remoteDirectory(getRemoteDirectoryPath())
.filter(buildRemoteFileFilter())
.remoteFileSeparator(
Optional
.ofNullable(getRemoteFileSeparator())
.orElse(DEFAULT_REMOTE_PATH_SEPARATOR))
.maxFetchSize(
Optional.ofNullable(getMaxFetchSize()).orElse(DEFAULT_MAX_FETCH_SIZE)),
sourcePollingChannelAdapterSpec -> sourcePollingChannelAdapterSpec
.id(getSftpInboundStreamingAdapterIdentifier())
.autoStartup(true)
.poller(buildPollerSpec()))
.handle(handleMessage())
.get();
}
/**
* Allows to build a regex to filter files.
*
* #return a regex as a {#link String}.
*/
private String buildRegexFileFilter() {
return String.format(".*\\.%s", getFileExtensionToFilter());
}
/**
* Allows to build an instance of {#link SftpRemoteFileTemplate}.
*
* #return an instance of {#link SftpRemoteFileTemplate}.
*/
private SftpRemoteFileTemplate buildSftpRemoteFileTemplate() {
final SftpRemoteFileTemplate sftpRemoteFileTemplate = new SftpRemoteFileTemplate(getSftpSessionFactory());
sftpRemoteFileTemplate.setAutoCreateDirectory(true);
return sftpRemoteFileTemplate;
}
/**
* Allows to build the filters to apply to the remote files.
*
* #return an instance of {#link CompositeFileListFilter}.
*/
#SuppressWarnings("resource")
private CompositeFileListFilter<LsEntry> buildRemoteFileFilter() {
return new ChainFileListFilter<LsEntry>() // NOSONAR
.addFilters(
new SftpRegexPatternFileListFilter(buildRegexFileFilter()),
getSftpPersistentAcceptOnceFileListFilter());
}
/**
* Allows to build the poller specifications.
*
* #return an instance of {#link PollerSpec}.
*/
private PollerSpec buildPollerSpec() {
return Pollers
.fixedDelay(
Optional.ofNullable(getPollerDelayInSeconds()).orElse(DEFAULT_POLLER_DELAY_IN_SECONDS),
TimeUnit.SECONDS)
.transactional()
.transactionSynchronizationFactory(getTransactionSynchronizationFactory());
}
...
Do you have any ideas to suggest to me ?
why in the handle method I receive files which should be excluded by the remote filter ?
It is a bug ? How get filtered messages ?
It's a bug in the modules spring-integration and spring-integration-sftp in version 5.2.1.
It works by upgrading these dependencies in version 5.2.2. (December 6, 2019)

need help figuring out why Im getting an exception on axlPort.getPhone(axlParams) call

I am attempting to run the axl demo shown at 'https://developer.cisco.com/docs/axl/#!javajax-ws-quickstart'
I am a newbie to axl, eclipse, and java, and just trying to get my toes wet.
I have followed the instructions listed and the project only shows 1 error at line:
GetPhoneRes getPhoneResponse = axlPort.getPhone(axlParams);
The error type says AXL Error.
There are no other errors showing in the compiler.
Can anyone give me any ideas of what the problem could be, or how to chase it?
package com.cisco.axl.demo;
/**
* demo to pull basic phone info
*/
import javax.xml.ws.BindingProvider;
import com.cisco.axlapiservice.AXLAPIService;
import com.cisco.axlapiservice.AXLPort;
import com.cisco.axl.api._10.*;
/**
*
** #author t01136
** Performs Getphone using AXL API
** Service Consumers were generated by the java ?? wsimport command:
** wsimport -keep -b schema/current/AXLSOAP.xsd -Xnocompile -s src -d bin -verbose schema/current/AXLAPI.wsd
* and since AXL uses HTTPS, you will have to install the UC applications
* certificate into you keystore in order to run this sample app.
* You can run the program by CD'ing to the bin folder within this project
* C:\Users\t01136.POS\eclipse-workspace\axl-demo\bin
* and running the following command
* java -cp . com.cisco.axl.demo.Demo
*/
public class Demo {
/**
* UC app host.
*/
protected static String ucHost = null;
/**
* OS admin.
*/
protected static String ucAdmin = null;
/**
* OS admin password.
*/
protected static String ucPswd = null;
/**
* phoneName used in request.
*/
protected static String phoneName = null;
/**
* Run the demo
*
* #param args not used
*/
public static void main(String[] args) {
// Verify JVM has a console
if (System.console() == null) {
System.err.println("The Cisco AXL Sample App requires a console.");
System.exit(1);
} else {
Demo.informUser("%nWelcome to the Cisco AXL Sample APP .%n");
}
Demo demo = new Demo();
demo.getPhoneInfo();
}
/**
* get information about phone
*/
public void getPhoneInfo() {
// Ask for the UC application to upgrade
// Demo.informuser("%nWhat UC server would you like to access?%n");
ucHost = promptUser(" Host: ");
ucAdmin = promptUser(" OS Admin Account: ");
ucPswd = promptUser(" OS Admin Password: ");
// Ask for the phone name
Demo.informUser("%nEnter the name of the phone you want to retrieve information about.%n");
phoneName = promptUser(" Phone Name: ");
// Make the getPhoneRequest
getPhone();
}
//private String promptUser(String string) {
// // TODO Auto-generated method stub
// return null;
// }
/**
* Makes the getPhone request and displays some of the fields that are returned.
*/
private void getPhone() {
// Instantiate the wsimport generated AXL API Service client --
// see the wsimport comments in the class javadocs above
AXLAPIService axlService = new AXLAPIService();
AXLPort axlPort = axlService.getAXLPort();
// Set the URL, user, and password on the JAX-WS client
String validatorUrl = "https://"
+ Demo.ucHost
+ ":8443/axl/";
((BindingProvider) axlPort).getRequestContext().put(
BindingProvider.ENDPOINT_ADDRESS_PROPERTY, validatorUrl);
((BindingProvider) axlPort).getRequestContext().put(
BindingProvider.USERNAME_PROPERTY, Demo.ucAdmin);
((BindingProvider) axlPort).getRequestContext().put(
BindingProvider.PASSWORD_PROPERTY, Demo.ucPswd);
// Create a GetPhoneReq object to represent the getPhone request and set the name of the device
//to name entered by user
GetPhoneReq axlParams = new GetPhoneReq();
axlParams.setName(phoneName);
//Make a call to the AXL Service and pass the getPhone request
GetPhoneRes getPhoneResponse = axlPort.getPhone(axlParams);
//display information returned in the response to the user
Demo.informUser("Product=" + getPhoneResponse.getReturn().getPhone().getProduct() + "%n"
+ getPhoneResponse.getReturn().getPhone().getLoadInformation().getValue() + "%n");
}
// -------------------- Some I/O Helper Methods ------------------------
/**
* Provide the user some instructions.
*/
protected static void informUser(String info) {
System.console().format(info);
}
/**
* Ask the user a question
*/
protected static String promptUser(String question) {
String answer = null;
while (answer==null || answer.isEmpty() ) {
answer = System.console().readLine(question);
}
return answer.trim();
}
}
Actually I have also noticed
That contained the following code:
package com.cisco.axlapiservice;
import javax.xml.ws.WebFault;
/**
* This class was generated by the JAX-WS RI.
* JAX-WS RI 2.1.6 in JDK 6
* Generated source version: 2.1
*
*/
#WebFault(name = "axlError", targetNamespace = "http://www.cisco.com/AXL/API/10.5")
public class AXLError
extends Exception
{
/**
* Java type that goes as soapenv:Fault detail element.
*
*/
private com.cisco.axl.api._10.AXLError faultInfo;
/**
*
* #param message
* #param faultInfo
*/
public AXLError(String message, com.cisco.axl.api._10.AXLError faultInfo) {
super(message);
this.faultInfo = faultInfo;
}
/**
*
* #param message
* #param faultInfo
* #param cause
*/
public AXLError(String message, com.cisco.axl.api._10.AXLError faultInfo, Throwable cause) {
super(message, cause);
this.faultInfo = faultInfo;
}
/**
*
* #return
* returns fault bean: com.cisco.axl.api._10.AXLError
*/
public com.cisco.axl.api._10.AXLError getFaultInfo() {
return faultInfo;
}
}
and when I look at the contents of 'getFaultInfo():AXLError' I see 'The serializable class AXLError does not declare a static final serialVersionUID field of type long', with 4 quick-fixes available.
But since all of that was part of the download from callmanager, I wouldnt think there would be an error in it.
Perhaps this will give someone a clue.
thanks

FileBasedConfigurationBuilder from Apache Commons Configuration2 not writing the configuration file

I need to write a simple configuration file using apache-commons-configuration but no matter what I try, it's not writing anything to the file.
This is how the file should look like
<config>
<foo>bar</foo>
</config>
This is what I'm doing to write the foo configuration:
private static final String USER_CONFIGURATION_FILE_NAME = "config.xml";
private final Path configFilePath = Paths.get(System.getProperty("user.home"), ".myapp",
USER_CONFIGURATION_FILE_NAME);
private final FileBasedConfigurationBuilder<XMLConfiguration> configBuilder=
new FileBasedConfigurationBuilder<>(XMLConfiguration.class)
.configure(new Parameters().xml().setFile(configFilePath.toFile()));
/**
* Sets the foo configuration to the given {#link String}
*
* #param foo The configuration to be set up
* #throws ConfigurationException If any error occur while setting the property on the
* configuration file
*/
public void setfoo(final String bar) throws ConfigurationException {
checkNotNull(bar);
final Configuration config = configBuilder.getConfiguration();
config.setProperty("foo", bar);
configBuilder.save();
}
/**
* Retrieves the foo set up on the configuration file
*
* #return The foo set up on the configuration file
* #throws ConfigurationException If any error occur while setting the property on the
* configuration file
* #throws NoSuchElementException If there is no foo set up
*/
public String getFoo() throws ConfigurationException {
return configBuilder.getConfiguration().getString("foo");
}
Am I missing something? In Apache Commons Configuration - File-based Configurations I can't see any other information needed to set up the file, so I really don't know what I'm missing here.
For some reason the FileBasedConfiguration is not setting up the xml file by itself, so I had to create it manually and set up the root element, like this:
configFilePath.toFile().createNewFile();
final Writer writer = Files.newBufferedWriter(configFilePath);
writer.write("<config></config>"); //sets the root element of the configuration file
writer.flush();
Shouldn't FileBasedConfiguration take care of this for me, or this is a step that's not documented on apache-commons?

How to capture video using JMF, but without installing JMF

A videoconferencing project I was working on used JMF to capture video and audio, and transmit it to another endpoint. An issue was that my team didn't want the user of the product to have to install JMF.
I thought it might be worthwhile to share our solution to this problem. It works. It works well. My question to you is: does anyone have a better way to do it?
Environment: Windows, XP and above
Download JMF for Windows
Install it on your machine
Locate the following dlls in the system32 folder after jmf installs:
jmacm.dll
jmam.dll
jmcvid.dll
jmdaud.dll
jmdaudc.dll
jmddraw.dll
jmfjawt.dll
jmg723.dll
jmgdi.dll
jmgsm.dll
jmh261.dll
jmh263enc.dll
jmjpeg.dll
jmmci.dll
jmmpa.dll
jmmpegv.dll
jmutil.dll
jmvcm.dll
jmvfw.dll
jmvh263.dll
jsound.dll
Copy the dlls into a temporary folder
Locate the jmf.properties file (Do a search on your computer for it)
Download the JMF source code
In the source code, find the following files:
JMFinit.java
JMRPropertiesGen.java
Registry.java
RegistryGen.java
Create a package; I'll call it JMFNoInstall
Add the files listed in step 6
Add a class called Main to this package as such:
package JMFNoInstall;
// add your imports and whatnot here
public class Main()
{
public Main()
{
JMFinit.main(null);
JMFPropertiesGen.main(null);
Registry.main(null);
RegistryGen.main(new String[] {
new File(".").getAbsolutePath(),
"registrylib"
});
}
}
The jmf.properties file needs to go in the same folder as the class that has your main method or the same folder as the JAR archive that contains the main method.
The dlls need to go into the win32 folder. You can have your program check to see if they are in the win32 folder. If they are not, you can have it copy them over from some location. The jmf.properties file gets updated whenever the the Main class listed above runs. You only need to run this once, the first time the program is ever run, or if the user would like to add new capture devices. Lastly, just make sure the jmf.jar file and jmfcom.jar that comes along with the Windows JMF download is included in the classpath. You're good to go at this point. All the functionality of JMF without actually having to install it.
There really isn't a lot of work involved with this, and you can incorporate it into your custom installer quite easily.
Has anyone found a better way to do this though? There are a few pitfalls of doing it this way.
EDIT: I thought it might be worthwhile to share some of the code that I created. Of course youll need to modify it to handle what you. It prob wont compile, but the stuff that is missing should be easy enough to recreate. But thought it might be a good starting point to help people. The detectCaptureDevices function is probably what will help most people. Ill update this class as I go.
import GUI.Window;
import GlobalUtilities.OS;
import GlobalUtilities.ProgressBar;
import GlobalUtilities.FileUtilities;
import java.io.File;
import java.util.ArrayList;
import java.util.Vector;
import javax.swing.text.Utilities;
/**
* This class providex easy access to the most needed info about JMF. You can test
* a JMF install (Windows only currently) and also get info about the captrue
* devices hooked up to JMF.
* #author dvargo
*/
public class JMFRunner
{
/**
* Show the status of operations
*/
final ProgressBar theBar = new ProgressBar();
/**
* Location where the dll's JMF relies on need to be placed
*/
final String windowsDllFolder = "C:\\WINDOWS\\system32\\";
final String linuxDllFolder = "/usr/lib/";
/**
* Dll's that JMF uses
*/
final String[] windowsDllList = new String[]{
"jmacm.dll",
"jmam.dll",
"jmcvid.dll",
"jmdaud.dll",
"jmdaudc.dll",
"jmddraw.dll",
"jmfjawt.dll",
"jmg723.dll",
"jmgdi.dll",
"jmgsm.dll",
"jmh261.dll",
"jmh263enc.dll",
"jmjpeg.dll",
"jmmci.dll",
"jmmpa.dll",
"jmmpegv.dll",
"jmutil.dll",
"jmvcm.dll",
"jmvfw.dll",
"jmvh263.dll",
"jsound.dll"};
String[] linuxDllList = new String[]{
"libjmcvid.so",
"libjmdaud.so",
"libjmfjawt.so",
"libjmg723.so",
"libjmgsm.so",
"libjmh261.so",
"libjmh263enc.so",
"libjmjpeg.so",
"libjmmpa.so",
"libjmmpegv.so",
"libjmmpx.so",
"libjmutil.so",
"libjmv4l.so",
"libjmxlib.so"
};
String [] dlls= null;
String dir = null;
/**
* List of the video capture devices found by JMF
*/
Vector videoDevices = null;
/**
* List of the audio capture devices found by JMF
*/
Vector audioDevices = null;
public JMFRunner()
{
if(OS.isWindows())
{
dlls = windowsDllList;
dir = windowsDllFolder;
}
else if(OS.isLinux())
{
dlls = linuxDllList;
dir = linuxDllFolder;
}
else
{
Window.getLogger().severe("Operating system does not support JMF");
}
}
/**
* Adds new capture devices
*/
public void detectCaptureDecives()
{
Thread theTread = new Thread(theBar);
theTread.start();
theBar.repaint();
JMFInit.main(new String[] {""});
JMFPropertiesGen.main(new String[] {""});
Registry.main(new String[] {""});
RegistryGen.main(new String[] {"-d",
new File(".").getAbsolutePath(),
"registrylib"
});
theBar.setMessage("");
theBar.stop();
}
/**
* Verifies that all the dll's that JMF needs are in their correct spot
* #return True if all dlls are in their correct spot, false otherwise
*/
public boolean detectDlls()
{
boolean retVal = true;
String currFile;
for(String currDll : dlls)
{
currFile = dir + currDll;
if(! new File(currFile).exists())
{
Window.getLogger().severe("Can not find dll " + currFile + " for JMF");
retVal = false;
}
}
return retVal;
}
//Doesnt work quite yet
public boolean installLibraryFiles()
{
boolean retVal = true;
String currFile;
for(String currDll : dlls)
{
currFile = dir + currDll;
File newDll = new File(currFile);
//see if this dll is already there
if(!newDll.exists())
{
//its not there so lets copy it
try
{
FileUtilities.copy(newDll,FileUtilities.getResourceFile("/JMFManager/Resources/"+currDll,currDll));
}
catch(Exception e)
{
retVal = false;
}
}
}
return retVal;
}
/**
* Returns the location of the jmf.properties file that STix is using
* #return THe locaiton of the JMF properties
*/
public String getJMFPropertiesFileLocation()
{
return Registry.getJMFPropertiesFileLocation();
}
/**
* Returns a list of the audio devices found by JMF
* #return Returns an Arraylist containing info about the audio capture devices
*/
public ArrayList getAudioDevices()
{
DeviceFinder df = new DeviceFinder();
audioDevices = df.getSoundCaptureDevices();
return new ArrayList(audioDevices);
}
/**
* Returns a list of the video decives deteced by JMF
* #return returns an arraylist with info of the video capture devices
*/
public ArrayList getVideoDevices()
{
DeviceFinder df = new DeviceFinder();
videoDevices = df.getVideoCaptureDevices();
return new ArrayList(videoDevices);
}
public static void main(String [] args)
{
JMFRunner x = new JMFRunner();
//x.detectCaptureDecives();
x.installLibraryFiles();
System.out.println(x.detectDlls());
System.out.println(x.getJMFPropertiesFileLocation());
System.out.println(x.getAudioDevices());
System.out.println(x.getVideoDevices());
}
}
DeviceFinder.java
import java.util.Vector;
import javax.media.*;
import javax.media.format.*;
/**
* this class gets information about capture devices (mics and cameras)
*/
public class DeviceFinder {
Vector videoDevices = new Vector();
Vector audioDevices = new Vector();
/**
* Constructor
* Creates a new DeviceFinder
*/
public DeviceFinder()
{
/*retrieve ALL video and audio devices*/
videoDevices = CaptureDeviceManager.getDeviceList(new VideoFormat(null));
audioDevices = CaptureDeviceManager.getDeviceList(new AudioFormat(null));
}
/**
* purpose: Get information on all Video capture devices on the system
* #return java.util.Vector a vector of attributes
*/
public Vector getVideoCaptureDevices()
{
return videoDevices;
}
/**
* purpose: Get information on all audio capture devices on the system
* #return java.util.Vector a vector of attributes
*/
public Vector getSoundCaptureDevices()
{
return audioDevices;
}
/**
* retrieve the first video capture device
*/
public CaptureDeviceInfo getPrimaryVideoCaptureDevice()
{
return (CaptureDeviceInfo)videoDevices.get(0);
}
/*retrieve the first audio capture device*/
public CaptureDeviceInfo getPrimaryAudioCaptureDevice()
{
return (CaptureDeviceInfo)audioDevices.get(0);
}
/**
* get the first video device name
* #return String the name of the video device
*/
public String getVideoCaptureDeviceName()
{
return ((CaptureDeviceInfo)videoDevices.get(0)).getName();
}
/**
* get the first audio device name
* #return String the name of the audio device
*/
public String getAudioCaptureDeviceName()
{
return ((CaptureDeviceInfo)audioDevices.get(0)).getName();
}
/**
* get the first video device media locator
* #return MediaLocator
*/
public MediaLocator getVideoMediaLocator()
{
return ((CaptureDeviceInfo)videoDevices.get(0)).getLocator();
}
/**
* get the first audio device media locator
* #return MediaLocator
*/
public MediaLocator getAudioMediaLocator()
{
return ((CaptureDeviceInfo)audioDevices.get(0)).getLocator();
}
/**
* get the video device media locator at index idx
* #param idx index of the media locator (0 is the first/default,
* as ordered by
* the JMFRegistry)
* #return MediaLocator
*/
public MediaLocator getVideoMediaLocator(int idx)
{
if(idx >= videoDevices.size())
{
return null;
}
return ((CaptureDeviceInfo)videoDevices.get(idx)).getLocator();
}
/**
* get the audio device media locator at index idx
* #param idx index of the audio device (as ordered by the JMFRegistry)
* #return MediaLocator
*/
public MediaLocator getAudioMediaLocator(int idx)
{
return ((CaptureDeviceInfo)audioDevices.get(idx)).getLocator();
}
/**
*
* #param args
*/
public static void main(String[] args)
{
DeviceFinder df = new DeviceFinder();
//DEBUG:
System.out.println(df.getVideoMediaLocator());
System.out.println(df.getAudioMediaLocator());
}
}
I don't think there is a better way. Unless the DLLs are explicitly loaded by path name, you would just need to make sure they are in the system path, so if they lived right next to the JVM executables it should also work. Windows does implicitly include the directory the program was started from in the system path, so that is another potential location.
Installers are a double edged sword, they make it easy to add new functionality and remove it later, but they also make it harder to deploy solutions that use the product.
One of the nice things about Java in general is that you don't have to install it for it to work. Essentially, once you perform the install of the JRE on one system, you can bundle it up and use it on another system as a zip file. Java doesn't need to explicitly register the DLLs because it loads them dynamically as needed.

Categories

Resources