I'm browsing the PrimeFaces 6.1 source at GitHub.
The components only seem to have a renderer class and no component class. For example, the OutputLabelRenderer references
the OutputLabel, but the OutputLabel class is nowhere to be found. I expected it to be in the same folder as the renderer (as there was no import).
I did find this template file though. So it looks like it is generated somehow.
Where can I find the attributes for a PrimeFaces component?
After checking the pom.xml I've found this plugin:
<plugin>
<groupId>org.primefaces</groupId>
<artifactId>maven-jsf-plugin</artifactId>
<version>1.3.3-SNAPSHOT</version>
<executions>
<execution>
<id>generate-ui</id>
<phase>generate-sources</phase>
<configuration>
<uri>http://primefaces.org/ui</uri>
<shortName>p</shortName>
<templatesDir>src/main/java-templates</templatesDir>
<componentConfigsDir>target/resources-maven-jsf/ui</componentConfigsDir>
<standardFacesConfig>src/main/resources-maven-jsf/standard-faces-config.xml</standardFacesConfig>
<standardFaceletsTaglib>src/main/resources-maven-jsf/standard-facelets-taglib.xml</standardFaceletsTaglib>
<standardTLD>src/main/resources-maven-jsf/standard-tld.xml</standardTLD>
</configuration>
<goals>
<goal>generate-components</goal>
<goal>generate-facelets-taglib</goal>
</goals>
</execution>
...
</executions>
</plugin>
The definition (including the attributes) are located in the /src/main/resources-maven-jsf/ui/ folder. For examplate outputLabel.xml.
You can also download the sources JAR from Maven. It will include the component code. For example:
/*
* Generated, Do Not Modify
*/
/*
* Copyright 2009-2013 PrimeTek.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.primefaces.component.outputlabel;
import javax.faces.component.html.HtmlOutputLabel;
import javax.faces.context.FacesContext;
import javax.faces.component.UINamingContainer;
import javax.el.ValueExpression;
import javax.el.MethodExpression;
import javax.faces.render.Renderer;
import java.io.IOException;
import javax.faces.component.UIComponent;
import javax.faces.event.AbortProcessingException;
import javax.faces.application.ResourceDependencies;
import javax.faces.application.ResourceDependency;
import java.util.List;
import java.util.ArrayList;
import org.primefaces.util.ComponentUtils;
#ResourceDependencies({
})
public class OutputLabel extends HtmlOutputLabel {
public static final String COMPONENT_TYPE = "org.primefaces.component.OutputLabel";
public static final String COMPONENT_FAMILY = "org.primefaces.component";
public static final String DEFAULT_RENDERER = "org.primefaces.component.OutputLabelRenderer";
public enum PropertyKeys {
indicateRequired;
String toString;
PropertyKeys(String toString) {
this.toString = toString;
}
PropertyKeys() {}
public String toString() {
return ((this.toString != null) ? this.toString : super.toString());
}
}
public OutputLabel() {
setRendererType(DEFAULT_RENDERER);
}
public String getFamily() {
return COMPONENT_FAMILY;
}
public boolean isIndicateRequired() {
return (java.lang.Boolean) getStateHelper().eval(PropertyKeys.indicateRequired, true);
}
public void setIndicateRequired(boolean _indicateRequired) {
getStateHelper().put(PropertyKeys.indicateRequired, _indicateRequired);
}
public final static String STYLE_CLASS = "ui-outputlabel ui-widget";
public final static String REQUIRED_FIELD_INDICATOR_CLASS = "ui-outputlabel-rfi";
}
Related
I'm trying to create a simple Junit5-Cucumber project (in Eclipse) that would be used for UI testing.
I took reference from this repo:https://github.com/cucumber/cucumber-java-skeleton
Issue: No definition found for Open the Chrome and launch the application (error happens to the Given, When and Then statements) in the test_features.feature file.
# test_features.feature
Feature: Reset functionality on login page of Application
Scenario: Verification of Reset button
Given Open the Chrome and launch the application
When Enter the username and password
Then Reset the credentials
# RunCucumberTest.java
package lpms.cucumber;
import org.junit.platform.suite.api.ConfigurationParameter;
import org.junit.platform.suite.api.IncludeEngines;
import org.junit.platform.suite.api.SelectClasspathResource;
import org.junit.platform.suite.api.Suite;
import static io.cucumber.junit.platform.engine.Constants.PLUGIN_PROPERTY_NAME;
import static io.cucumber.junit.platform.engine.Constants.GLUE_PROPERTY_NAME;
#Suite
#IncludeEngines("cucumber")
#SelectClasspathResource("lpms/cucumber")
#ConfigurationParameter(key = PLUGIN_PROPERTY_NAME, value = "pretty")
#ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "lpms.cucumber")
public class RunCucumberTest {
}
# StepDefinitions.java
package lpms.cucumber;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
public class StepDefinitions {
#Given("^Open the Chrome and launch the application$")
public void open_the_chrome_and_launch_the_application() throws Throwable
{
System.out.println("This step opens the chrome and launches the application");
}
#When("^Enter the username and password$")
public void enter_the_username_and_password() throws Throwable
{
System.out.println("This step enters the username and password on the login page");
}
#Then("^Reset the credentials$")
public void reset_the_credential() throws Throwable
{
System.out.println("This step clicks on the reset button.");
}
}
Project Structure
IMAGE OF MY PROJECT STRUCTURE
Solved!
It's a warning from Eclipse IDE, likely just a bug, because I can still get testing done.
Sidenote: Extremely useful guide for learning the latest cucumber: https://cucumber.io/docs/guides/10-minute-tutorial/
I had the same problem on my project and i'll post my solution here.
I've used Eclipse + Java 11 + SpringBoot 2.6.4
pom.xml dependencies
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<scope>test</scope>
<version>7.3.0</version>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit-platform-engine</artifactId>
<version>7.3.0</version>
<scope>test</scope>
</dependency>
pom.xml plugin in build section
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<properties>
<configurationParameters>
cucumber.junit-platform.naming-strategy=long
</configurationParameters>
</properties>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
</plugin>
After that, i've created a package in src/test/java called
filelife/skynet/cucumber
In this package i've created my steps class and my runner class; Steps class contains only some logging instrauctions, it doesn't verify nothing yet.
Steps class:
#Slf4j
public class SendMessagesOnServiceLimitsSteps {
#Given("A ServiceLimits Module with PosTXRate of {int} seconds")
public void a_service_limits_module_with_pos_tx_rate_of_seconds(Integer posTxRate) {
log.info("ServiceLimits PosTxRate {}", posTxRate);
System.out.println("Given Step");
}
#When("I keyOn the device")
public void i_key_on_the_device() {
System.out.println("Given Step");
}
#When("i wait for {int} seconds")
public void i_wait_for_seconds(Integer int1) {
System.out.println("Given Step");
}
#When("i keyOff the device")
public void i_key_off_the_device() {
System.out.println("Given Step");
}
#Then("PositionData messages should be {int} or {int}")
public void position_data_messages_should_be_or(Integer int1, Integer int2) {
System.out.println("Given Step");
}
#Then("device log print {string}")
public void device_log_print(String string) {
System.out.println("Given Step");
}
}
And my runner tests class:
#Suite
#IncludeEngines("cucumber")
#SelectClasspathResource("filelife/skynet/cucumber")
#ConfigurationParameter(
key = GLUE_PROPERTY_NAME,
value = "filelife.skynet.cucumber"
)
public class SkynetTest{
}
I've also created the same folder path (filelife/skynet/cucumber) in src/test/resources source folder and i've pasted my .feature file.
In the end, i've created 2 files:
cucumber.properties
junit-platform.properties
in same source folder src/test/resources containg, both of them, string:
cucumber.publish.quiet=true
This configuration works with:
mvn tests
and
right click on SkynetTest -> RunAs -> Junit Test
i'm trying to change the displayed name of the minecraft version 'cause of some server has plugin which detects if a client is running forge by checking its version, i tried to decompile several .class files in search of that settings but i didn't found it, here the screen of what "displayed version" i'm talking about.
the only thing that i found is this "id", but if i change it i only get minecraft crashing.
{
"_comment_": [
"Please do not automate the download and installation of Forge.",
"Our efforts are supported by ads from the download page.",
"If you MUST automate this, please consider supporting the project through https://www.patreon.com/LexManos/"
],
"id": "1.16.5-forge-36.2.0",
"time": "2021-07-22T01:48:10+00:00",
"releaseTime": "2021-07-22T01:48:10+00:00",
"type": "release",
"mainClass": "cpw.mods.modlauncher.Launcher",
"inheritsFrom": "1.16.5",
"logging": {
},
pls help, this is getting me mad.
This is called a client brand. Vanilla Minecraft uses vanilla, Forge uses fml,forge, Lunar client uses Lunarclient:LunarVersionNumber, etc. I don't know about 1.16.5, but in 1.8.9 the class which is used for getting the client brand is net.minecraft.client.ClientBrandRetriever (It would be similar to 1.8.9). You would need to use mixins or another way of manipulating code at runtime to modify this.
ok i actually found something while trying making the mod, i found this 2 .class file.
Forge's ClientBrandRetriever.class
package net.minecraft.client;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
#OnlyIn(Dist.CLIENT)
public class ClientBrandRetriever {
public static String getClientModName() {
return net.minecraftforge.fml.BrandingControl.getClientBranding();
}
}
and this called BrandingControl.class
/*
* Minecraft Forge
* Copyright (c) 2016-2021.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.stream.IntStream;
import net.minecraft.resources.IResourceManager;
import net.minecraft.resources.IResourceManagerReloadListener;
import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.versions.forge.ForgeVersion;
import net.minecraftforge.versions.mcp.MCPVersion;
public class BrandingControl
{
private static List<String> brandings;
private static List<String> brandingsNoMC;
private static List<String> overCopyrightBrandings;
private static void computeBranding()
{
if (brandings == null)
{
ImmutableList.Builder<String> brd = ImmutableList.builder();
brd.add("Forge " + ForgeVersion.getVersion());
brd.add("Minecraft " + MCPVersion.getMCVersion());
brd.add("MCP " + MCPVersion.getMCPVersion());
int tModCount = ModList.get().size();
brd.add(ForgeI18n.parseMessage("fml.menu.loadingmods", tModCount));
brandings = brd.build();
brandingsNoMC = brandings.subList(1, brandings.size());
}
}
private static List<String> getBrandings(boolean includeMC, boolean reverse)
{
computeBranding();
if (includeMC) {
return reverse ? Lists.reverse(brandings) : brandings;
} else {
return reverse ? Lists.reverse(brandingsNoMC) : brandingsNoMC;
}
}
private static void computeOverCopyrightBrandings() {
if (overCopyrightBrandings == null) {
ImmutableList.Builder<String> brd = ImmutableList.builder();
if (ForgeHooksClient.forgeStatusLine != null) brd.add(ForgeHooksClient.forgeStatusLine);
overCopyrightBrandings = brd.build();
}
}
public static void forEachLine(boolean includeMC, boolean reverse, BiConsumer<Integer, String> lineConsumer) {
final List<String> brandings = getBrandings(includeMC, reverse);
IntStream.range(0, brandings.size()).boxed().forEachOrdered(idx -> lineConsumer.accept(idx, brandings.get(idx)));
}
public static void forEachAboveCopyrightLine(BiConsumer<Integer, String> lineConsumer) {
computeOverCopyrightBrandings();
IntStream.range(0, overCopyrightBrandings.size()).boxed().forEachOrdered(idx->lineConsumer.accept(idx, overCopyrightBrandings.get(idx)));
}
public static String getClientBranding() {
return "forge";
}
public static String getServerBranding() {
return "forge";
}
public static IResourceManagerReloadListener resourceManagerReloadListener() {
return BrandingControl::onResourceManagerReload;
}
private static void onResourceManagerReload(IResourceManager resourceManager) {
brandings = null;
brandingsNoMC = null;
}
}
at this point i managed to rebuild this last .class file changing the client and server branding returns to "elberto", now when i'm running the sdk environment it says "elberto" on the version, but when i'm trying to do the same with the actual minecraft forge file it load everithing and at the end of loading it crash.
I'm pretty sure that this isn't a really good way to do what i want to do, if you know a better way doing a proper working mod i'm listening
The following example works in a Java EE6 (Glassfish3) project of mine but failed after I switched to Java EE7 (Glassfish4). The HTTP request returns "500 Internal Error" without any message in the Glassfish server log. The project was setup using NetBeans8 as Maven Web Project and has no special dependencies, beans.xml or other configuration.
#RequestScoped
#Path("generic")
public class GenericResource {
#GET
#Path("ping")
#Produces(APPLICATION_JSON)
public List<String> debugPing() {
return Arrays.asList("pong");
}
And then:
$ curl -v http://localhost:8080/mavenproject2/webresources/generic/ping
> GET /mavenproject2/webresources/generic/ping HTTP/1.1
...
< HTTP/1.1 500 Internal Server Error
As as I understand, all REST handling is done by the Jackson reference implementation and that Jackson uses Jersey as underlaying JSON library. One of the two is supposed to have some kind of provider for all basic data types. Only custom made classes need a self written ObjectMapper. Are these concepts still correct?
It took me some hours but I finally solved this question myself.
First fact is that the Glassfish4 JAX-RS implementation "Jersey" as switched its underlying JSON library from Jackson 1.x to Eclipselink MOXy. The latter seems not be able to convert Lists, Arrays and arbitrary POJOs to JSON out of the box. Therefore I tried to force JAX-RS to use Jackson 2.x and disable MOXy.
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
// This is Jackson 2.x, Jackson 1.x used org.codehaus.jackson!
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#ApplicationPath("rest")
public class RestConfig extends Application {
private final static Logger log = LoggerFactory.getLogger(RestConfig.class);
#Override
public Set<Object> getSingletons() {
Set<Object> set = new HashSet<>();
log.info("Enabling custom Jackson JSON provider");
set.add(new JacksonJsonProvider() /* optionally add .configure(SerializationFeature.INDENT_OUTPUT, true) */);
return set;
}
#Override
public Map<String, Object> getProperties() {
Map<String, Object> map = new HashMap<>();
log.info("Disabling MOXy JSON provider");
map.put("jersey.config.disableMoxyJson.server", true);
return map;
}
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new java.util.HashSet<>();
// ... add your own REST enabled classes here ...
return resources;
}
}
My pom.xml contains:
<dependency>
<!-- REST (Jackson as JSON mapper) -->
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.2.3</version>
</dependency>
<dependency>
<!-- REST (Jackson LowerCaseWithUnderscoresStrategy etc.) -->
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.2.3</version>
</dependency>
Hope this helps someone!
I have written the above rule and when trying to run it from the command line I keep getting the same message namely:
Unable to create Checker: cannot initialize module TreeWalker - Unable to instantiate LoggerAttrCheck
I have stripped down my checks to just one in Checker and one in Treewalker, copied religiously the entries as suggested in the manual and no joy. Anyone had similar issues with custom rules. I am WinXP, java 1.6 (Eclipse), checkstyle-5.1 folder is in path.
I can provide code but this smells of an environmental issue.
Code is as follows:
package com.mystuff.checkstyle.hecks;
import com.puppycrawl.tools.checkstyle.api.Check;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.FullIdent;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
import com.puppycrawl.tools.checkstyle.checks.CheckUtils;
/**
*
*
* This package provides the custom checks that were required outside
* of the standard checks provided
*
*/
public class LoggerAttrCheck extends Check
{
/**
*
*
* The Logger must be declared as a static final class attribute
*
*/
#Override
public int[] getDefaultTokens()
{
return new int[] { TokenTypes.VARIABLE_DEF};
}
#Override
public void visitToken(DetailAST aAST)
{
if(aAST.getType()==TokenTypes.VARIABLE_DEF)
visitVariableDef(aAST);
}
/**
* Checks type of given variable.
* #param aAST variable to check.
*/
private void visitVariableDef(DetailAST aAST)
{
checkVariableDefn(aAST);
}
/**
*
* Checks variable to see if its a Logger and static final
* * #param aAST node to check.
*/
private void checkVariableDefn(DetailAST aAST)
{
final DetailAST type = aAST.findFirstToken(TokenTypes.TYPE);
final FullIdent ident = CheckUtils.createFullType(type);
if ((ident.getText().equals("Logger")))
{
if((!aAST.branchContains(TokenTypes.FINAL))||(!aAST.branchContainsTokenTypes.LITERAL_STATIC)))
{
log(type.getLineNo(), type.getColumnNo(),
"Logger not defined as static final class attribute", type.getText());
}
}
}
}
This builds com.stuff.checkstyle.checks.jar, so the the checkstyle_packages.xml looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE checkstyle-packages PUBLIC
"-//Puppy Crawl//DTD Package Names 1.3//EN"
"http://www.puppycrawl.com/dtds/packages_1_3.dtd">
<checkstyle-packages>
<package name="com.mystuff.checkstyle.checks"/>
</checkstyle-packages>
All ideas gratefully received !
What does your checkstyle configuration file look like? It appears that your checkstyle_packages.xml is being ignored. I found I couldn't add my package to the checkstyle-packages and so declared my check with the full package name:
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.2//EN"
"http://www.puppycrawl.com/dtds/configuration_1_2.dtd">
<module name="Checker">
<module name="TreeWalker">
<!-- Blundell specific checks -->
<module name="com.blundell.checks.AntiHungarian" />
</module>
</module>
Note that the java class name for the check is AntiHungarianCheck but you declare is as just AntiHungarian
Taken from my custom checkstyle example here:
http://blog.blundell-apps.com/create-your-own-checkstyle-check/
and source code here:
https://github.com/blundell/CreateYourOwnCheckStyleCheck
I have several projects built by maven, and I want to share some common properties among them - spring version, mysql driver version, svn base url, etc. - so I can update them once and it will be reflected on all projects.
I thought of having a single super pom with all the properties, but if I change one of the problem I need to either increment its version (and to update all the poms inherit from it) or to delete it from all the developers' machines which I don't want to do.
Can specify these parameters externally to the pom? I still want to have the external location definition in a parent pom.
What you can do is to use the Properties Maven plugin. This will let you define your properties in an external file, and the plugin will read this file.
With this configuration :
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0-alpha-1</version>
<executions>
<execution>
<phase>initialize</phase>
<goals>
<goal>read-project-properties</goal>
</goals>
<configuration>
<files>
<file>my-file.properties</file>
</files>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
and if you have, in your properties file the following lines:
spring-version=1.0
mysql-version=4.0.0
then it's the same thing as if you wrote, in your pom.xml, the following lines:
<properties>
<spring-version>1.0</spring-version>
<mysql-version>4.0.0</mysql-version>
</properties>
Using this plugin, you will have several benefits:
Set easily a long list of properties
Modify the values of these properties without modifying the parent pom.xml.
Note that the original idea I have here is something that I am doing, but that I may have found a much better idea which I've also listed out below. I wanted to keep both ideas here for completeness in case the newer idea does not work.
I think you can solve this problem using the parent pom, but you need to have a maven repository and a CI build tool.
I've got several projects which all inherit base properties from a parent POM. We use Java 1.5, so that build property is setup there. Everything is UTF-8. All of the reports that I wish to run, Sonar setup, etc, is inside the parent POM.
Assuming your project is in version control and you've got a CI tool, when you check in, your CI tool can build to POM project and deploy the SNAPSHOT to the maven repos. If your projects point to the SNAPSHOT version of the parent POM, they'll check the repository to validate that they have the latest version...if not they download the latest version. So if you update the parent, all of the other projects will update.
The trick, I suppose is releasing with a SNAPSHOT. I'd say your releases are going to come much less frequently than your changes. So you perform a release of your POM, then update your POMs that inherit from them and check them into version control. Let the devs know that they need to do an update and go from there.
You could just trigger builds there forcing the new POMs into the repository and then have all of the devs pick up the changes automagically upon build.
I've removed the LATEST/RELEASE keywords idea because they do not work for parent POMs. They only work for dependencies or plugins. The problem area is in DefaultMavenProjectBuilder. Essentially it has trouble determining which repository to look for the parent to determine what the latest or release version is. Not sure why this is different for dependencies or plugins though.
It sounds like these would be less painful than having to update the POMs on every change to the parent POM.
I think the properties-maven-plugin is the right approach long term, but as you responded to that answer it doesn't allow the properties to be inherited. There are some facilities in maven-shared-io that allow you to discover resources on the project classpath. I've included some code below that extends the properties plugin to find properties files in the dependencies of the plugin.
The configuration declares a path to a properties file, because the descriptor project is declared on the plugin configuration, it is accessible to the ClasspathResourceLocatorStrategy. The configuration can be defined in a parent project, and will be inherited by all the child projects (if you do this avoid declaring any files as they won't be discovered, only set the filePaths property).
The configuration below assumes that there is another jar project called name.seller.rich:test-properties-descriptor:0.0.1 that has a file called external.properties packaged into the jar (i.e. it was defined in src/main/resources).
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-ext-maven-plugin</artifactId>
<version>0.0.1</version>
<executions>
<execution>
<id>read-properties</id>
<phase>initialize</phase>
<goals>
<goal>read-project-properties</goal>
</goals>
</execution>
</executions>
<configuration>
<filePaths>
<filePath>external.properties</filePath>
</filePaths>
</configuration>
<dependencies>
<!-- declare any jars that host the required properties files here -->
<dependency>
<groupId>name.seller.rich</groupId>
<artifactId>test-properties-descriptor</artifactId>
<version>0.0.1</version>
</dependency>
</dependencies>
</plugin>
The pom for the plugin project looks like this:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-ext-maven-plugin</artifactId>
<packaging>maven-plugin</packaging>
<version>0.0.1</version>
<dependencies>
<dependency>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0-alpha-1</version>
</dependency>
<dependency>
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-shared-io</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
</project>
The mojo is a copy of the properties plugin's ReadPropertiesMojo, with an additional "filePaths" property to allow you to define the relative path to the external properties file in the classpath, it makes the files property optional, and adds the readPropertyFiles() and getLocation() methods to locate the files and merge any filePaths into the files array before continuing. I've commented my changes to make them clearer.
package org.codehaus.mojo.xml;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.io.location.ClasspathResourceLocatorStrategy;
import org.apache.maven.shared.io.location.FileLocatorStrategy;
import org.apache.maven.shared.io.location.Location;
import org.apache.maven.shared.io.location.Locator;
import org.apache.maven.shared.io.location.LocatorStrategy;
import org.apache.maven.shared.io.location.URLLocatorStrategy;
import org.codehaus.plexus.util.cli.CommandLineUtils;
/**
* The read-project-properties goal reads property files and stores the
* properties as project properties. It serves as an alternate to specifying
* properties in pom.xml.
*
* #author Zarar Siddiqi
* #author Krystian Nowak
* #version $Id: ReadPropertiesMojo.java 8861 2009-01-21 15:35:38Z pgier $
* #goal read-project-properties
*/
public class ReadPropertiesMojo extends AbstractMojo {
/**
* #parameter default-value="${project}"
* #required
* #readonly
*/
private MavenProject project;
/**
* The properties files that will be used when reading properties.
* RS: made optional to avoid issue for inherited plugins
* #parameter
*/
private File[] files;
//Begin: RS addition
/**
* Optional paths to properties files to be used.
*
* #parameter
*/
private String[] filePaths;
//End: RS addition
/**
* If the plugin should be quiet if any of the files was not found
*
* #parameter default-value="false"
*/
private boolean quiet;
public void execute() throws MojoExecutionException {
//Begin: RS addition
readPropertyFiles();
//End: RS addition
Properties projectProperties = new Properties();
for (int i = 0; i < files.length; i++) {
File file = files[i];
if (file.exists()) {
try {
getLog().debug("Loading property file: " + file);
FileInputStream stream = new FileInputStream(file);
projectProperties = project.getProperties();
try {
projectProperties.load(stream);
} finally {
if (stream != null) {
stream.close();
}
}
} catch (IOException e) {
throw new MojoExecutionException(
"Error reading properties file "
+ file.getAbsolutePath(), e);
}
} else {
if (quiet) {
getLog().warn(
"Ignoring missing properties file: "
+ file.getAbsolutePath());
} else {
throw new MojoExecutionException(
"Properties file not found: "
+ file.getAbsolutePath());
}
}
}
boolean useEnvVariables = false;
for (Enumeration n = projectProperties.propertyNames(); n
.hasMoreElements();) {
String k = (String) n.nextElement();
String p = (String) projectProperties.get(k);
if (p.indexOf("${env.") != -1) {
useEnvVariables = true;
break;
}
}
Properties environment = null;
if (useEnvVariables) {
try {
environment = CommandLineUtils.getSystemEnvVars();
} catch (IOException e) {
throw new MojoExecutionException(
"Error getting system envorinment variables: ", e);
}
}
for (Enumeration n = projectProperties.propertyNames(); n
.hasMoreElements();) {
String k = (String) n.nextElement();
projectProperties.setProperty(k, getPropertyValue(k,
projectProperties, environment));
}
}
//Begin: RS addition
/**
* Obtain the file from the local project or the classpath
*
* #throws MojoExecutionException
*/
private void readPropertyFiles() throws MojoExecutionException {
if (filePaths != null && filePaths.length > 0) {
File[] allFiles;
int offset = 0;
if (files != null && files.length != 0) {
allFiles = new File[files.length + filePaths.length];
System.arraycopy(files, 0, allFiles, 0, files.length);
offset = files.length;
} else {
allFiles = new File[filePaths.length];
}
for (int i = 0; i < filePaths.length; i++) {
Location location = getLocation(filePaths[i], project);
try {
allFiles[offset + i] = location.getFile();
} catch (IOException e) {
throw new MojoExecutionException(
"unable to open properties file", e);
}
}
// replace the original array with the merged results
files = allFiles;
} else if (files == null || files.length == 0) {
throw new MojoExecutionException(
"no files or filePaths defined, one or both must be specified");
}
}
//End: RS addition
/**
* Retrieves a property value, replacing values like ${token} using the
* Properties to look them up. Shamelessly adapted from:
* http://maven.apache.
* org/plugins/maven-war-plugin/xref/org/apache/maven/plugin
* /war/PropertyUtils.html
*
* It will leave unresolved properties alone, trying for System properties,
* and environment variables and implements reparsing (in the case that the
* value of a property contains a key), and will not loop endlessly on a
* pair like test = ${test}
*
* #param k
* property key
* #param p
* project properties
* #param environment
* environment variables
* #return resolved property value
*/
private String getPropertyValue(String k, Properties p,
Properties environment) {
String v = p.getProperty(k);
String ret = "";
int idx, idx2;
while ((idx = v.indexOf("${")) >= 0) {
// append prefix to result
ret += v.substring(0, idx);
// strip prefix from original
v = v.substring(idx + 2);
idx2 = v.indexOf("}");
// if no matching } then bail
if (idx2 < 0) {
break;
}
// strip out the key and resolve it
// resolve the key/value for the ${statement}
String nk = v.substring(0, idx2);
v = v.substring(idx2 + 1);
String nv = p.getProperty(nk);
// try global environment
if (nv == null) {
nv = System.getProperty(nk);
}
// try environment variable
if (nv == null && nk.startsWith("env.") && environment != null) {
nv = environment.getProperty(nk.substring(4));
}
// if the key cannot be resolved,
// leave it alone ( and don't parse again )
// else prefix the original string with the
// resolved property ( so it can be parsed further )
// taking recursion into account.
if (nv == null || nv.equals(nk)) {
ret += "${" + nk + "}";
} else {
v = nv + v;
}
}
return ret + v;
}
//Begin: RS addition
/**
* Use various strategies to discover the file.
*/
public Location getLocation(String path, MavenProject project) {
LocatorStrategy classpathStrategy = new ClasspathResourceLocatorStrategy();
List strategies = new ArrayList();
strategies.add(classpathStrategy);
strategies.add(new FileLocatorStrategy());
strategies.add(new URLLocatorStrategy());
List refStrategies = new ArrayList();
refStrategies.add(classpathStrategy);
Locator locator = new Locator();
locator.setStrategies(strategies);
Location location = locator.resolve(path);
return location;
}
//End: RS addition
}