I'm developing a custom authentication plugin for OAM(Oracle Access Manager) in Java language using JDeveloper IDE.
i'm parsing a URL and i get the variables i want from a JSONObject correctly on a Main.class file without triggering any kind of Exception
This leads me to the assumption that the whole parsing code is correct which means the readJsonFromUrl function does it job.
Let me mention what my PhillPlugin.class includes
public ExecutionStatus process(AuthenticationContext context) ,
triggered when the Plug-In is to run.
public void getDataGenerate(String Url), called inside process function to created the JSONObject from URL
public static JSONObject readJsonFromUrl(String url) called inside getDataGenerate function
private static String readAll(Reader rd) used for parsing inside readJsonFromUrl
Now i upload the Plug-In to the server, i run it and get the following in it's Logs
java.lang.NoClassDefFoundError: org/json/JSONObject
at phillplugin.PhillPlugin.readJsonFromUrl(PhillPlugin.java:184)
at phillplugin.PhillPlugin.getDataGenerate(PhillPlugin.java:132)
at phillplugin.PhillPlugin.process(PhillPlugin.java:63)
What is needed in order to create the Plug-In:
PhillPlugin.class
PhillPlugin.xml
MANIFEST.MF
I'm mentioning the above because i have to include somewhere in these files the org.json path. ( it already exists as an import in PhillPlugin.class and Main.class )
The org.json.jar is included in Project's Libraries as well as all the .jars in order to build the Plug-In
MANIFEST.MF
Manifest-Version: 1.0
Bundle-Version: 10
Bundle-Name: PhillPlugin
Bundle-Activator: phillplugin.PhillPlugin
Bundle-ManifestVersion: 2
Import-Package: org.osgi.framework;version="1.3.0",oracle.security.am.plugin,oracle.security.am.plugin.authn,oracle.security.am.plugin.impl,oracle.security.am.plugin.api,oracle.security.am.common.utilities.principal,oracle.security.idm,javax.security.auth
Bundle-SymbolicName: PhillPlugin
CLASSPATH: felix.jar, identitystore.jar, oam-plugin.jar, utilities.jar, org.json.jar
Sample of the PhillPlugin.Class
I'm not supposed to include the URL for security purposes. (Trust me it's Valid)
public void getDataGenerate(String Url) {
System.out.println("----- Reading Json Object -----");
JSONObject json;
try {
json = readJsonFromUrl(Url);
System.out.println("The Json Object: "+json.toString());
otp=Integer.parseInt((String) json.get("otp"));
System.out.println("The User is:"+user+"\n"+"His OTP is: "+otp);
} catch (Exception e) {
System.out.println("Exception : "+e.toString());
}
public static JSONObject readJsonFromUrl(String url) throws IOException,JSONException {
System.out.println("Opening Stream");
InputStream is = new URL(url).openStream();
System.out.println("Stream opened");
try {
System.out.println("----------\n\n\nUrl to Parse: "+url+"\n\n\n");
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
System.out.println("\n\n\n"+"BufferedReader opened\n\n\n\n");
String jsonText =(String) readAll(rd);
System.out.println("\n\n\nJsonTEXT:"+jsonText+"\n\n\n");
JSONObject json=null;
System.out.println("\n\n Created Json Instance\n\n\n");
try{
System.out.println("inside try statement - initializing JSONObject with the text above \n\n\n");
//-------ERROR TRIGGERED HERE---------
json = new JSONObject(jsonText);
System.out.println("--------------------Object created-------------------");
}catch (Exception e) {
System.out.println("\n\n\n\n\nJSONOBJECT failed to be created: \n"+e);
}
System.out.println("\n\n\nJSON OBJECT"+json+"\n\n\n\n");
return json;
} finally {
is.close();
}
private static String readAll(Reader rd) throws IOException {
StringBuilder sb = new StringBuilder();
int cp;
while ((cp = rd.read()) != -1) {
sb.append((char) cp);
}
return sb.toString();
}
PhillPlugin.xml
<Plugin type="Authentication">
<author>uid=Phill</author>
<email>phill#oracle.com</email>
<creationDate>12:47:00, 2019-07-11</creationDate>
<description>Phill-Plugin Prints Hello</description>
<configuration>
</configuration>
</Plugin>
This is the output on server Logs before crashing:
Stream opened
----------
Url to Parse: https://something
BufferedReader opened
JsonTEXT: it's correct
Created Json Instance
inside try statement - initializing JSONObject with the text above
I'm worrying too much about the MANIFEST.MF file because probably i'm
doing something wrong in there
Sorry for the long post, i will provide any extra information if needed, Thank you
When writing an Authenticaiton Plugin for OAM Server , all extra libraries should be mentioned in MANIFEST.MF as well as the external .jar files.
Furthermore , all .jar files should be deployed in the final plugin .jar as well as the external libraries
In my case i had to include org.json.jar at the exported PhillPlugin.jar as follows:
PhillPlugin.jar
as you can see both org.json.jar and it's libraries org are required
Manifest.MF
The last step is to mention in MANIFEST.MF all the extra classes that you are using in your plugin
In my case i had to include this in my Import-Package Attribute in order to be able to create a JSONObject instance
org.json;resolution:=optional,
org.json.JSONObject;resolution:=optional
If you would like to use a JSONArray you had to add this:
org.json.JSONArray;resolution:=optional
and so on.
Edit: The class-path should be mentioned as follows:
Bundle-ClassPath: org.json.jar, felix.jar, identity-provider.jar, oam-plugin.jar, utilities.jar
The CLASSPATH entry in the MANIFEST.MF is obviously wrong. Correct name is Class-Path see: https://docs.oracle.com/javase/tutorial/deployment/jar/downman.html
Whole MANIFEST.MF documentation: https://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html
Related
I want to add custom manifest attributes to an existing jar file. The file is an external jar and is not the jar containing my application, nor is it a dependency of my application.
I drafted up some test code and verified that it makes the desired changes (by accessing the manifest with 7zip). However, it seems like Java is ignoring the manifest entry. When I call java.util.jar.Attributes.getValue(String), it returns null. This is the code I am using:
public static void main(String[] args) throws IOException, URISyntaxException {
File jar = new File("C:\\Users\\employee1234\\Desktop\\auth-0.1.3.jar");
String testVersion = "1.2.3";
Map<String, String> env = new HashMap<>();
env.put("create", "true");
// Mount the jar
try (FileSystem fileSystem = FileSystems.newFileSystem(jarFileToURI(jar), env)) {
// Read the manifest
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Path manifestPath = fileSystem.getPath("/META-INF/MANIFEST.MF");
Files.copy(manifestPath, byteArrayOutputStream);
// Convert the manifest bytes to a string and construct a string builder
StringBuilder manifestData = new StringBuilder(byteArrayOutputStream.toString().trim());
// Add the custom manifest attribute
manifestData.append("\n");
manifestData.append("Deployments-Version: ");
manifestData.append(testVersion);
// Write the manifest back to the jar
Files.copy(new ByteArrayInputStream(manifestData.toString().getBytes()), manifestPath,
StandardCopyOption.REPLACE_EXISTING);
// Try-with-resources closes the mounted jar
}
// This part doesn't work
try (JarFile jarFile = new JarFile(jar)) {
Manifest manifest = jarFile.getManifest();
System.out.println(manifest.getMainAttributes().getValue("Deployments-Version"));
}
}
// Stolen from java.io.File with some modifications
private static URI jarFileToURI(File jarFile) throws URISyntaxException {
String sp = slashify(jarFile.getAbsoluteFile().getPath(), false);
if (sp.startsWith("//"))
sp = "//" + sp;
return new URI("jar:file", null, sp, null);
}
// Stolen from java.io.File;
private static String slashify(String path, boolean isDirectory) {
String p = path;
if (File.separatorChar != '/')
p = p.replace(File.separatorChar, '/');
if (!p.startsWith("/"))
p = "/" + p;
if (!p.endsWith("/") && isDirectory)
p = p + "/";
return p;
}
I inspected the Manifest instance in my debugger and the attribute was not anywhere present. I double and triple checked the jar file, and the manifest reflects my changes:
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: employee1234
Build-Jdk: 1.8.0_202
Deployments-Version: 1.2.3
Is my issue with the way I am adding the attribute, or is the way I am attempting to read it? What am I doing wrong?
Make sure you append another linefeed after your newly added entry in the manifest and you should be good to go.
manifestData.append("\n").append("Deployments-Version: ").append(testVersion).append("\n");
I tried to create a quick framework. in that I created below-mentioned classes:
Config file(All browsers path)
configDataProvider java class(reads the above file)
BrowserFactory class(has firefox browser object)
configDataProviderTest class(access data from dconfigDataProvider class)
now its not reading the paths mentioned in config.properties file.
I have provided all correct path and attached screenshots:
Looks like a problem is at your ConfigDataProvider class.
Firstly, you using Maven for building your project. Maven has defined project structure for code sources and for resources:
/src/main/java
/src/main/resorces
Thus, much better to put your .properties file there.
Second, you don't need to set the full path to your config file.
Relative path will be just enough. Something like below:
public class PropertiesFileHandler {
private static Logger log = Logger.getLogger(PropertiesFileHandler.class);
public static final String CONFIG_PROPERTIES = "src/main/resources/config.properties";
public static final String KEY = "browser.type";
public static BrowserType readBrowserType() {
BrowserType browserType = null;
Properties properties = new Properties();
try (InputStream inputStream = new BufferedInputStream(new FileInputStream(CONFIG_PROPERTIES))) {
properties.load(inputStream);
browserType = Enum.valueOf(BrowserType.class, properties.getProperty(KEY));
} catch (FileNotFoundException e) {
log.error("Properties file wasn't found - " + e);
} catch (IOException e) {
log.error("Problem with reading properties file - " + e);
}
return browserType;
}
}
Lastly, if you are building framework you don't need to put everything under src/main/test. This path specifies tests with future possibilities to be executed with maven default lifecycle - mvn test.
The core of your framework can look like:
Two things which I noticed:
Don't give path in your properties path within ""
all the path seperators should be replaced with double backward slash \\ or single forward slash /
First of all I would like to add that I probably have tried every proposed solution on SO about this issue but still cant get it working.
So this is my problem...
I have an application for parsing XML files. I select an xml file (source) and I validate it against an xsd (this is the file inside my JAR that I cant access). Running the code from within my IDE works fine:
xsd = new File(getClass().getResourceAsStream("xsds/2014/schema.xsd").getFile());
System.out.println(xsd.getAbsolutePath());
//returns: C:\Users\xxx\Desktop\Documents\NetBeansProjects\JavaXMLValidator\build\classes\app\xsds\2014\schema.xsd
But when I build by application to JAR file and I run it I cant get the reference to that file.
When I run the application from within my JAR i get this:
//returns: C:\Users\xxx\Desktop\Documents\NetBeansProjects\JavaXMLValidator\dist\file:C:\Users\xxx\Desktop\Documents\NetBeansProjects\JavaXMLValidator\dist\JavaXMLValidator.jar!\app\xsds\2014\schema.xsd
The path looks ok (i think) but I cant get a correct reference to my file in the code:
Source schemaFile = new StreamSource(xsd);
Schema schema = null;
try {
schema = factory.newSchema(schemaFile);
} catch (SAXException ex) {
JOptionPane.showMessageDialog(null, "Invalid XML Schema Selected!!!\n Exception: "+this.getStackTraceString(ex," "));
return;
}
I get the exception:
SAXParseException: schema_reference.4: Failed to read schema document
'C:\Users\xxx\Desktop\Documents\NetBeansProjects\JavaXMLValidator\dist\file:C:\Users\xxx\Desktop\Documents\NetBeansProjects\JavaXMLValidator\dist\JavaXMLValidator.jar!\app\xsds\2014\schema.xsd',
because 1)could not find the document;
2)the document could not be read;
3)the root element of the document is not <xsd:schema>
........
Can anyone suggest a way that I could have a correct reference to the xsd file withing the JAR?
Thanks a lot for any help
As MadProgrammer says, use the URL:
URL xsd = getClass().getResource("xsds/2014/schema.xsd");
Schema schema = null;
try {
schema = factory.newSchema(xsd);
} catch (SAXException ex) {
JOptionPane.showMessageDialog(null, "Invalid XML Schema Selected!!!\n Exception: "+this.getStackTraceString(ex," "));
return;
}
For example there is a project with such structure:
testproject
xsdfolder
schema.xsd
javaclassfolder
SomeClass.java
public static class SomeClass {
public static URL getLocalXsd() throws MalformedURLException {
URL baseUrl = SomeClass.class.getResource(SomeClass.class.getSimpleName() + ".class");
return new URL(baseUrl, "../xsdfolder/schema.xsd");
}
}
i want to open a file and return its content. Although it is in the same directory like the class that wants to open the file, the file can't be found. Would be cool if you could help me solving the problem.
Here is the code:
#GET #Produces("text/html") #Path("/{partNO}/") #Consumes("text/html")
public String getPartNoResponseHTML(#PathParam("partNO") String parID) throws WebApplicationException {
PartNoTemplate partNo = getPartNoResponse(parID);
String result = "";
try {
result = readFile(PART_NO_TEMPLATE_FILE);
} catch (FileNotFoundException e) {
e.printStackTrace(System.out);
return e.getMessage() + e.toString();
// throw new WebApplicationException(Response.Status.NOT_FOUND);
} finally {
result = result.replace("{partNO}", parID);
result = result.replace("{inputFormat}", partNo.getFormat().toString());
}
return result;
}
I guess it can't find the file, because its running on tomcat. I'm also using Jersey and JAX-RS. Thank you for your help,
Maxi
If the file is inside the application WAR (or in a jar) you can try by using
InputStream input = servletContext.getClass().getClassLoader().getResourceAsStream("my_filename.txt");
Your problem is similar (I think) with How can I read file from classes directory in my WAR?
Try to get the path of the file from ServletContext.
ServletContext context = //Get the servlet context
In JAX-RS to get servlet context use this:
#javax.ws.rs.core.Context
ServletContext context;
Then get the file from your web application:
File file = new File(context.getRealPath("/someFolder/myFile.txt"));
You don't post the code that actually tries to read the file, but assuming the file is in the classpath (as you mention it's in the same directory as the class) then you can do:
InputStream in = this.getClass().getResourceAsStream("/SomeTextFile.txt");
See here
My team are doing with 2 teams: server team and client team. We at server team will provide APIs for the client team to call. The APIs have many version, so that we need to match the server build and the respective client build - for example, the old client will refuse to work if the server build number is much larger than its support version and requires an update.
Because of the above reason, we need to send back the build version of server to client. Currently we are doing this by adding a static field in a Config class. But I'm concerned with the fact that we must manually increase it everytime a new server is built - especially when we do daily build. This process is quite error-prone and not quite elegant.
In my search, I see many propose for using maven plugins to manage the build version. Though I highly appreciated the auto-process, it still doesn't let the server know the build number. Server application should be able to return its build version to client through an API call.
I have thought of write the number version somewhere (remote database, files on server).
Is there any way to make the building process automatically increase the build version, but the application itself can retrieve this number in running also?
We are using Maven build and having Jenkin as the integration build server.
I usually read the version from the MANIFEST.MF file that is packaged in the JAR by Maven.
By default it looks something like this:
Manifest-Version: 1.0
Built-By: user
Build-Jdk: 1.6.0_35
Created-By: Apache Maven 3.0.4
Archiver-Version: Plexus Archiver
Name: Artifact
Implementation-Build: 1.14-SNAPSHOT
Version: 1.14-SNAPSHOT
From this file I read the Version element and use that to for instance display the build version of the application (and all versions of the packaged jars in a WAR/EAR for instance).
Something like this code should work:
public static String getApplicationVersion() {
String version = null;
try {
final List<VersionsUtil.Version> moduleVersions = VersionsUtil.getModuleVersions(Thread.currentThread().getContextClassLoader());
for (VersionsUtil.Version moduleVersion : moduleVersions) {
if (moduleVersion.name.equals("<NAME OF ARTIFACT TO GET>")) {
version = moduleVersion.version;
break;
}
}
} catch (IOException e) {
// We'll return null...
}
return version;
}
public class VersionsUtil {
private static final Logger LOG = LoggerFactory.getLogger(VersionsUtil.class);
/**
* Returns a list of the module versions available for the given class loader.
*
* #param classLoader the class loader to return module versions for
* #return a list of module versions
* #throws IOException in case there's an error reading the manifest
*/
public static List<Version> getModuleVersions(final ClassLoader classLoader) throws IOException {
return processResources(classLoader.getResources("META-INF/MANIFEST.MF"));
}
private static List<Version> processResources(final Enumeration<URL> resources) throws IOException {
final List<Version> moduleVersions = new ArrayList();
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
Version v = process(resource);
if (v != null) {
moduleVersions.add(v);
}
}
return moduleVersions;
}
private static Version process(final URL resource) {
try {
Properties p = readResource(resource);
return createVersion(p);
} catch (IOException e) {
LOG.warn("Failed to read resource: " + resource, e);
return null;
}
}
private static Version createVersion(final Properties p) {
Object name = p.get("Name");
if (name != null) {
return new Version((String) name, (String) p.get("Version"));
}
return null;
}
private static Properties readResource(final URL resource) throws IOException {
LOG.trace("Reading resource: " + resource);
InputStream is = resource.openStream();
Properties p = new Properties();
p.load(is);
is.close();
return p;
}
public static final class Version {
String name;
String version;
private Version(final String name, final String version) {
this.name = name;
this.version = version;
}
}
}
Updated:
If you want Jenkins buildnumber in the MANIFEST.MF you can configure your POM.XML with something like:
...
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<configuration>
<archive>
<manifestSections>
<manifestSection>
<name>${project.name} (${project.artifactId})</name>
<manifestEntries>
<Version>${project.version}${build.number}</Version>
</manifestEntries>
</manifestSection>
</manifestSections>
</archive>
</configuration>
</plugin>
...
<properties>
<build.number />
</properties>
...
If you're interested in tagging the WAR/EAR files instead, you have to add the manifest configurations accordingly.
Then in your Jenkins job configuration, simply pass the BUILD_NUMBER parameter to the maven process like this: -Dbuild.number=$BUILD_NUMBER.