Got problem calling method from inherited aggregation - methods

the following are my code. When I execute 'System.out.println(e.getBrowserInfo().getBrowser( )); ' in the last line of code in Webstat class. The result gives me 8 results of "Chrome". This is wrong as it is suppose to give answer as "Chrome" , "IE", "Chrome", "Firefox" ","Chrome","Safari","Chrome" & "IE". I have problem figuring out and please help on how to get the correct result.
---Code---------------------------------
package problem;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.security.Timestamp;
import java.sql.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.chrono.ChronoLocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import d1Assignment.Helper;
public class WebStat {
private static int actionId = 100;
private static String browser;
private static double ConnectionSpeed;
private String[] webinfo;
private static ArrayList<SiteEntry> siteEntrydetails = new ArrayList<SiteEntry>();
private static ArrayList<SiteExit> siteExitdetails = new ArrayList<SiteExit>();
private static ArrayList<PageHop> pageHopdetails = new ArrayList<PageHop>();
public static void main(String[] args) {
WebStat wl = new WebStat();
wl.start();
}
private void start() {
int option = -1;
while (option != 6) {
updateArrayList();
menu();
option = Helper.readInt("Enter choice > ");
if (option == 1) {
// AddNewSiteEntry();
} else if (option == 2) {
// AddNewSiteExit();
}else if (option == 3) {
// AddPageHop();
} else if (option == 4) {
// ViewBrowseActions();
}
else if (option == 6) {
System.out.println("Thank you for using our Service!");
}
}
}
private void menu() {
Helper.line(60, "=");
System.out.println("WELCOME TO MY WEB STAT PORTAL");
Helper.line(60, "=");
System.out.println("1. Add New Site Entry");
System.out.println("2. Add New Site Exit");
System.out.println("3. Add New Page Hop");
System.out.println("4. List Browse Actions by Date Range");
System.out.println("5. Export with Common Statistics Format");
System.out.println("6. Quit");
}
private void updateArrayList() {
siteEntrydetails.clear();
siteExitdetails.clear();
pageHopdetails.clear();
try {
BufferedReader br = new BufferedReader(new FileReader(new File("visitdetails.txt"))); //read file from items.txt
String line = br.readLine();
while(line != null){
browser = "";
ConnectionSpeed = 0.00;
webinfo = line.split(",");
webinfo[0] = webinfo[0].trim();
actionId = Integer.parseInt(webinfo[0]);
webinfo[1] = webinfo[1].trim();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHH:mm");
LocalDateTime dateTime = LocalDateTime.parse(webinfo[1], formatter);
webinfo[6] = webinfo[6].trim();
double d = Double.parseDouble(webinfo[6]);
BrowseInfo browserInfo = new BrowseInfo (webinfo[5],d);
//System.out.println(String.format("%-10d, %-10s, %-10s %-10s %-10s", actionId,dateTime,webinfo[2],browserInfo.getBrowser(),browserInfo.getconnectionSpeed()));
if(webinfo[2].trim().equalsIgnoreCase("entry")) {//save entries with entry in visitdetails.txt into ArrayList
SiteEntry SiteEntryObj = new SiteEntry(actionId,dateTime,webinfo[3],webinfo[4],browserInfo);
siteEntrydetails.add(SiteEntryObj);
browser = "";
ConnectionSpeed = 0.00;
}
if(webinfo[2].trim().equalsIgnoreCase("exit")) {//save entries with exit in visitdetails.txt into ArrayList
SiteExit SiteExitObj = new SiteExit(actionId,dateTime,webinfo[3],webinfo[4],browserInfo);
siteExitdetails.add(SiteExitObj);
browser = "";
ConnectionSpeed = 0.00;
}
if(webinfo[2].trim().equalsIgnoreCase("hop")) {//save entries with hop in visitdetails.txt into ArrayList
PageHop PageHopObj = new PageHop(actionId,dateTime,webinfo[3],webinfo[4],webinfo[5],d);
pageHopdetails.add(PageHopObj);
browser = "";
ConnectionSpeed = 0.00;
}
line = br.readLine();
}
br.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException io) {
io.printStackTrace();
}
for(SiteEntry e: siteEntrydetails) {
System.out.println(e.getBrowserInfo().getBrowser() ); //problem lies here
}
}
}
---Code End--------------------------------------------
--------Output--------------------------------
Chrome
Chrome
Chrome
Chrome
Chrome
Chrome
Chrome
Chrome
--------Output Ends--------------------------------
The below are contents of visitdetails.txt :
101 ,2021040903:07 ,entry ,www.google.com.sg ,home ,Chrome ,55.78
102 ,2021040914:43 ,entry ,www.google.com ,home ,IE ,99.11
103 ,2021040915:26 ,entry ,www.soccernet.com.sg ,home ,Chrome ,34.45
104 ,2021040915:41 ,entry ,www.google.com ,home ,Firefox ,233.00
105 ,2021040915:45 ,exit ,Join us ,www.google.com ,Chrome ,99.11
106 ,2021040917:37 ,exit ,Shop ,www.yahoo.new.com.sg ,Safari ,39.11
107 ,2021040917:43 ,hop ,Join ,Shopping ,Firefox ,88.11
108 ,2021040917:44 ,hop ,Check Out ,Join Us ,IE ,88.19
109 ,2021040918:03 ,entry ,www.google.com.sg ,Home ,Chrome ,88.11
110 ,2021040918:06 ,entry ,www.manutd.com ,home ,Safari ,99.11
111 ,2021041001:07 ,entry ,www.Liverpool.com ,Find ,Chrome ,89.11
112 ,2021041001:07 ,exit ,Shop ,www.mancity.com ,Firefox ,111.99
113 ,2021041013:57 ,entry ,www.google.com ,home ,IE ,71.77
114 ,2021041013:58 ,exit ,Check Out ,www.google.com ,Chrome ,38.19
115 ,2021041014:00 ,hop ,Join Us ,www.maskgowhere.com.sg ,Safari ,55.89

Related

Why are my validations not working from input file?

Full respect for your talents, please ignore how awful my code is. I am no natural and appreciate many of you will find my coding offensive!
I am wanting to create a GUI that 1 -chooses a text file, 2- displays the text to text panel and 3- validates the code ( i have a valid and invalid text file to demonstrate the validations work).
I can get points 1 and 2 to work but none of my validations are erroring when i select an invalid text file.
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.Scanner;
import java.awt.Color;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.Image;
public class MainClass extends JFrame implements ActionListener {
#SuppressWarnings("deprecation")
public static void main(String[] args) {
// Creates new Window Frame with title and sets app to close on clicking cross
JFrame frame = new JFrame("SE2 - Graphics Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Creates JFrame as top level container in hierarchy
Container toplevelContainer = frame.getContentPane();
// Sets Grid Layout
GridLayout layout = new GridLayout(1, 0);
frame.setLayout(layout);
// Splits Panel into 2 halves and sets parameters for text panel and area
String str = "This is the area your imported text will be displayed";
JTextArea TextPanel = new JTextArea(str);
TextPanel.setBackground(Color.YELLOW);
TextPanel.setEditable(false);
TextPanel.setLineWrap(true);
TextPanel.setWrapStyleWord(true);
frame.add(TextPanel);
// calls graphicspanel class
GraphicsPanel grp = new GraphicsPanel();
toplevelContainer.add(grp);
grp.drawLine(Color.BLACK, 100, 100, 200, 100);
grp.drawLine(Color.BLACK, 200, 100, 200, 200);
grp.drawLine(Color.BLACK, 200, 200, 100, 200);
grp.drawLine(Color.BLACK, 100, 200, 100, 100);
// adds graphic panel to frame
frame.pack();
frame.setVisible(true);
// Creates new menubar within frame
JMenuBar menubar = new JMenuBar();
frame.setJMenuBar(menubar);
// Creates new menu with new jmenuitems for File (load,save,exit) with shortcuts
JMenu file = new JMenu("File");
menubar.add(file);
JMenuItem load = new JMenuItem("Load");
load.setIcon(new ImageIcon("Images/Looad.png"));
load.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, KeyEvent.SHIFT_MASK));
file.add(load);
// enables user to browse and choose files to load from filepath
load.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
JFileChooser chooser = new JFileChooser();
chooser.showOpenDialog(null);
File f = chooser.getSelectedFile();
String filename = f.getAbsolutePath();
try
{
// reads file and displays in text panel
FileReader reader = new FileReader(filename);
BufferedReader br = new BufferedReader(reader);
TextPanel.read(br, null);
br.close();
TextPanel.requestFocus();
File Fileobject = new File(filename);
#SuppressWarnings("resource")
Scanner fileReader = new Scanner(Fileobject);
fileReader = new Scanner(Fileobject);
while (fileReader.hasNext())
{
String line = fileReader.nextLine();
String[] splitArray = line.split(" ");
String command = splitArray[0];
if (command.contains ("MOVE"))
{
String MOVE = splitArray[0];
String x1 = splitArray[1];
String y1 = splitArray[2];
if (isNumeric(MOVE))
{
JOptionPane.showMessageDialog(null, "Command cannot be a number");
}
if(isLetter(x1))
{
JOptionPane.showMessageDialog(null, "Must be integer value");
}
if(isLetter(y1))
{
JOptionPane.showMessageDialog(null, "Must be integer value");
}
else if (command.contains("LINE"))
{
String LINE = splitArray[0];
String x2 = splitArray[1];
String y2 = splitArray[2];
if (isNumeric(LINE))
{
JOptionPane.showMessageDialog(null, "Command cannot be a number");
}
if(isLetter(x2))
{
JOptionPane.showMessageDialog(null, "Must be integer value");
}
if(isLetter(y2))
{
JOptionPane.showMessageDialog(null, "Must be integer value");
}
else if(command.contains("CIRCLE"))
{
String CIRCLE =splitArray[0];
int r = Integer.parseInt(splitArray[1]);
if(r < 0)
{
JOptionPane.showMessageDialog(null, "Must be positive number");
}
JOptionPane.showMessageDialog(null, "Must be integer value");
}
else if (command.contains("SOLID_CIRCLE"))
{
String SOLID_CIRCLE = splitArray[0];
try {
int r = Integer.parseInt(splitArray[1]);
if(r<0)
{
JOptionPane.showMessageDialog(null, "Must be positive number");
}
}
catch(NumberFormatException e) {
}
JOptionPane.showMessageDialog(null, "Must be integer value");
}
else if (command.contains("CLEAR"))
{
JOptionPane.showMessageDialog(null, "Commands have been cleared");
}
else if (command.contains("COLOUR"))
{
String Colour = splitArray[0];
int red = Integer.parseInt(splitArray[1]);
int green = Integer.parseInt(splitArray[2]);
int blue = Integer.parseInt(splitArray[3]);
if(red>255)
if(red<0)
if (green>255)
if(green<0)
if(blue>255)
if(blue<0)
{
JOptionPane.showMessageDialog(null, "Colour values must range between 0 and 255");
}
else if (command.contains("TEXT"))
{
String text = null;
if(isNumeric(text))
{
JOptionPane.showMessageDialog(null, "Text must not contain numbers");
}
if (!contains(""))
{
JOptionPane.showMessageDialog(null, "Text must contain double quotation marks");
}
}
}
}
}
}}
//confirm checks are complete for user
catch (Exception e) {
JOptionPane.showMessageDialog(null, "Error Check Complete");
}
}
private boolean contains(String string) {
// TODO Auto-generated method stub
return false;
}
private boolean isLetter(String string) {
// TODO Auto-generated method stub
return false;
}
private boolean isNumeric(String command) {
// TODO Auto-generated method stub
return false;
}
});
// adds image icon and shortcut keys to JMenuItems
JMenuItem save = new JMenuItem("Save");
save.setIcon(new ImageIcon("Images/Saveas.png"));
save.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.SHIFT_MASK));
// Attempt at requirement 4 to add functionality to save JMENUITEM
// save.addActionListener(new ActionListener() {
// public void actionPerformed(ActionEvent ae) {
// JFileChooser fc = new JFileChooser();
// fc.showSaveDialog(this);
// encoder.encode(image);
// byte[] jpgData = bos.toByteArray();
// FileOutputStream fos = new FileOutputStream(fc.getSelectedFile()+".jpeg");
// fos.write(jpgData);
// fos.close();
file.add(save);
JMenuItem exit = new JMenuItem("Exit");
exit.setIcon(new ImageIcon("Images/Exiit.png"));
exit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyEvent.SHIFT_MASK));
file.add(exit);
JMenu help = new JMenu("Help");
menubar.add(help);
JMenuItem about = new JMenuItem("About");
about.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.SHIFT_MASK));
help.add(about);
// Adds Action listener to display dialog box with app description
about.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
JOptionPane.showMessageDialog(about,
"This Application allows you to import, save and display graphical content from a file containing a set of instructions.",
"About", JOptionPane.INFORMATION_MESSAGE);
}
});
frame.setVisible(true);
class exitaction implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
exit.addActionListener(new exitaction());
}
protected static int isEmpty() {
// TODO Auto-generated method stub
return 0;
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}

speak text as Type

Javafx:How can text-to speech is done on animated text; I have applied a typewriter effect on text to make animated text, and now i want that it will speak word by word as typed. P.S. for Text-to-Speech iam using the "FreeTTS is a speech synthesis engine"
here is code snippet of my project
public void AnimattedTextToSpeech()
{
// Text to Speech
Voice voice;
VoiceManager vm=VoiceManager.getInstance();
voice=vm.getVoice("kevin16");
voice.allocate();
// TypeWritter Effect to the text
String str="Welcome! This is the Lesson number one";
final IntegerProperty i = new SimpleIntegerProperty(0);
Timeline timeline = new Timeline();
KeyFrame keyFrame = new KeyFrame(Duration.seconds(0.1), event2 -> {
if (i.get() > str.length()) {
timeline.stop();
} else {
textArea.setText(str.substring(0, i.get()));
i.set(i.get() + 1);
textArea.requestFocus();
textArea.end();
}
});
voice.speak(str);
timeline.getKeyFrames().add(keyFrame);
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
}
But it is speaking every character as it is typing. But i want it speak word by word.
This works but it seems like you need to run the speech on a different thread.
import com.sun.speech.freetts.Voice;
import com.sun.speech.freetts.VoiceManager;
import java.util.concurrent.atomic.AtomicInteger;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;
/**
*
* #author blj0011
*/
public class FreeTTTS extends Application
{
#Override
public void start(Stage primaryStage)
{
TextArea textArea = new TextArea();
// Text to Speech
Voice voice;
VoiceManager vm = VoiceManager.getInstance();
voice = vm.getVoice("kevin16");
voice.allocate();
// TypeWritter Effect to the text
String str = "Welcome! This is the Lesson number one";
final IntegerProperty i = new SimpleIntegerProperty(0);
Timeline timeline = new Timeline();
AtomicInteger startIndex = new AtomicInteger();
AtomicInteger endIndex = new AtomicInteger();
KeyFrame keyFrame = new KeyFrame(Duration.seconds(0.1), event2 -> {
if (i.get() >= str.length()) {
timeline.stop();
startIndex.set(endIndex.get());
endIndex.set(i.get());
String word = str.substring(startIndex.get(), endIndex.get()).trim().replaceAll("[^a-zA-Z ]", "");
System.out.println(word);
voice.speak(word);
}
else {
textArea.appendText(Character.toString(str.charAt(i.get())));
if (str.charAt(i.get()) == ' ') {
if (endIndex.get() == 0) {
endIndex.set(i.get());
String word = str.substring(startIndex.get(), endIndex.get()).trim().replaceAll("[^a-zA-Z ]", "");
System.out.println(word);
voice.speak(word);
}
else {
startIndex.set(endIndex.get());
endIndex.set(i.get());
String word = str.substring(startIndex.get(), endIndex.get()).trim().replaceAll("[^a-zA-Z ]", "");
System.out.println(word);
voice.speak(word);
}
}
i.set(i.get() + 1);
}
});
//voice.speak(str);
StackPane root = new StackPane(textArea);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
timeline.getKeyFrames().add(keyFrame);
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
//voice.speak("Hello World");
}
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
}
I imagine you should divide text into strings, and start TTS the moment you start TypeWritter effect for each string.
Like this:
String str1 = "Welcome! This is the Lesson number one";
String[] temp = str1.split(" ");
final IntegerProperty i = new SimpleIntegerProperty(0);
Timeline timeline = new Timeline();
for (String str : temp) {
KeyFrame keyFrame = new KeyFrame(Duration.seconds(0.1), event2 -> {
if (i.get() > str.length()) {
timeline.stop();
} else {
textArea.setText(str.substring(0, i.get()));
i.set(i.get() + 1);
textArea.requestFocus();
textArea.end();
}
});
voice.speak(str);
timeline.getKeyFrames().add(keyFrame);
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
}

Can't get my String switch statement to hit anything but default

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;
}
}
}

Copying rich text and images from one document to MIME in another document

I have a solution for copying rich text content from one document to MIME in another document. See http://per.lausten.dk/blog/2012/12/xpages-dynamically-updating-rich-text-content-in-a-ckeditor.html. I use this in an application as a way for the user to insert content templates in a new document and have the content appear on-the-fly in the CKEditor.
The problem is that inline images are not included in the copying - only a reference to temporary storage of the images. This means that the images are only visible for the current user in the current session. So not very useful.
How can I include images?
Update October 4, 2013:
I'm still looking for a solution to this.
I finally got it work. It was much more simple and did not even involve MIME. The trick was to modify the image tags in the working HTML to include the base64 encoded image so that the src tag could use this format (here shown with a gif as example):
src="data:image/gif;base64,<base64 encoded image>"
I already had the code necessary to get the HTML from the rich text field (see my blog post already mentioned in my question). So all I needed was to replace the image src tags with the correct src format including the base64 encoded image.
The following code gets the HTML and goes through each of the included images and modifies the src tag:
String html = this.document.getValue(fieldName).toString();
if (null != html) {
final List<FileRowData> fileRowDataList = document.getEmbeddedImagesList(fieldName);
if (null != fileRowDataList) {
final Matcher matcher = imgRegExp.matcher(html);
while (matcher.find()) {
String src = matcher.group();
final String srcToken = "src=\"";
final int x = src.indexOf(srcToken);
final int y = src.indexOf("\"", x + srcToken.length());
final String srcText = src.substring(x + srcToken.length(), y);
for (FileRowData fileRowData : fileRowDataList) {
final String srcImage = fileRowData.getHref();
final String cidImage = ((AttachmentValueHolder) fileRowData).getCID();
final String typeImage = ((AttachmentValueHolder) fileRowData).getType();
final String persistentName = ((AttachmentValueHolder) fileRowData).getPersistentName();
// Add base 64 image inline (src="data:image/gif;base64,<name>")
if (srcText.endsWith(srcImage)) {
final String newSrc = src.replace(srcText, "data:" + typeImage + ";base64," + getBase64(persistentName));
html = html.replace(src, newSrc);
}
}
}
}
}
Here is the getBase64() method that base64 encodes an image:
private String getBase64(final String fileName) {
String returnText = "";
try {
BASE64Encoder base64Enc = new BASE64Encoder();
ByteArrayOutputStream output = new ByteArrayOutputStream();
base64Enc.encode(this.getEmbeddedImageStream(fileName), output);
returnText = output.toString();
} catch (NotesException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return returnText;
}
Some of the code is from the emailBean by Tony McGuckin.
Can you get a handle to the inline image by the DominoDocument.AttachmentValueHolder, see http://public.dhe.ibm.com/software/dw/lotus/Domino-Designer/JavaDocs/XPagesExtAPI/8.5.2/com/ibm/xsp/model/domino/wrapped/DominoDocument.AttachmentValueHolder.html
I blogged about attachments inside notes documents, see http://www.domino-weblog.nl/weblogs/Domino_Blog.nsf/dx/xpages-tip-get-easily-access-to-your-attachments-in-java.htm
Gruesome hack (you need to sort out authentication and server names)
The SSJS (getting the source from a view)
var unid = curRow.getUniversalID();
var body = getComponent("body1");
var magic = new demo.HTMLMagic();
magic.doMagic(database, unid, body);
The Java
package demo;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import net.htmlparser.jericho.Attribute;
import net.htmlparser.jericho.Attributes;
import net.htmlparser.jericho.HTMLElementName;
import net.htmlparser.jericho.OutputDocument;
import net.htmlparser.jericho.Source;
import net.htmlparser.jericho.StartTag;
import lotus.domino.Database;
import lotus.domino.NotesException;
import com.ibm.misc.BASE64Encoder;
import com.ibm.xsp.component.xp.XspInputRichText;
import com.ibm.xsp.http.IMimeMultipart;
import com.ibm.xsp.model.domino.wrapped.DominoRichTextItem;
public class HTMLMagic {
private HttpClient httpClient = null;
private HttpHost httpHost = null;
//TODO: that needs to be resolved smarter
private static final String HOSTNAME = "localhost";
public void doMagic(final Database database, final String unid, final XspInputRichText body) throws NotesException,
ClientProtocolException, IOException {
final String docURL = "http://" + HOSTNAME + "/__" + database.getReplicaID() + ".nsf/0/" + unid + "/Body?OpenField";
final String fixedHTML = this.fixHTML(docURL);
IMimeMultipart result = DominoRichTextItem.convertToMime("-- copied text--<br />" + fixedHTML);
body.setValue(result);
}
private String fixHTML(final String rawHTMLstring) throws ClientProtocolException, IOException {
HttpHost target = this.getHttpHost();
HttpClient client = this.getHttpClient();
HttpGet get = new HttpGet(rawHTMLstring);
HttpResponse response = client.execute(target, get);
InputStream data = response.getEntity().getContent();
Source rawHTML = new Source(data);
OutputDocument outputDocument = new OutputDocument(rawHTML);
StringBuilder sb = new StringBuilder();
String tagName = HTMLElementName.IMG;
String attName = "src";
List<StartTag> links = rawHTML.getAllStartTags(tagName);
for (StartTag onelink : links) {
String href = onelink.getAttributeValue(attName);
if (href != null) {
String replace = this.urltoData(href);
if (replace != null) {
sb.setLength(0);
sb.append("<");
sb.append(tagName);
sb.append(" ");
sb.append(attName);
sb.append("=\"");
sb.append(replace);
sb.append("\"");
Attributes atts = onelink.getAttributes();
if (!atts.isEmpty()) {
for (int i = 0; i < atts.size(); i++) {
Attribute att = atts.get(i);
if (!att.getName().equals(attName)) {
sb.append(" ");
sb.append(att.getName());
sb.append("=\"");
sb.append(att.getValue());
sb.append("\" ");
}
}
}
sb.append(">");
outputDocument.replace(onelink, sb.toString());
}
}
}
return outputDocument.toString();
}
private HttpClient getHttpClient() {
if (this.httpClient == null) {
// general setup
SchemeRegistry supportedSchemes = new SchemeRegistry();
// Register the "http" protocol scheme, it is required
// by the default operator to look up socket factories.
supportedSchemes.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// prepare parameters
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, "UTF-8");
HttpProtocolParams.setUseExpectContinue(params, true);
ClientConnectionManager connMgr = new ThreadSafeClientConnManager(params, supportedSchemes);
this.httpClient = new DefaultHttpClient(connMgr, params);
}
return this.httpClient;
}
private HttpHost getHttpHost() {
if (this.httpHost == null) {
this.httpHost = new HttpHost(HOSTNAME, 80, "http");
}
return this.httpHost;
}
private String urltoData(final String href) throws ClientProtocolException, IOException {
StringBuilder sb = new StringBuilder();
sb.append("data:image/");
sb.append(href.substring(href.lastIndexOf("FieldElemFormat=") + 1));
sb.append(";base64,");
// Here go the Image data
HttpHost target = this.getHttpHost();
HttpClient client = this.getHttpClient();
HttpGet get = new HttpGet(href);
HttpResponse response = client.execute(target, get);
InputStream data = response.getEntity().getContent();
BASE64Encoder encoder = new BASE64Encoder();
OutputStream output = new ByteArrayOutputStream();
encoder.encode(data, output);
sb.append(output.toString());
output.close();
return sb.toString();
}
}
Would be curious if that works for you. The Notes client can't show inline HTML images

Getting attachments from document

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();
}

Resources