Here is the file ClientArea.java (located in folder demoapp) which uses a WebEngine object.
public class ClientArea implements Initializable {
public WebEngine engine;
#Override
public void initialize(URL url, ResourceBundle rb) {
engine = browser.getEngine();
engine.load("about:blank");
}
}
I want to reference it to another file (Undecorator.java), located in folder insidefx.undecorator
How can I make this reference?
I solve similar problems as follows: In the place where you load the fxml file, you can get any element of the controller and provide its reference to the other controller.
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());
fxmlLoader.setLocation(...); // set a URL for the ClientArea.fxml
try {
fxmlLoader.load();
} catch (IOException ex) {
...
}
ClientArea cacontroller = (ClientArea) fxmlLoader.getController();
WebEngine engine = cacontroller.getEngine(); // add a getter method in ClientArea
fxmlLoader.setLocation(...); // set a URL for the Undecorator.fxml
try {
fxmlLoader.load();
} catch (IOException ex) {
...
}
Undecorator ucontroller = (Undecorator) fxmlLoader.getController();
ucontroller.setEngine(engine); // add a setter method in Undecorator
Related
I would like to trap the file upload event in IBM Connections, and take some actions. If a particular criteria gets satisfied, the file should be stored within the system, or else should be rejected with a message.
For this, I was exploring the IBM Connections SPI ( Pre-Event Handler hooks ). I have followed the necessary steps required as per the document to create the jar, deploy and change the configurations, but it seems that my code doesn't get called, when a file is uploaded into Connections.
Not sure, where lies the issue, as I don't get any errors too.
PS: I tried the Post Event handler hook and it worked successfully.
Following are the snippets
public class PreHandlerEvents implements PreEventHandler{
#Override
public void destroy() {
// TODO Auto-generated method stub
}
#Override
public void handleEvent(MutableEvent arg0) throws EventHandlerException {
String content = "This is the content to write into file";
File file = new File("filenamePre.txt");
// if file doesnt exists, then create it
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
FileWriter fw;
try {
fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
bw.write(content);
bw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
events-config.xml
<preHandler enabled="true" name="PreHandlerEvents" class="com.connections.PreHandlerEvents">
<subscriptions>
<subscription source="*" type="*" eventName="*"/>
</subscriptions>
</preHandler>
</preHandlers>
Perhaps rather than a PreEventHandler, you could use an EventHandler instead in your <preHandler .../>?
Example code:
public class CustomEventHandler implements EventHandler {
public void init() throws EventHandlerInitException {}
public void destroy() {}
#Override
public void handleEvent(Event event) throws EventHandlerException {
System.out.println(" +++ Event: " + event.getName());
}
}
I am able to successfully get this to work with the template in my app:
<ui:decorate template="/WEB-INF/templates/mytemplate.xhtml">
I am also able to move template to /META-INF/templates/mytemplate.xhtml of a JAR and get this to work:
<ui:decorate template="/templates/mytemplate.xhtml">
I would actually like to put this file onto filesystem (or database for that matter). How can I achieve this? I found plenty of things related to com.sun.facelets.impl.DefaultResourceResolver, but I don't think that is actually related to override the serving of the template. It is not trying resolve a URL, it is simply trying to get the file somehow on the classpath.
If you're already on JSF 2.2, you can do this by providing a custom ResourceHandler wherein you return the desired view resource in createViewResource().
public class FaceletsResourceHandler extends ResourceHandlerWrapper {
private ResourceHandler wrapped;
public FaceletsResourceHandler(ResourceHandler wrapped) {
this.wrapped = wrapped;
}
#Override
public ViewResource createViewResource(FacesContext context, final String name) {
ViewResource resource = super.createViewResource(context, name);
if (resource == null) {
resource = new ViewResource() {
#Override
public URL getURL() {
try {
return new File("/some/base/path", name).toURI().toURL();
} catch (MalformedURLException e) {
throw new FacesException(e);
}
}
};
}
return resource;
}
#Override
public ResourceHandler getWrapped() {
return wrapped;
}
}
Which is registered in faces-config.xml as below:
<application>
<resource-handler>com.example.FaceletsResourceHandler</resource-handler>
</application>
Or if you're not on JSF 2.2 yet, then use ResourceResolver instead.
public class FaceletsResourceResolver extends ResourceResolver {
private ResourceResolver parent;
public FaceletsResourceResolver(ResourceResolver parent) {
this.parent = parent;
}
#Override
public URL resolveUrl(String path) {
URL url = parent.resolveUrl(path); // Resolves from WAR.
if (url == null) {
try {
url = new File("/some/base/path", path).toURI().toURL();
} catch (MalformedURLException e) {
throw new FacesException(e);
}
}
return url;
}
}
Which is registered in web.xml as below:
<context-param>
<param-name>javax.faces.FACELETS_RESOURCE_RESOLVER</param-name>
<param-value>com.example.FaceletsResourceResolver</param-value>
</context-param>
Regardless of the way, in order to provide the resource from the database, you'd either save/cache them on (temp) disk file system so you can provide the URL just via File, or invent a custom protocol such as db:// and provide a custom URLStreamHandlerFactory and URLStreamHandler implementation to perform the actual job of streaming from the DB. You can find a kickoff example here Registering and using a custom java.net.URL protocol.
Something strange is happening.. Untill 10 minutes ago I had no problem with this code. But now I have a problem updating JUST my VBOX from an external thread.
These are my three classes:
Controller Class:
public class Controller implements Initializable{
#FXML
private VBox slaveVbox;
private ButtonBar newNode = new ButtonBar();
private Circle c= new Circle();
private Button b= new Button();
private Label lname = new Label();
private Label lIMEI = new Label();
private Label lroot = new Label();
#Override
public void initialize(URL location, ResourceBundle resources) {
}
public void create(String imei, String permission,boolean isOnline) throws IOException{
if(!alreadyExist(imei)){
newNode = new ButtonBar();
b = setButtonSpec(imei + "btnHavefun");
c = setCircleSpec(imei + "statuOnline", isOnline);
lname= setLNameSpec(imei + "name");
lIMEI = setLIMEISpec(imei + "Imei");
lroot = setLrootSpec(imei + "root", permission);
newNode.getButtons().addAll(lname,lIMEI,lroot,b,c);
slaveVbox.getChildren().addAll(newNode);
}
}
}
Main Class:
public class MainApp extends Application {
FXMLLoader loader2;
private Stage primaryStage;
private BorderPane rootLayout;
#Override
public void start(Stage primaryStage) throws IOException {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("Thypheon Application");
initRootLayout();
Controller controller2 = initDesign();
Connection con = new Connection(controller2);
Thread t = new Thread(con);
t.start();
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent e) {
Platform.exit();
System.exit(0);
}
});
}
public static void main(String[] args) {
launch(args);
}
public void initRootLayout(){
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("RootLayout.fxml"));
rootLayout = (BorderPane) loader.load();
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public Controller initDesign(){
try {
FXMLLoader loader2= new FXMLLoader(getClass().getResource("Design.fxml"));
AnchorPane anchor = (AnchorPane) loader2.load();
rootLayout.setCenter(anchor);
Controller controller = loader2.getController();
return controller;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
public Stage getPrimaryStage(){
return primaryStage;
}
}
Connection THREAD:
public class Connection implements Runnable {
String result;
Controller controller;
public Connection(Controller controller) {
this.controller = controller;
}
#Override
public void run() {
try {
controller.create("jhgjhgjh", "dssf", true);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Debugging the Application Everything works perfectly untill I reach slaveVbox.getChildren().addAll(newNode); Here comes the exception..
After some attempt to solve the problem I figured out that if I create a ButtonBar and I insert it in the slaveVbox from Main (inside start()) it works fine.. So I ve tied to add controller2.create("FIRST", "FIRST", true); in my start() function like this:
#Override
public void start(Stage primaryStage) throws IOException {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("Thypheon Application");
initRootLayout();
Controller controller2 = initDesign();
controller2.create("FIRST", "FIRST", true);
Connection con = new Connection(controller2);
Thread t = new Thread(con);
t.start();
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent e) {
Platform.exit();
System.exit(0);
}
});
}
But obviously my application shows two ButtonBars... One created in the start() function and one created inside the Connection Thread.. How Can I avoid this?? Why I can't directly add item inside my VBox directly from my Connecton thread??
You cannot update the UI from a thread other than the FX Application Thread. See, for example, the "Threading" section in the Application documentation.
It's not at all clear why you are using a background thread at all here: there doesn't seem to be any long-running code in the method you are calling. In general, if you have long-running code to call, you can call it in a background thread and then update the UI by wrapping UI update in a Platform.runLater(...).
public class Connection implements Runnable {
String result;
Controller controller;
public Connection(Controller controller) {
this.controller = controller;
}
#Override
public void run() {
try {
// execute long-running code here...
// perform any updates to the UI on the FX Application Thread:
Platform.runLater(() -> {
// code that updates UI
});
// more long-running code can go here...
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
After reading introduction_to_fxml I got an impression that an initialize method can be used as spring's afterPropertiesSet or EJB's a #PostConstruct method - that is expected all member variables set when it is invoked. But when I tried I got NPE. The code I tried looks like following.
Main app:
public class MyApp extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("/myapp.fxml"));///MAIN LOAD
Scene scene = new Scene(root, 320, 240);
scene.getStylesheets().add("/myapp.css");
stage.setScene(scene);
stage.setTitle("my app");
stage.show();
}
public static void main(String[] args) { launch(); }
}
myapp.fxml:
...
<VBox fx:id="root" xmlns:fx="http://javafx.com/fxml" >
<ControlA>
<SomeClass>
</SomeClass>
</ControlA>
</VBox>
ControlA.java:
#DefaultProperty("aproperty")
public class ControlA extends StackPane {
private SomeClass aproperty;
public ContentPane(){
try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/controls/ControlA.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
fxmlLoader.load();//ControlA LOAD
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
public void initialize() {
//aproperty is null here, called from ControlA LOAD
}
//aproperty get/set
public void setAproperty(SomeClass p){//it is called from MAIN LOAD
....
}
The component's initialize method is called from its load method and its property is being set from parent's load method which is called later. And it looks understandable, a component's property values can't be constructed until parent fxml is read. But if so, what is best practice to init a component before it will be used and after all the props were initialized?
Best regards, Eugene.
You need to implement the Initializable interface in a controller. I was under the impression that this was for controllers only.
I am trying to build an JSF library control for XPages based on the examples by Keith Strickland.
http://xprentice.gbs.com/A55BAC/keithstric.nsf/default.xsp?documentId=82770C11FA7B9B21852579C100581766
I'm having a little bit trouble in building a FileDownloadControl
Here is the code I've built:
public class Libcontrol extends UIComponentBase implements FacesComponent {
private static final String RENDERER_TYPE = "de.chris.Libcontrol ";
private static final String COMPONENT_FAMILY = "de.chris";
public Libcontrol() {
setRendererType(RENDERER_TYPE);
}
#Override
public String getFamily() {
return COMPONENT_FAMILY;
}
#SuppressWarnings("unchecked")
public void initBeforeContents(FacesContext arg0) throws FacesException {
FacesContext context;
ExpressionEvaluatorImpl evaluator;
context = FacesContext.getCurrentInstance();
evaluator = new ExpressionEvaluatorImpl(context);
XspFileDownload result = new XspFileDownload();
String sourceId = "fileDownload1/#value";
String valueExpr = "#{document1.FileField}";
ValueBinding value = evaluator.createValueBinding(result, valueExpr, sourceId,Object.class);
result.setValueBinding("value", value);
result.setDisplayLastModified(true);
result.setAllowDelete(true);
result.setTitle("filedown");
result.setRows(30);
result.setId("fileDownload1");
this.getChildren().add(result);
}
public void buildContents(FacesContext arg0, FacesComponentBuilder arg1) throws FacesException {
// Do Nothing
}
public void initAfterContents(FacesContext arg0) throws FacesException {
// Do nothing
}
}
Why is the control not completely rendered? When I look to the HTML Code I see a starttag from the control but no Files to download
and yes I've uploaded files to the corresponding NotesDocument.
Here is the renderer I have implmented respectively copied:
public class MainLibcontrolRenderer extends Renderer {
#Override
public void encodeBegin(FacesContext context, UIComponent component) {
try {
super.encodeBegin(context, component);
context = FacesContext.getCurrentInstance();
UIViewRootEx rootEx = (UIViewRootEx) context.getViewRoot();
/*rootEx.setDojoParseOnLoad(true);
rootEx.setDojoTheme(true);*/
ResponseWriter writer = context.getResponseWriter();
writer.startElement("fieldset", component);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void encodeChildren(FacesContext context, UIComponent component) {
try {
super.encodeChildren(context, component);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void encodeEnd(FacesContext context, UIComponent component) {
try {
super.encodeEnd(context, component);
ResponseWriter writer = context.getResponseWriter();
writer.endElement("fieldset");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Stephan is right: the reason the contents do not render is that you're not building them. When implementing FacesComponent, the buildContents method typically should instruct the FacesComponentBuilder to initiate the build process; e.g.:
arg1.buildAll(arg0, this, true);
NOTE: I'm using the argument names from your example; ideally, you should use meaningful argument names like "context" and "builder".
The buildAll method referred to above causes the component tree to properly reflect any changes made to the structure during the init methods. If you skip this step, the subsequent JSF phases (including RENDER_RESPONSE) are unaware of any components you injected.
By the way, Keith also makes a valid point: hardcoding the value binding and other properties - at least, in the example you provided - tends to defeat the purpose of defining a reusable control. I'd echo Keith's advice to take a closer look at what you're trying to accomplish to determine whether a custom component is really the appropriate implementation. And one final caution: use extreme care when programmatically setting the id property on injected components... you could end up with a name collision that cannot be detected during compilation. In other words, Designer can't warn you... it will just break at runtime and the reason for failure will probably not be obvious.