I am getting the error "ERROR 2078: Caught error from UDF: com.Hadoop.pig.SplitRec [Caught exception processing input row [1]]". I am sure that the input string is going out of bound, but I am not sure which record(record number) is causing the problem.
I am trying to create log for displaying the record which is causing the problem, but I am not sure about debugging to print/log the error record.
The input looks like:
**PXW01YIN 12000099PGEN PXW01YINFFFFFFFF PXW01YINIMFGUIPY04301Y301 JFK 00888JFK 008880001 PIMF 0000N/ACTRC5/TXN08/SCR301\/SEQ/TEX021\#
PXW01PIN 12000099PGEN PXW01PINFFFFFFFF PXW01PINIMFGUIAV04301P301 PER 03615PER 036150001 PIMF 0000N/ACTRCK/TXN08/SCR301\/SEQ/TEX021\#**
The above lines are two records and I have tested them(using LIMIT), and they are not causing problem. I have more than 150kb of input data.
The script that I am using:
SPLT_REC1 = load '/user/hduser/output/realdata/pig_out6/part-m-00000' as (tran_array:chararray);
register /home/cloudera/workspace/SplitRec.jar;
define SplitRec com.Hadoop.pig.SplitRec();
SPLT_REC2 = foreach SPLT_REC1 generate SplitRec(tran_array);
store SPLT_REC2 into '/user/hduser/output/realdata/pig_out7';
package com.Hadoop.pig;
import java.io.IOException;
import org.apache.pig.EvalFunc;
import org.apache.pig.data.Tuple;
import org.apache.pig.impl.util.WrappedIOException;
#SuppressWarnings("deprecation")
public class SplitRec extends EvalFunc<String> {
public String exec(Tuple input) throws IOException {
if (input == null || input.size() == 0)
return null;
try {
String Str1 = (String)input.get(0);
String delim1 = "PIMF+";
String[] tokens1 = Str1.split(delim1);
String part3 = tokens1[0];
String part4 = tokens1[1];
int len1 = part4.length();
String part5 = part4.substring(8,len1);
String conCat1 = part3+":"+part5;
return conCat1;
}
catch(Exception e) {
throw WrappedIOException.wrap("Caught exception processing input row ", e);
}
}
Related
How do I use the sort function in Saxon when calling it from Java (not from XSLT). For example, for the query (data modeled on the Northwind database) I can get unsorted data using:
/windward-studios/Employees/Employee
But I want to get it sorted like the following (using SQL syntax here):
/windward-studios/Employees/Employee order by City descending, LastName ascending
How do I write the query to accomplish this?
The full code for this is in SaxonQuestions.zip (minus license key) - TestSort.java.
TestSort.java
import net.sf.saxon.s9api.*;
import java.io.*;
import java.util.ArrayList;
public class TestSort {
public static void main(String[] args) throws Exception {
XmlDatasource datasource = new XmlDatasource(
new FileInputStream(new File("files", "SouthWind.xml").getCanonicalPath()),
new FileInputStream(new File("files", "SouthWind.xsd").getCanonicalPath()));
// what I want is sort like: "/windward-studios/Employees/Employee order by City descending, LastName ascending"
XdmValue nodeSet = datasource.getxPathCompiler().evaluate("/windward-studios/Employees/Employee", datasource.getXmlRootNode());
System.out.println(String.format("%10s %10s %10s", "firstName", "lastName", "city"));
for (int i = 0; i < nodeSet.size(); i++) {
XdmItem item = nodeSet.itemAt(i);
String firstName = ((XdmNode)((ArrayList)((XdmNode) item).children("FirstName")).get(0)).getStringValue();
String lastName = ((XdmNode)((ArrayList)((XdmNode) item).children("LastName")).get(0)).getStringValue();
String city = ((XdmNode)((ArrayList)((XdmNode) item).children("City")).get(0)).getStringValue();
System.out.println(String.format("%10s %10s %10s", firstName, lastName, city));
}
}
}
XmlDatasource.java
import com.saxonica.config.EnterpriseConfiguration;
import com.saxonica.ee.s9api.SchemaValidatorImpl;
import net.sf.saxon.Configuration;
import net.sf.saxon.lib.FeatureKeys;
import net.sf.saxon.s9api.*;
import net.sf.saxon.type.SchemaException;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
import javax.xml.transform.Source;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamSource;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
public class XmlDatasource {
/** the DOM all searches are against */
private XdmNode xmlRootNode;
private XPathCompiler xPathCompiler;
/** key == the prefix; value == the uri mapped to that prefix */
private HashMap<String, String> prefixToUriMap = new HashMap<>();
/** key == the uri mapped to that prefix; value == the prefix */
private HashMap<String, String> uriToPrefixMap = new HashMap<>();
public XmlDatasource (InputStream xmlData, InputStream schemaFile) throws SAXException, SchemaException, SaxonApiException, IOException {
boolean haveSchema = schemaFile != null;
// call this before any instantiation of Saxon classes.
Configuration config = createEnterpriseConfiguration();
if (haveSchema) {
Source schemaSource = new StreamSource(schemaFile);
config.addSchemaSource(schemaSource);
}
Processor processor = new Processor(config);
DocumentBuilder doc_builder = processor.newDocumentBuilder();
XMLReader reader = createXMLReader();
InputSource xmlSource = new InputSource(xmlData);
SAXSource saxSource = new SAXSource(reader, xmlSource);
if (haveSchema) {
SchemaValidator validator = new SchemaValidatorImpl(processor);
doc_builder.setSchemaValidator(validator);
}
xmlRootNode = doc_builder.build(saxSource);
xPathCompiler = processor.newXPathCompiler();
if (haveSchema)
xPathCompiler.setSchemaAware(true);
declareNameSpaces();
}
public XdmNode getXmlRootNode() {
return xmlRootNode;
}
public XPathCompiler getxPathCompiler() {
return xPathCompiler;
}
/**
* Create a XMLReader set to disallow XXE aattacks.
* #return a safe XMLReader.
*/
public static XMLReader createXMLReader() throws SAXException {
XMLReader reader = XMLReaderFactory.createXMLReader();
// stop XXE https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#JAXP_DocumentBuilderFactory.2C_SAXParserFactory_and_DOM4J
reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
reader.setFeature("http://xml.org/sax/features/external-general-entities", false);
reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
return reader;
}
private void declareNameSpaces() throws SaxonApiException {
// saxon has some of their functions set up with this.
prefixToUriMap.put("saxon", "http://saxon.sf.net");
uriToPrefixMap.put("http://saxon.sf.net", "saxon");
XdmValue list = xPathCompiler.evaluate("//namespace::*", xmlRootNode);
if (list == null || list.size() == 0)
return;
for (int index=0; index<list.size(); index++) {
XdmNode node = (XdmNode) list.itemAt(index);
String prefix = node.getNodeName() == null ? "" : node.getNodeName().getLocalName();
// xml, xsd, & xsi are XML structure ones, not ones used in the XML
if (prefix.equals("xml") || prefix.equals("xsd") || prefix.equals("xsi"))
continue;
// use default prefix if prefix is empty.
if (prefix == null || prefix.isEmpty())
prefix = "def";
// this returns repeats, so if a repeat, go on to next.
if (prefixToUriMap.containsKey(prefix))
continue;
String uri = node.getStringValue();
if (uri != null && !uri.isEmpty()) {
xPathCompiler.declareNamespace(prefix, uri);
prefixToUriMap.put(prefix, uri);
uriToPrefixMap.put(uri, prefix); }
}
}
public static EnterpriseConfiguration createEnterpriseConfiguration()
{
EnterpriseConfiguration configuration = new EnterpriseConfiguration();
configuration.supplyLicenseKey(new BufferedReader(new java.io.StringReader(deobfuscate(key))));
configuration.setConfigurationProperty(FeatureKeys.SUPPRESS_XPATH_WARNINGS, Boolean.TRUE);
return configuration;
}
}
In terms of using fn:sort in XPath 3.1 with multiple sort keys, the XPath expression is
sort(/windward-studios/Employees/Employee, (), function($emp) { $emp/City, $emp/LastName })
To get descending order (for the complete result) I think you can use fn:reverse:
sort(/windward-studios/Employees/Employee, (), function($emp) { $emp/City, $emp/LastName }) => reverse()
As for setting up an XSLT stylesheet defining functions to be used as functions in XPath 3.1 with Saxon 10, in XSLT you need to give the functions to be exposed the visibility="public" attribute e.g. <xsl:function name="pf:foo" visibility="public">...</xsl:function> in a stylesheet module (e.g. with the xsl:stylesheet root element) or an XSLT 3 package (e.g. with xsl:package, see the XSLT 3 spec for an example).
Then you need to use an XsltCompiler (I think created with same Processor as the other compilers for XPath) to compile the stylesheet into an XsltPackage:
Processor processor = new Processor(true);
XsltCompiler xsltCompiler = processor.newXsltCompiler();
XsltPackage xpathLibrary = xsltCompiler.compilePackage(new StreamSource("my-functions.xsl"));
finally, on the XPathCompiler you need to addXsltFunctionLibrary e.g.
compiler = processor.newXPathCompiler();
compiler.addXsltFunctionLibrary(xpathLibrary);
then your XPath expressions can use any of the public functions. Of course, as any functions need to be in a namespace, the stylesheet needs to declare a prefix for the namespace and the XPathCompiler needs to declare a prefix too for the same namespace, it makes sense probably to use the same prefix:
compiler.declareNamespace("pf", "http://example.com/pf");
Then any XPath expressions you compile with that compiler can call the function pf:foo.
With Saxon EE it might additionally be more efficient to compile and export the stylesheet in a separate step and to load the exported stylesheet. Probably better to ask on the Saxon support site for details.
I am trying to use a switch statement to pass a LinkedHashMap to the correct class constructor for a school project(I just added the rest of the code).
The code reads takes in a txt file and based off the first word in the text sends the hash map.
I can't seem to get a hit on the case report I am testing.
I have even tried just making everything into an if-else-if structure,
and that still didn't work out,
I've tried using a private enum method to no avail.
I am at a loss here.
I am running Java 8.
I am open to any suggestion on optimizing the code as well.
Thanks.
package linkedlist;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
/**
*
* #author admin
*/
public class TextReaderGUI extends javax.swing.JFrame {
JFileChooser fileChooser = new JFileChooser();
String rawText;
String[] text;
public String listType;
private JButton fileChooserButton;
private JLabel statusLabel;
/**
* Creates new form TextReaderGUI
*/
public TextReaderGUI() {
initComponents();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
fileChooserButton = new javax.swing.JButton();
statusLabel = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
fileChooserButton.setText("File Chooser");
fileChooserButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
fileChooserButtonActionPerformed(evt);
}
});
statusLabel.setText("Status: ");
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(layout
.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup().addGap(14, 14, 14).addComponent(fileChooserButton))
.addGroup(layout.createSequentialGroup().addGap(36, 36, 36).addComponent(statusLabel)))
.addContainerGap(264, Short.MAX_VALUE)));
layout.setVerticalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup().addGap(16, 16, 16).addComponent(fileChooserButton)
.addGap(18, 18, 18).addComponent(statusLabel).addContainerGap(221, Short.MAX_VALUE)));
pack();
}// </editor-fold>
private void fileChooserButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
try {
int returnVal = fileChooser.showOpenDialog(this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
rawText = "";
BufferedReader reader = new BufferedReader(new FileReader(file));
StringBuilder stringb = new StringBuilder();
String s;
while ((s = reader.readLine()) != null) {
stringb.append(s);
stringb.append("\n"); // this makes sure that java sees when a new line has started
}
rawText = stringb.toString();
statusLabel.setText("Status: " + file.getName());
}
} catch (IOException e) {
statusLabel.setText("Status" + e);
}
text = rawText.split("\n"); // creating a string array split at each line break
Map<String, String> lines = new LinkedHashMap<>();
for (int i = 0; i < text.length; i++) { // this sets the first word of the line = key
String[] currentLine = text[i].split("\\s+"); // splits the words in the current line to an array
if (i == 0) {
listType = currentLine[0].replaceAll("\n", "").replaceAll("\\s+", ""); // determines listType to pass
}
if (currentLine.length > 1 && i > 0) {
lines.put(currentLine[0] + " " + i, currentLine[1]); // if two words exist on a line
// the first is the key second is the value
} else if (currentLine.length == 1 && i > 0) { // keeps list type out of key values
lines.put(currentLine[0] + " " + i, ""); // " " + i is used to ensure that each command is unique key
}
}
lines.keySet().forEach((name) -> {// Testing to see if document was correctly placed into the HashMap
String key = name;
String value = lines.get(name);
System.out.println(key + " " + value + "\n");
});
System.out.println(listType); // testing to see if list type was correctly stored
switch (listType) {
case "stack":
Stack stack = new Stack((LinkedHashMap) lines);
break;
case "queue":
Queue queue = new Queue((LinkedHashMap) lines);
break;
case "dll":
Dll dll = new Dll((LinkedHashMap) lines);
break;
case "sll":
System.out.println("almost there");
Sll sll = new Sll((LinkedHashMap) lines);
break;
case "cll":
Cll cll = new Cll((LinkedHashMap) lines);
break;
default:
System.out.println("something went wrong here");
break;
}
}
}
Currently, I have a repeat control with computed fields that display column values from a Domino view. In each row in the repeat control I have another computed field that executes a SQL query that returns a value from a SQL table. The SQL query has a parameter that uses one of the column values from the Domino view.
For the SQL computed field I wrote a function that instantiates a JDBC connection and then executes a SQL query for each row in the repeat control. The function looks like this (the pTextNo argument comes from one of the column values in the Domino view):
function getFormulaTextDetailRows(pTextNo){
if(pTextNo == null){return ""};
var con:java.sql.Connection;
try {
con = #JdbcGetConnection("as400");
vStatement = "SELECT TXSQN, TXDTA FROM LIB1.PRTEXTS WHERE RTRIM(TEXT#) = ? ORDER BY TXSQN";
var vParam = [pTextNo];
var resultset:java.sql.ResultSet = #JdbcExecuteQuery(con, vStatement, vParam);
var returnList = "<ul>";
//format the results
while(resultset.next()){
returnList += ("<li>" + resultset.getString("TXDTA").trim() + "</li>");
}
returnList += "</ul>";
}catch(e){
returnList = e.toString()
}finally{
con.close();
}
return returnList;
}
This works fine but I'm sure this isn't the most efficient way of utilising the JDBC connection. Opening and closing a JDBC connection on each row in the repeat control isn't right and I'm concerned that when more than one person opens the XPage the server will run into difficulties with the number of open connections.
After doing some research on the internet it seems I should be using a jdbcConnectionManager on the page.
I added a jdbcConnectionManager to my custom control and also added a jdbcQuery data source to the panel that holds the repeat control. The jdbcConnectionManager looks like this:
<xe:jdbcConnectionManager
id="jdbcConnectionManager1"
connectionName="as400">
</xe:jdbcConnectionManager>
And the jdbcQuery data source looks like this:
<xe:jdbcQuery
var="jdbcProcessText"
scope="request"
calculateCount="true"
sqlQuery="SELECT TXSQN,TXDTA FROM DOMINO.PRTEXTS WHERE RTRIM(TEXT#) = ? AND TXSQN != '0' ORDER BY TXSQN"
connectionManager="jdbcConnectionManager1">
<xe:this.sqlParameters>
<xe:sqlParameter value="#{javascript:requestScope.processTextNo}">
</xe:sqlParameter>
</xe:this.sqlParameters>
</xe:jdbcQuery>
My computed field's value property in the repeat control looks like this:
requestScope.processTextNo = textrow.getDocument().getItemValueString('ProcessTextNo');
var vCount = jdbcProcessText.getCount();
var returnList = "<ul>";
for(i=0; i<vCount; i++){
returnList += ("<li>" + jdbcProcessText.get(i).getColumnValue("TXDTA") + "</li>");
}
returnList += "</ul>";
return returnList;
The problem I've run into is that I don't get any data from the JDBC query at all. Even if I hard code a value I know exists in the SQL table in the sqlParameter property of the jdbcQuery object I still get no results. I suspect I'm not calling the jdbcQuery object correctly but I can't figure out how to do so. Any help will be greatly appreciated.
You may want to reconsider your approach. I would suggest creating a Java bean to get the Domino view data, loop through that and call out to your query for each row in the view. Build up a List (Java List) of a Row class that has all the data you want to show. Then in the repeat call to your Java bean to a method that returns the List of Row classes. In each control in the repeat you would call to the getXXX method in your Row class. This way you can quickly build the List the repeat works on. Doing it your way in the control in the repeat will be very slow.
Howard
Here's the bean I wrote to do the job. At the start it opens a connection to the SQL data source, grabs a viewEntryCollection using a document UNID as a key, and then puts the column values into a HashMap for each row in the viewEntryCollection. One of the values in the HashMap is pulled from a SQL query. My repeat control iterates over the List returned by the bean. In other words the bean returns a List of HashMaps where most of the values in each HashMap comes from Domino view entry data and one value comes from SQL (not sure if that's the correct way of saying it, but it makes sense to me!).
Here's my code:
package com.foo;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Vector;
import javax.faces.context.FacesContext;
import lotus.domino.Database;
import lotus.domino.NotesException;
import lotus.domino.View;
import lotus.domino.ViewEntry;
import lotus.domino.ViewEntryCollection;
import com.ibm.xsp.extlib.relational.util.JdbcUtil;
import com.ibm.xsp.extlib.util.ExtLibUtil;
public class ProcessTextLines implements Serializable {
private static final long serialVersionUID = 1L;
private Connection conn = null;
public int rowCount = 0;
public int getRowCount() {
return rowCount;
}
// public void setRowCount(int rowCount) {
// this.rowCount = rowCount;
// }
public ProcessTextLines() {
/*
* argumentless constructor
*/
try {
// System.out.println("ProcessTextLines.java - initialising connection to as400");
this.conn = this.initialiseConnection();
} catch (SQLException e) {
e.printStackTrace();
}
finally {
if (this.conn != null) {
// System.out.println("ProcessTextLines.java - closing connection to as400");
try {
this.conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
public List<HashMap<String, String>> getRows(final String unid)
throws NotesException {
List<HashMap<String, String>> result = new ArrayList<HashMap<String, String>>();
try {
Database db = ExtLibUtil.getCurrentSession().getCurrentDatabase();
View view = db.getView("luProductMasterFormula");
view.setAutoUpdate(false);
ViewEntryCollection vec = view.getAllEntriesByKey(unid, true);
ViewEntry ve = vec.getFirstEntry();
while (ve != null) {
result.add(processRowVals(ve));
rowCount++;
ViewEntry tmp = vec.getNextEntry(ve);
ve.recycle();
ve = tmp;
}
view.recycle();
db.recycle();
vec.recycle();
} catch (NotesException e) {
e.printStackTrace();
}
return result;
}
/*
* Create a HashMap of names + column values from a ViewEntry
*/
#SuppressWarnings("unchecked")
private HashMap<String, String> processRowVals(ViewEntry ve) {
HashMap<String, String> processRow = new HashMap<String, String>();
try {
Vector cols = ve.getColumnValues();
processRow.put("sequenceNo", cols.get(1).toString());
processRow.put("textNo", cols.get(3).toString());
processRow.put("status", cols.get(6).toString());
processRow.put("textLines", getProcessTextLines(cols.get(3).toString()));
// unid of the entry's doc
processRow.put("unid", ve.getUniversalID());
} catch (NotesException e) {
e.printStackTrace();
}
return processRow;
}
private Connection initialiseConnection() throws SQLException {
Connection connection = null;
try {
connection = JdbcUtil.createNamedConnection(FacesContext
.getCurrentInstance(), "as400");
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
private String getProcessTextLines(String textNo) {
String resultHTML = "<ul class=\"processTextList\">";
try {
// System.out.println("ProcessTextLines.java - setting SQL parameter: " + textNo);
PreparedStatement prep = conn
.prepareStatement("SELECT TXSQN,TXDTA FROM LIB1.PRTEXTS WHERE RTRIM(TEXT#) = ? AND TXSQN != '0' ORDER BY TXSQN");
// supply a value to the PreparedStatement's parameter (the first
// argument is 1 because it is the first parameter)
prep.setString(1, textNo);
ResultSet resultSet = prep.executeQuery();
while (resultSet.next()) {
resultHTML += ("<li>" + resultSet.getString("TXDTA").trim() + "</li>");
}
} catch (SQLException e) {
// e.printStackTrace();
}
resultHTML += "</ul>";
return resultHTML;
}
}
It took me a while because of my lack of Java knowledge but with the pointers #Howard gave plus the few bits and pieces I found on the web I was able to cobble this together.
Opening and closing the SQL connection in the constructor feels counter intuitive to me, but it seems to work.
I need your help to know how to use an alias (stored tuple) on my Pig udf function, i exmplain:
my_file.csv
101,message here
102,message here
103,message here
...
My script PIG:
X = load'mydata.csv' using PigStorage(',') as (myVar:chararray);
A = load'my_file.csv' using PigStorage(',') as (key:chararray,value:chararray);
B = GROUP par ALL;
C = foreach B {
D = ORDER par BY key;
GENERATE BagToTuple(D);
};
the result of the C is something like (101,message here, 102, message here, 103, message here...)
Now what i need is to pass this result in my udf function like :
Z = foreach X generate MYUDF(myVar, C);
the alias "C" is the tuple key,value,key,value...
MYUDF :
import java.io.IOException;
import java.util.regex.Pattern;
import org.apache.pig.EvalFunc;
import org.apache.pig.data.Tuple;
import org.apache.pig.PigWarning;
import org.apache.pig.data.DataType;
import org.apache.pig.impl.util.WrappedIOException;
import org.apache.pig.impl.logicalLayer.schema.Schema;
public class ReDecode extends EvalFunc<String> {
int numParams = -1;
Pattern mPattern = null;
#Override
public Schema outputSchema(Schema input) {
try {
return new Schema(new Schema.FieldSchema(getSchemaName(this
.getClass().getName().toLowerCase(), input),
DataType.CHARARRAY));
} catch (Exception e) {
return null;
}
}
#Override
public String exec(Tuple tuple) throws IOException {
if (numParams==-1) // Not initialized
{
numParams = tuple.size();
if (numParams <= 2) {
String msg = "Decode: Atleast an expression and default string is required.";
throw new IOException(msg);
}
if (tuple.size()%2!=0) {
String msg = "ItssPigUDFs.ReDecode : Some parameters are unmatched.";
throw new IOException(msg);
}
}
if (tuple.get(0)==null)
return null;
try {
for (int count = 1; count < numParams - 1; count += 2)
{
mPattern=Pattern.compile((String)tuple.get(count));
if (mPattern.matcher((String)tuple.get(0)).matches())
{
return (String)tuple.get(count+1);
}
}
} catch (ClassCastException e) {
warn("ItssPigUDFs.ReDecode : Data type error", PigWarning.UDF_WARNING_1);
return null;
} catch (NullPointerException e) {
String msg = "ItssPigUDFs.ReDecode : Encounter null in the input";
throw new IOException(msg);
}
return (String)tuple.get(tuple.size()-1);
}
Thank you for your help
I don't think numParams is needed; the number of params that you get to the UDF will be input.size().
Therefore, if you call MYUDF(myVar, C), then you should be able to get those values in Java like String myVar = (String) input.get(0) and Tuple param2 = input.get(1).
This is all I need, nothing too fancy:
I'm creating an url from files that have been attached in the document, but the document is not opened. I have an xpage where I want to show attachments from specific document. How do I do this?
Thank you in advance.
The easiest way is to use #AttachmentNames (in a view column) to get the names of the files. Then you can construct the url using db.nsf/0/unid/$file/[filename] -- that's classic, won't run in XPiNC. There is a second URL syntax (need to check) that is XPages specific:
http(s)://[yourserver]/[application.nsf]/xsp/.ibmmodres/domino/OpenAttachment/[application.nsf]/[UNID|/$File/[AttachmentName]?Open
Read my full article on it here: http://www.wissel.net/blog/d6plinks/SHWL-86QKNM
(includes SSJS sample)
I found that DominoDocument.AttachmentValueHolder.getHref() works for getting the URL to an attached file or image, if you have a handle to the document. For example:
<xp:image
id="image1">
<xp:this.url>
<![CDATA[#{javascript:document1.getAttachmentList("Body").get(0).getHref()}]]>
</xp:this.url>
</xp:image>
You would need to handle multiple attachments by iterating over the elements returned from getAttachmentList().
If you can use Java (like in XPages) then
import com.ibm.xsp.extlib.util.ExtLibUtil;
import lotus.domino.MIMEEntity;
import lotus.domino.Document;
import lotus.domino.Session;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Vector;
import lotus.domino.Database;
import lotus.domino.DocumentCollection;
import lotus.domino.EmbeddedObject;
import lotus.domino.Item;
import lotus.domino.MIMEHeader;
import lotus.domino.NotesException;
import lotus.domino.RichTextNavigator;
import lotus.domino.RichTextItem;
import lotus.domino.Stream;
import lotus.domino.View;
// ...
private String fileSeparator = File.separator;
private String tempPath = System.getProperty("java.io.tmpdir") + fileSeparator + "Temp" + fileSeparator;
// ...
private void saveFilesFromDoc(Document doc) throws NotesException {
if (doc.hasEmbedded()) {
RichTextItem body = null;
try {
body = (RichTextItem) doc.getFirstItem("body");
} catch (ClassCastException e) {
// save file from MIME (Rich text is converted to MIME)
MIMEEntity mime = doc.getMIMEEntity();
findMimeWithFile(mime);
return;
}
if (body != null) {
// save file from richtext
RichTextNavigator rtnav = body.createNavigator();
if (rtnav.findFirstElement(RichTextItem.RTELEM_TYPE_FILEATTACHMENT)) {
do {
EmbeddedObject att = (EmbeddedObject) rtnav.getElement();
String fileName = att.getSource();
fileName = notConflictFileName(fileName );
String path = tempPath + fileName ;
att.extractFile(path);
} while (rtnav.findNextElement());
}
} else {
// ("BODY is NULL");
}
}
Get file from richtext converted to Mime
private void findMimeWithFile(MIMEEntity mime) {
try {
askMimeForFiles(mime, "");
MIMEEntity child = mime.getFirstChildEntity();
while (child != null) {
askMimeForFiles(child, "child");
// String encoding = "ISO-8859-2";
String c = child.getContentType();
MIMEEntity subChild = child.getFirstChildEntity();
askMimeForFiles(subChild, "subChild");
if ("multipart".equals(c)) {
while (subChild != null) {
askMimeForFiles(subChild, "subChild2");
// String sc = subChild.getContentType();
subChild = subChild.getNextSibling();
}
}
child = child.getNextSibling();
}
} catch (Exception e) {
e.printStackTrace();
}
}
Find out, if MIME Entity is file attachment (or some text)
private void askMimeForFiles(MIMEEntity mime, String prefix) throws NotesException {
if (mime != null) {
boolean thisMimeHasFile = false;
String fileName = "noname";
Vector<MIMEHeader> headers = mime.getHeaderObjects();
for (MIMEHeader header : headers) {
// (prefix + "-header: " + header.getHeaderName() + " :: " + header.getHeaderValAndParams());
if ("Content-Transfer-Encoding".equals(header.getHeaderName())) {
if ("binary".equals(header.getHeaderVal())) {
thisMimeHasFile = true;
}
}
if ("Content-Disposition".equals(header.getHeaderName())) {
String val = header.getHeaderValAndParams();
int odd = val.indexOf("filename=") + "filename=".length();
int doo = val.length();
fileName = val.substring(odd, doo);
this.fileNames.add(fileName);
}
}
if (thisMimeHasFile) {
safeFilesFromMIME(mime, fileName);
}
}
}
If MIME is file attachment, then save it
private void safeFilesFromMIME(MIMEEntity mime, String fileName) throws NotesException {
Session session = ExtLibUtil.getCurrentSession(); // or user variableResolver
Stream stream = session.createStream();
String pathname = tempPath + fileName;
stream.open(pathname, "binary");
mime.getContentAsBytes(stream);
stream.close();
}