Oracle: Success with compilation error with Java in SQL AES256 - java

I have a Java code that encrypts JSON data using AES 256. It works exactly as intended in the command prompt. But when I convert the same to SQL (Oracle server), it throws an error "success with compilation error". Below is the code:
create or replace JAVA SOURCE NAMED encryptData AS
import java.io.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import javax.xml.bind.DatatypeConverter;
import java.lang.Exception;
import java.util.Scanner;
import java.io.FileInputStream;
import java.io.BufferedReader;
import java.io.FileReader;
public class encryptData {
public static string encryptJSONCall(String jsonPath, String decSEK) {
String decSEK = decSEK;
File file = new File(jsonPath);
Scanner sc = new Scanner(file);
sc.useDelimiter("\\Z");
String json = removeWhitespaces(sc.next().replace("\n", "").replace("\r", ""));
String encryptedResult = encryptBySymmetricKey(json, decSEK);
System.out.println(encryptedResult);
return encryptedResult;
}
public static String removeWhitespaces(String json) {
boolean quoted = false;
boolean escaped = false;
String out = "";
for(Character c : json.toCharArray()) {
if(escaped) {
out += c;
escaped = false;
continue;
}
if(c == '"') {
quoted = !quoted;
} else if(c == '\\') {
escaped = true;
}
if(c == ' ' &! quoted) {
continue;
}
out += c;
}
return out;
}
public static String encryptBySymmetricKey(String json, String decryptedSek) {
byte[] sekByte = DatatypeConverter.parseBase64Binary(decryptedSek);
Key aesKey = new SecretKeySpec(sekByte, "AES");
try {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] encryptedjsonbytes = cipher.doFinal(json.getBytes());
String encryptedJson = DatatypeConverter.printBase64Binary(encryptedjsonbytes);
return encryptedJson;
}
catch(Exception e) {
return "Exception "+e;
}
}
}
/
CREATE OR REPLACE FUNCTION encryptData_func(P_json varchar2,p_decSEK VARCHAR2)
RETURN VARCHAR2 AS
LANGUAGE JAVA NAME 'encryptData.encryptJSONCall( java.lang.String,java.lang.String )
return java.lang.String';
The problem is I am not able to find what is causing the error because there is no other explanation give out by the system. It just says "success with compilation error". Where am I going wrong?

I presume CREATE OR REPLACE FUNCTION encryptData_func ... returned that error. If that's so, connect to that Oracle user and run
select *
from user_errors
where name = 'ENCRYPTDATA_FUNC'; --> note uppercase here!
For example:
SQL> create or replace function f_test
2 return number
3 as
4 begin
5 retval = 1;
6 end;
7 /
Warning: Function created with compilation errors.
SQL> select line, position, text
2 from user_errors
3 where name = 'F_TEST';
LINE POSITION TEXT
---------- ---------- ----------------------------------------------------
5 10 PLS-00103: Encountered the symbol "=" when expecting
one of the following: := . ( # % ;
The symbol ":= was inserted before "=" to continue.
Now that you know what's wrong with it, you'll be able to fix it (hopefully).

Related

How to use excel text function "NUMBERVALUE" from Apache POI formula

I am using Apache POI to evaluate a formula cell that has a text function "NUMBERVALUE", then I got an exception
Caused by: org.apache.poi.ss.formula.eval.NotImplementedFunctionException: _xlfn.NUMBERVALUE
Interesting enough, when I try to regist this function WorkbookEvaluator.registerFunction("NUMBERVALUE", new NumberRValue());
it gives me another error:
java.lang.IllegalArgumentException: NUMBERVALUE is not a function from the Excel Analysis Toolpack.
I also tried to use the user-defined functions by implementing FreeRefFunction, it backs to the first error again.
Caused by: org.apache.poi.ss.formula.eval.NotImplementedFunctionException: _xlfn.NUMBERVALUE
How to implement a text function in Apache POI?
WorkbookEvaluator.registerFunction only works for functions apache poi at least knows per name. This are all functions listed through:
java.util.Collection<String> unsupportedFuncs = org.apache.poi.ss.formula.WorkbookEvaluator.getNotSupportedFunctionNames();
System.out.println(unsupportedFuncs);
All the listed functions can be registered using WorkbookEvaluator.registerFunction either as org.apache.poi.hssf.record.formula.functions.Function, when in org.apache.poi.hssf.record.formula.atp.AnalysisToolPak or else as org.apache.poi.hssf.record.formula.functions.FreeRefFunction if not.
But NUMBERVALUE function is not in this list. So this only can be added as a user defined function. See User Defined Functions of apache poi's documentation.
The function must implement org.apache.poi.ss.formula.functions.FreeRefFunction and must be registered in UDF toolpack of the Workbook.
Following complete example shows a basic implementation of _xlfn.NUMBERVALUE. Implementation is done using the description in NUMBERVALUE function. It is a working draft until now and might need to be improved to better fulfill compatibility to Excel's own results.
import java.io.FileInputStream;
import java.util.Locale;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.formula.functions.FreeRefFunction;
import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;
import org.apache.poi.ss.formula.udf.DefaultUDFFinder;
import org.apache.poi.ss.formula.udf.UDFFinder;
import org.apache.poi.util.LocaleUtil;
public class EvaluateNUMBERVALUE {
public static void main( String[] args ) throws Exception {
Workbook workbook = WorkbookFactory.create(new FileInputStream("./ExcelWithNUMBERVALUE.xlsx"));
String[] functionNames = { "_xlfn.NUMBERVALUE" } ;
FreeRefFunction[] functionImpls = { new NumberValue() } ;
UDFFinder udfs = new DefaultUDFFinder( functionNames, functionImpls ) ;
UDFFinder udfToolpack = new AggregatingUDFFinder( udfs ) ;
workbook.addToolPack(udfToolpack);
LocaleUtil.setUserLocale(Locale.US);
FormulaEvaluator formulaEvaluator = workbook.getCreationHelper().createFormulaEvaluator();
DataFormatter dataFormatter = new DataFormatter();
for (Sheet sheet: workbook) {
for (Row row : sheet) {
for (Cell cell : row) {
String cellValue = dataFormatter.formatCellValue(cell, formulaEvaluator);
System.out.println(cellValue);
}
}
}
}
}
Class NumberValue used in above code:
import java.lang.NumberFormatException;
import java.util.Locale;
import java.text.DecimalFormatSymbols;
import org.apache.poi.ss.formula.OperationEvaluationContext;
import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.eval.NumberEval;
import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.formula.eval.EvaluationException;
import org.apache.poi.ss.formula.eval.OperandResolver;
import org.apache.poi.ss.formula.functions.FreeRefFunction;
import org.apache.poi.util.LocaleUtil;
public final class NumberValue implements FreeRefFunction {
#Override
public ValueEval evaluate( ValueEval[] args, OperationEvaluationContext ec ) {
Locale locale = LocaleUtil.getUserLocale();
DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols(locale);
String text = null;
//If the Decimal_separator and Group_separator arguments are not specified, separators from the current locale are used.
String decSep = String.valueOf(decimalFormatSymbols.getDecimalSeparator());
String groupSep = String.valueOf(decimalFormatSymbols.getGroupingSeparator());
Double result = Double.NaN;
ValueEval v1 = null;
ValueEval v2 = null;
ValueEval v3 = null;
try {
if (args.length == 1) {
v1 = OperandResolver.getSingleValue( args[0], ec.getRowIndex(), ec.getColumnIndex());
text = OperandResolver.coerceValueToString(v1);
} else if (args.length == 2) {
v1 = OperandResolver.getSingleValue( args[0], ec.getRowIndex(), ec.getColumnIndex());
v2 = OperandResolver.getSingleValue( args[1], ec.getRowIndex(), ec.getColumnIndex());
text = OperandResolver.coerceValueToString(v1);
decSep = OperandResolver.coerceValueToString(v2).substring(0, 1); //If multiple characters are used in the Decimal_separator or Group_separator arguments, only the first character is used.
} else if (args.length == 3) {
v1 = OperandResolver.getSingleValue( args[0], ec.getRowIndex(), ec.getColumnIndex());
v2 = OperandResolver.getSingleValue( args[1], ec.getRowIndex(), ec.getColumnIndex());
v3 = OperandResolver.getSingleValue( args[2], ec.getRowIndex(), ec.getColumnIndex());
text = OperandResolver.coerceValueToString(v1);
decSep = OperandResolver.coerceValueToString(v2).substring(0, 1); //If multiple characters are used in the Decimal_separator or Group_separator arguments, only the first character is used.
groupSep = OperandResolver.coerceValueToString(v3).substring(0, 1); //If multiple characters are used in the Decimal_separator or Group_separator arguments, only the first character is used.
}
} catch (EvaluationException e) {
e.printStackTrace() ;
return e.getErrorEval();
}
if("".equals(text)) text = "0"; //If an empty string ("") is specified as the Text argument, the result is 0.
text = text.replace(" ", ""); //Empty spaces in the Text argument are ignored, even in the middle of the argument. For example, " 3 000 " is returned as 3000.
String[] parts = text.split("["+decSep+"]");
String sigPart = "";
String decPart = "";
if (parts.length > 2) return ErrorEval.VALUE_INVALID; //If a decimal separator is used more than once in the Text argument, NUMBERVALUE returns the #VALUE! error value.
if (parts.length > 1) {
sigPart = parts[0];
decPart = parts[1];
if (decPart.contains(groupSep)) return ErrorEval.VALUE_INVALID; //If the group separator occurs after the decimal separator in the Text argument, NUMBERVALUE returns the #VALUE! error value.
sigPart = sigPart.replace(groupSep, ""); //If the group separator occurs before the decimal separator in the Text argument , the group separator is ignored.
text = sigPart + "." + decPart;
} else if (parts.length > 0) {
sigPart = parts[0];
sigPart = sigPart.replace(groupSep, ""); //If the group separator occurs before the decimal separator in the Text argument , the group separator is ignored.
text = sigPart;
}
//If the Text argument ends in one or more percent signs (%), they are used in the calculation of the result.
//Multiple percent signs are additive if they are used in the Text argument just as they are if they are used in a formula.
//For example, =NUMBERVALUE("9%%") returns the same result (0.0009) as the formula =9%%.
int countPercent = 0;
while (text.endsWith("%")) {
countPercent++;
text = text.substring(0, text.length()-1);
}
try {
result = Double.valueOf(text);
result = result / Math.pow(100, countPercent); //If the Text argument ends in one or more percent signs (%), they are used in the calculation of the result.
checkValue(result);
} catch (EvaluationException e) {
e.printStackTrace() ;
return e.getErrorEval();
} catch (Exception anyex) {
return ErrorEval.VALUE_INVALID; //If any of the arguments are not valid, NUMBERVALUE returns the #VALUE! error value.
}
return new NumberEval(result);
}
static final void checkValue(double result) throws EvaluationException {
if (Double.isNaN(result) || Double.isInfinite(result)) {
throw new EvaluationException(ErrorEval.NUM_ERROR);
}
}
}
What about the prefix _xlfn.?
Excel uses this to mark functions which were introduced after Excel 2007. The prefix is stored as part of the function name. If the Excel version knows that function because it is later than Excel 2007, then the GUI will not show that prefix and evaluates the function. If the Excel version doesn't know that function, then the GUI will show the prefix to inform the user about that incompatibility. See Issue: An _xlfn. prefix is displayed in front of a formula
Since the prefix is stored, the user defined function must be registered having the function name including the prefix: String[] functionNames = { "_xlfn.NUMBERVALUE" };.
This code is public available. It is free to be reused in any kind of project. Of course it is without any warranty from my side.

How to set in java program that is registered on oracle db- character set for Polish sings

Im running a program in java, registered in oracleDB.
I have a 11.0.2.4 version of oracle DB.
What im trying to achieve is to import files from some folder with polish sings.
So far program is importing data, but it changes the polish sings.
Im not into java very much, but i read that i have to set:
Locale.setDefault(new Locale("Polish", "Poland", "pl_PL"));
Which i already did, and it is not working.
Entire program looks like (from PLSQL) :
CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED SCHEMA."DirListClass" AS
import java.io.*;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class DirListClass
{
public static void getList(String directory)
throws SQLException
{
Locale.setDefault(new Locale("Polish", "Poland", "pl_PL"));
File path = new File( directory );
String[] list = path.list();
String element;
File fileObject;
long length;
String dateStr, type;
Date now = new Date();
SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy H:m:s");
for(int i = 0; i < list.length; i++)
{
element = list[i];
fileObject = new File(directory + File.separatorChar + list[i]);
length = fileObject.length();
if (fileObject.isDirectory()) {
type = "d";
} else if (fileObject.isFile()) {
type = "f";
} else {
type = "?";
}
java.util.Date d = new java.util.Date(fileObject.lastModified());
dateStr = format.format(d);
#sql { INSERT INTO dir_list(filename,length, mod_date, type)
VALUES (:element, :length, to_date(:dateStr,'dd-mm-yyyy hh24:mi:ss'), :type) };
}
}
}
For example:
Instead of import: "ż"
It imports: "Ĺş"
Any ideas?

Java UDF not returning expected result while called inside hive queries

When I call a java UDF inside hive, it returns inconsistent result than the one returned in IDE (sorted in the same order as string provided). The UDF is created to removed duplicates from a string and return the output in same order but in lowercase.
E.g.:
Sony+sony+E2312+xperia+sony => sony+e2312+xperia
while executing inside IDE, it returns the correct value (as above) but when called from Hive console, it returns:
e2312+sony+xperia
UDF code:
package com.javaudf.hive;
import java.util.LinkedHashSet;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;
public class processDeviceModel extends UDF {
private Text result = new Text();
private String delimiters = "[-+\\s*_=|;:]";
public Text evaluate(Text input) {
String dmModel = new String();
if (input == null || input.getLength() == 0)
return null;
else
dmModel = input.toString().trim().toLowerCase();
String[] parts = dmModel.split(delimiters);
Set<String> uniqueparts = new LinkedHashSet<String>();
for(int i = 0; i < parts.length; i++){
uniqueparts.add(parts[i]);
}
String str = StringUtils.join(uniqueparts, '+');
result.set(str);
return result;
}
}

Error with ChatColor.translateAlternateColorCodes

I'm getting a error with ChatColor.translateAlternateColorCodes since I added a custom config to my plugin.
Here is the error:
Caused by: java.lang.NullPointerException
at org.bukkit.ChatColor.translateAlternateColorCodes(ChatColor.java:206)
~[spigot.jar:git-Spigot-1473]
at com.gmail.santiagoelheroe.LoginVip.<init>(LoginVip.java:44) ~[?:?]
The error says the problem is at line 44 inside LoginVip class.
YamlConfiguration configuracion = YamlConfiguration.loadConfiguration(configFile);
String textpermisos = configuracion.getString("Configuration.NoPermissionsMessage");
// Line 44
String permisos = (ChatColor.translateAlternateColorCodes('&', textpermisos));
String prefixtext = configuracion.getString("Configuration.Prefix");
String prefix = (ChatColor.translateAlternateColorCodes('&', prefixtext));
I have to fix this error to finish my first plugin.
Config.class:
import java.io.File;
import java.util.logging.Level;
import org.bukkit.configuration.file.YamlConfiguration;
public class Config {
public static File configFile = new File("Plugins/LoginVip/config.yml");
public static void load() {
YamlConfiguration spawn = YamlConfiguration.loadConfiguration(configFile);
}
public static void saveConfig() {
YamlConfiguration configuracion = new YamlConfiguration();
configuracion.set("Configuration.NoPermissionsMessage", "&cYou don't have permissions to do that");
try {
configuracion.save(configFile);
} catch (Exception e) {
LoginVip.log.log(Level.WARNING, "[LV] Error creating Config.yml file");
}
}
}
onEnable:
#Override
public void onEnable() {
log.log(Level.INFO, "[LV] Plugin loaded");
if(!Config.configFile.exists()) {
Config.saveConfig();
}
if(!Config.spawnFile.exists()) {
Config.saveSpawn();
}
Config.load();
}
textpermisos is null. From the Javadocs of MemoryConfiguration.getString(String):
Gets the requested String by path.
If the String does not exist but a default value has been specified, this will return the default value. If the String does not exist and no default value was specified, this will return null.
This means that your configuration file does not contain the key-value mapping for "Configuration.NoPermissionsMessage". It is null, which is then passed into ChatColor.translateAlternateColorCodes(char, String). Here is its source code, with a comment of mine indicating which line ChatColor.java:206 in your crash log was:
/*
* Translates a string using an alternate color code character into a
* string that uses the internal ChatColor.COLOR_CODE color code
* character. The alternate color code character will only be replaced if
* it is immediately followed by 0-9, A-F, a-f, K-O, k-o, R or r.
*
* #param altColorChar The alternate color code character to replace. Ex: &
* #param textToTranslate Text containing the alternate color code character.
* #return Text containing the ChatColor.COLOR_CODE color code character.
*/
public static String translateAlternateColorCodes(char altColorChar, String textToTranslate) {
char[] b = textToTranslate.toCharArray(); // textToTranslate is null, it causes a NPE to be thrown.
for (int i = 0; i < b.length - 1; i++) {
if (b[i] == altColorChar && "0123456789AaBbCcDdEeFfKkLlMmNnOoRr".indexOf(b[i+1]) > -1) {
b[i] = ChatColor.COLOR_CHAR;
b[i+1] = Character.toLowerCase(b[i+1]);
}
}
return new String(b);
}
To solve this:
Add default mapping so getString() would not return null but instead a default value. Here is one way to do this (consult the documentation for applying as HashMap):
YamlConfiguration configuracion = YamlConfiguration.loadConfiguration(configFile);
String defpermisos = "";
String textpermisos = configuracion.getString("Configuration.NoPermissionsMessage", defpermisos);
String permisos = ChatColor.translateAlternateColorCodes('&', textpermisos);
String defprefix = "";
String textprefix = configuracion.getString("Configuration.Prefix", defprefix);
String prefix = ChatColor.translateAlternateColorCodes('&', textprefix);
Modify your code to only translate color codes after a != null check.
YamlConfiguration configuracion = YamlConfiguration.loadConfiguration(configFile);
String textpermisos = configuracion.getString("Configuration.NoPermissionsMessage");
String permisos = null;
if (textpermisos != null)
permisos = ChatColor.translateAlternateColorCodes('&', textpermisos);
String prefixtext = configuracion.getString("Configuration.Prefix");
String prefix = null;
if (prefixtext != null)
prefix = ChatColor.translateAlternateColorCodes('&', prefixtext);

String pattern wit ha dollar present

I have the below data in a text file.
CS##NEWSLTR$$
RY##GLMALAW$$
VW##NWL$$
VW##GLS$$
IS##4$$
ST##NJ$$
ST##NY$$
SORTX##0050004018001$$
RC##18 No. 4 GLMALAW 1$$
CR##18 No. 4 M & A Law. 1$$
SO3##The M & A Lawyer$$
DL##April, 2014$$
TI##DUSTING OFF APPRAISAL RIGHTS: THE DEVELOPMENT OF A NEW INVESTMENT
STRATEGY$$
here i'm actually trying to fetch these values into a java array with the below code.
package strings;
import com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
/**
*
* #author u0138039
*/
public class Strings {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
Scanner inFile1 = null;
try {
inFile1 = new Scanner(new File("C:\\Users\\u0138039\\Desktop\\Adhil\\WDA.TP.GLASSER.IB.F486806.A.D140605.T.txt")).useDelimiter("$\\\\\\\\\\\\$");
} catch (FileNotFoundException ex) {
Logger.getLogger(Strings.class.getName()).log(Level.SEVERE, null, ex);
}
List<String> tokens = new ArrayList<String>();
while (inFile1.hasNext()) {
tokens.add(inFile1.nextLine());
}
String[] tokenArray = tokens.toArray(new String[0]);
for (int i = 0; i < tokenArray.length; i++) {
String s = tokenArray[i];
System.out.println("a["+i+"]" +tokenArray[i]);
}
}
}
here my concept is that the line ends with a $$ and this is how it should be stored in an array, but when i run the above program i get the below output.
a[0]CS##NEWSLTR$$
a[1]RY##GLMALAW$$
a[2]VW##NWL$$
a[3]VW##GLS$$
a[4]IS##4$$
a[5]ST##NJ$$
a[6]ST##NY$$
a[7]SORTX##0050004018001$$
a[8]RC##18 No. 4 GLMALAW 1$$
a[9]CR##18 No. 4 M & A Law. 1$$
a[10]SO3##The M & A Lawyer$$
a[11]DL##April, 2014$$
a[12]TI##DUSTING OFF APPRAISAL RIGHTS: THE DEVELOPMENT OF A NEW INVESTMENT
a[13] STRATEGY$$
here a[12] and a[13] belong to same array number(index), but here these are divided into 2.
The expected output is as below(since the end $$ of a[12] came in a[13])
a[0]CS##NEWSLTR$$
a[1]RY##GLMALAW$$
a[2]VW##NWL$$
a[3]VW##GLS$$
a[4]IS##4$$
a[5]ST##NJ$$
a[6]ST##NY$$
a[7]SORTX##0050004018001$$
a[8]RC##18 No. 4 GLMALAW 1$$
a[9]CR##18 No. 4 M & A Law. 1$$
a[10]SO3##The M & A Lawyer$$
a[11]DL##April, 2014$$
a[12]TI##DUSTING OFF APPRAISAL RIGHTS: THE DEVELOPMENT OF A NEW INVESTMENT STRATEGY$$
please let me know where am i going wrong and how to fix it.
Thanks
Forget the useDelimiter
List<String> tokens = new ArrayList<String>();
int next = 0;
while (inFile1.hasNext()) {
String line = inFile1.nextLine();
if( next >= tokens.size() ){
tokens.add( line );
} else {
tokens.set( next, tokens.get(next) + line );
}
if( line.endsWith( "$$" ) ) next++;
}
You're issuing a inFile1.nextLine() so naturally, the strings in a[12] and a[13] would be separated.
One approach I can think of is putting the content of the file in a String object, then do a split using "\$\$" .
String s = "Hello$$World$$Sample$$";
for(String sa: s.split("\\$\\$")) {
System.out.println(sa);
}
Output:
Hello
World
Sample
But this will not include the trailing "$$" since you used it in the split. You can easily add that do the end of your string, but this is just one approach.
Hope this helps.
String partialLine = null;
while (inFile1.hasNext()) {
String line = inFile1.nextLine();
if (partialLine != null) {
line = partialLine + line;
partialLine = null;
}
if (line.endsWith("$$") {
tokens.add(line);
} else {
partialLine = line;
}
}
if (partialLine != null) {
// Probably empty line.
}
A bit of buffering: not adding a partial line (missing $$), but keeping it in partialLine.
As you see even several partial lines would work.

Categories