In your module's project.properties, define two properties like this:
extra.src.dir=src2
cp.extra=${extra.src.dir}
where the value of extra.source.dir is the name of the folder directly inside your module which will contain an additional source tree.
In your project.xml, add this just before </data>:
<extra-compilation-unit>
<package-root>${extra.src.dir}</package-root>
</extra-compilation-unit>
In your module's build.xml, you need to override the compile target to add a hook for compiling the code in your extra source tree:
<target name="compile" depends="projectized-common.compile">
<mkdir dir="${build.classes.dir}"/>
<javac srcdir="${extra.src.dir}"
destdir="${build.classes.dir}"
debug="${build.compiler.debug}"
debuglevel="${build.compiler.debuglevel}"
deprecation="${build.compiler.deprecation}"
optimize="${build.compiler.optimize}"
source="${javac.source}"
target="${javac.target}"
includeantruntime="false">
<classpath refid="cp"/>
</javac>
</target>
You should have a look at the harness/README file under your Netbeans installation directory it is a treasure trove of information about issues like this one. The build harness is capable of doing a good deal more than the GUI currently supports (since NetBeans 6.0).
First, make sure you have Mercurial installed on your machine, along with its requirements such as python.
Then, from the command line, you run
hg clone http://hg.netbeans.org/main/to get the full Platform and IDE sources. If you also want the contrib/ and misc/ repositories, it is best to first install the Forest extension for Mercurial, and then run
hg fclone http://hg.netbeans.org/main/ nb_all
To build, simply run Ant in the root of your NetBeans sources. The build will appear in $NB_SRC/nbbuild/netbeans/.
(as of June, 2008)
1. Go to the nightly build download site:
http://bits.netbeans.org/dev/nightly/
2. Click the link for the build you want.
3. You will be shown an index page which makes no mention of how you can get a ZIP file or a source archive, so ignore it.
4. Add "zip/" to the end of the URL in your browser's address bar and hit enter. In other words, the complete URL might look like this:
http://bits.netbeans.org/dev/nightly/2008-06-24_02-01-08/zip/
5. There are about a dozen links on that page. The one you want is begins with "netbeans-trunk-nightly" and ends with "-src.zip" Click that link to download the source archive.
You have to override the
public Action[] getActions( boolean context )method of your node.
If this node is really a DataNode for your own file type, instead see How do I add an action to a file of a given mime-type?.
You must declare your action in your layer.xml file. Like this:
<folder name="Editors">
<folder name="text">
<folder name="x-java">
<folder name="Popup">
<file name="org-mymodule-MyAction.instance"/>
</folder></folder></folder></folder></folder>
Prior to NB 4.2, you could use Editors/text/base/Popup/ to add an action to all editor kits. As of NB 4.2 and later versions, use just Editors/Popup/ instead.
You must declare your action in your layer.xml file. Like this:
<folder name="Loaders">
<folder name="text">
<folder name="html">
<folder name="Actions">
<file name="org-mymodule-MyAction.instance">
</folder></folder></folder></folder>
Substitute "text/html" by "text/x-java" or "text/x-ant+xml" or "text/x-jsp" or "image/png".
However, this still may not work depending on how the data loader for the type works. The DataLoader implementation has to override actionsContext() and return this path if it wants to load the Action instances from there. If the data loader you are interested in does not yet do this, please first file a bug report to make sure this is fixed in a future release; as an inferior workaround, you can use e.g.
DataLoader loader = DataLoaderPool.getDefault().firstProducerOf(SomeDataObject.class);
if (loader != null) {
SystemAction[] actions = loader.getActions();
SystemAction[] newactions = new SystemAction[actions.length + 2];
System.arraycopy(actions, 0, newactions, 0, actions.length);
// More realistically: take care that it is not a duplicate,
// place into a specific position, etc.:
newactions[actions.length] = null;
newactions[actions.length + 1] = SystemAction.get(SomeAction.class);
loader.setActions(newactions);
}
You need to know the implementation class of the foreign data object to implement this workaround. You should avoid doing this unless it is really critical to usability, and replace it with layer-based declarative actions as soon as that is available (you did file that bug report, right?).
You must declare your action in your layer.xml file. Like this:
<folder name="Loaders">
<folder name="folder">
<folder name="any">
<folder name="Actions">
<file name="org-mymodule-MyAction.instance"/>
</folder>
</folder>
</folder>
</folder>
You must declare your action in your layer.xml file. Like this:
<folder name="Menu">
<folder name="File">
<file name="org-mymodule-MyAction.instance"/>
</folder></folder>
Register the panel like this in the layer (here for Java SE projects):
<filesystem>
<folder name="Projects">
<folder name="org-netbeans-modules-java-j2seproject">
<folder name="Customizer">
<file name="Bla.instance">
<attr name="instanceCreate" methodvalue="org.bla.BlaPanelProvider.createBlaPanel"/>
</file>
</folder>
</folder>
</folder>
</filesystem>
Then create it:
public class BlaPanelProvider implements ProjectCustomizer.CompositeCategoryProvider {
public static BlaPanelProvider createBlaPanel() {
return new BlaPanelProvider();
}
@Override
public Category createCategory(Lookup arg0) {
ProjectCustomizer.Category toReturn = null;
toReturn = ProjectCustomizer.Category.create(
"Bla",
"Bla",
null,
null);
return toReturn;
}
@Override
public JComponent createComponent(Category arg0, Lookup arg1) {
return new BlaPanel();
}
}
See also Project Properties GUI for custom project templates
public final class AddActionOperation implements CopyOperationImplementation {
private final AddActionProject project; // suppose this is the
private final FileObject projectDir;
public AddActionOperation(final AddActionProject project) {
this.project = project;
this.projectDir = project.getProjectDirectory();
}
public List/*<FileObject>*/ getMetadataFiles() {
return Collections.EMPTY_LIST;
}
public List/*<FileObject>*/ getDataFiles() {
return Collections.EMPTY_LIST;
}
public void notifyCopying() throws IOException {
System.out.println("Copying");
}
public void notifyCopied(Project project, File file, String string) throws IOException {
System.out.println("Copied");
}
}
public final class AddActionActions implements ActionProvider {
private final AddActionProject project; //suppose this is your project
public AddActionActions(AddActionProject project) {
this.project = project;
}
public String[] getSupportedActions() {
return new String[] {
ActionProvider.COMMAND_COPY
};
}
public boolean isActionEnabled(String command, Lookup context) {
if (command.equals(ActionProvider.COMMAND_COPY)) {
return true;
} else {
throw new IllegalArgumentException(command);
}
}
public void invokeAction(String command, Lookup context) {
if (command.equalsIgnoreCase(ActionProvider.COMMAND_COPY)){
DefaultProjectOperations.performDefaultCopyOperation(project);
}
}
}
lookup = Lookups.fixed(new Object[] {
this,
state,
new AddActionOperation(this),
new AddActionActions(this),
loadProperties(),
new Info(),
new AddActionLogicalView(this)
});
public Action[] getActions(boolean context) {
Action[] nodeActions = new Action[2];
nodeActions[0] = CommonProjectActions.copyProjectAction();
nodeActions[1] = CommonProjectActions.closeProjectAction();
return nodeActions;
}
See also Common Project Actions
Just register an instance of the action in your XML layer under Projects/Actions/. It should be a ContextSensitiveAction, such as a CookieAction.
<filesystem>
<folder name="Projects">
<folder name="Actions">
<file name="projectcontextmenudemo-DemoAction.instance"/>
</folder>
</folder>
</filesystem>
See also How do I add an action to a project popup menu of a specific project type?
You can install an action into the context menu of all projects simply by adding to your layer under the folder Projects/Actions/. Your action should be context-sensitive, meaning it should be a placeholder which implements ContextAwareAction; the context-aware derived action will do the real work. Generally it will look for an instance of Project in the supplied Lookup (context).
If you just override isEnabled on the derived action based on the context, the menu item will always be present, though it will be greyed out in the case of inappropriate projects. If you want to hide the menu item for all but relevant projects, you will need to make the derived action implement Presenter.Popup and the resulting component should also implement DynamicMenuContext.
This is a lot of boilerplate (hopefully a future revision of the APIs will make it simpler and/or the module development support will include a wizard for it), so it is better to show an example you can copy and customize. The following trivial action shows the location of a project so long as its name comes in the first half of the alphabet:
package projectcontextmenudemo;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JMenuItem;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectUtils;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.awt.DynamicMenuContent;
import org.openide.awt.Mnemonics;
import org.openide.filesystems.FileUtil;
import org.openide.util.ContextAwareAction;
import org.openide.util.Lookup;
import org.openide.util.actions.Presenter;
public class DemoAction extends AbstractAction implements ContextAwareAction {
public void actionPerformed(ActionEvent e) {assert false;}
public Action createContextAwareInstance(Lookup context) {
return new ContextAction(context);
}
private boolean enable(Project p) {
assert p != null;
// TODO for which projects action should be enabled
char c = ProjectUtils.getInformation(p).getDisplayName().charAt(0);
return c >= 'A' && c <= 'M';
}
private String labelFor(Project p) {
assert p != null;
// TODO menu item label with optional mnemonics
return "&Info on " + ProjectUtils.getInformation(p).getDisplayName();
}
private void perform(Project p) {
assert p != null;
// TODO what to do when run
String msg = "Project location: " + FileUtil.getFileDisplayName(p.getProjectDirectory());
DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(msg));
}
private final class ContextAction extends AbstractAction implements Presenter.Popup {
private final Project p;
public ContextAction(Lookup context) {
Project _p = (Project) context.lookup(Project.class);
p = (_p != null && enable(_p)) ? _p : null;
}
public void actionPerformed(ActionEvent e) {
perform(p);
}
public JMenuItem getPopupPresenter() {
class Presenter extends JMenuItem implements DynamicMenuContent {
public Presenter() {
super(ContextAction.this);
}
public JComponent[] getMenuPresenters() {
if (p != null) {
Mnemonics.setLocalizedText(this, labelFor(p));
return new JComponent[] {this};
} else {
return new JComponent[0];
}
}
public JComponent[] synchMenuPresenters(JComponent[] items) {
return getMenuPresenters();
}
}
return new Presenter();
}
}
}
and here is how to register it:
<filesystem>
<folder name="Projects">
<folder name="Actions">
<file name="projectcontextmenudemo-DemoAction.instance"/>
</folder>
</folder>
</filesystem>
Applies to: NetBeans 5.0, 5.5, 6.x
You must declare your action in your layer.xml file. Like this:
<folder name="Toolbars">
<folder name="Build">
<file name="org-mymodule-MyAction.instance"/>
</folder></folder>
There are three ways to do this, depending on what exactly you need:
CookieAction is used to write actions that are sensitive to what is in the selected Node(s) Lookup. You can specify one or more classes that must be present in the selected Node's Lookup, and some other semantics about enablement.
Being an older class, under the hood it is using Node.getCookie(), so your action will only be sensitive to things actually returned by that method - in other words, only objects that implement the marker interface Node.Cookie can work here.
NodeAction is somewhat more flexible, but requires more code to implement. It is just passed the array of activated nodes whenever that changes, and can choose to enable or disable itself as it wishes. Essentially this is just an action that automagically tracks the global Node selection.
The following is relatively simple and affords a way to perform whatever enablement logic you like (NodeAction can do that too, but this might be a little more straightforward and your code doesn't have to worry about Nodes at all). To understand how this works, see the section on the global action context:
public class FooAction extends AbstractAction implements LookupListener, ContextAwareAction {
private Lookup context;
Lookup.Result lkpInfo;
public FooAction() {
this(Utilities.actionsGlobalContext());
}
private FooAction(Lookup context) {
putValue (Action.NAME, NbBundle.getMessage(FooAction.class,
"LBL_Action")); //NOI18N
this.context = context;
}
void init() {
assert SwingUtilities.isEventDispatchThread()
: "this shall be called just from AWT thread";
if (lkpInfo != null) {
return;
}
//The thing we want to listen for the presence or absence of
//on the global selection
Lookup.Template tpl = new Lookup.Template(Whatever.class);
lkpInfo = context.lookup (tpl);
lkpInfo.addLookupListener(this);
resultChanged(null);
}
public boolean isEnabled() {
init();
return super.isEnabled();
}
public void actionPerformed(ActionEvent e) {
init();
Collection c = lkpInfo.allItems();
//do something with them here
}
public void resultChanged(LookupEvent ev) {
setEnabled (lkpInfo.allItems().size() != 0);
}
public Action createContextAwareInstance(Lookup context) {
return new FooAction(context);
}
}
You need to add a section to your module's manifest denoting your action as a 'tools action.'
This section should look similar to this:
Name: com/tomwheeler/example/dataimport/wizard/DataImportCookieAction.class OpenIDE-Module-Class: Action
Don't forget to put the extra space above it, since manifest sections need to be separated this way. This method will be deprecated sometime in the future and replaced by an entry in the layer file.
You may have noticed that the examples of adding actions typically look like this:
<folder name="Actions">
<folder name="Build">
<file name="com-foo-SomeAction.instance"/>
</folder>
</folder>
<folder name="Menu">
<folder name="Build">
<file name="pointerToComFooSomeAction.shadow">
<attr name="originalFile" stringvalue="Actions/Build/com-foo-SomeAction.instance"/>
</file>
</folder>
</folder>
And you may have noticed that actions are usually put, not directly into the Menu/ folders, but into subfolders of this Actions/ folder. Then we create .shadow files that act like symbolic links, pointing to the real .instance file . Why all this indirection?
The default UI in NetBeans includes the ability to rearrange, and even delete, whole menus or individual menu items. Many applications built on NetBeans will not want to expose such customizability, but some do. The Actions/ folder is shown in the options dialog (and also used from the key bindings editor); it makes it possible for a user to delete an action from menus and toolbars, but still be able to restore it at a later date - if there were not some UI for this, any deleted action would effectively disappear from the universe, as far as the user was concerned.
No.
Occasionally people want to do something like this, because they want to enhance, for example, the behavior or nodes for Java files or other nodes created by some other modules. However, this is a recipe for disaster - nobody writing a Node subclass does so expecting that random modules will change its internal structures without warning. It is possible to write code that does this sort of thing that looks like it works, but it is sheer luck and it will probably not work for long.
(there, did I say that strongly enough?).
Many modules are designed for extensibility - in fact, Nodes for Java files in the IDE do allow you to add children, actions, etc. They offer an API for doing this sort of thing (for example, adding Actions to Loaders/text/x-java/Actions declaratively); see the beans module for an example of adding sub-nodes to Java classes.
If you want to modify the children/properties/actions/etc. of a Node you did not create, look for an API that lets you do that in a supported way.
If one does not exist, file an enhancement request against the module that actually creates these nodes, asking for an appropriate API for doing what you want (and be clear about exactly what you want or why). If you really want to expedite it, write a patch that creates such an API (look at how other modules do this sort of thing and aim to follow a similar pattern) - it's hard to say no to working code.
Yes. Have your node subclass AbstractNode or whatever else you like.
NB 6 > m9 Specific: Implement ChildFactory. To create the Children object for your Node, pass it to Children.create(). When the child list needs updating, call refresh() on your ChildFactory. Its createKeys method will be called again and you can update the set of key objects as needed; Nodes for objects that remain in the list of keys will simply continue to exist; additions and removals will be handled.
NB 5 And Earlier: Have your Children object subclass Children.Keys . As needed, call setKeys() on the Children.Keys object. Just by passing a larger or smaller (or reordered) list of keys, you will be adding or removing (or reordering) children.
Do not ever try to add/remove children from a node you did not create (unless it has an API that explicitly gives you permission to do that); occasionally people try to add child nodes to nodes for things like Java files. If it works at all it's by accident.
Applies to: NetBeans 4.0, 4.1, 5.0
The most important thing is to know what you are trying to do clearly, so you can find what you need to get started quickly. Here are some basic NetBeans factoids which will either answer some questions or whet your appetite for more information:
A lot of things in NetBeans are based around file recognition and using files to provide Java objects. Even if your application has nothing to do with editing files, this may still be very useful to you, since the same mechanism that recognizes/displays a user's files on disk also recognizes/displays configuration data (which may not even be files in the traditional sense at all), and such "files" can actually be factories for whatever kind of object you want (and that way you get persistence of those files for free).
For example, the FeedReader tutorial simply serializes POJO Feed objects into the configuration filesystem , and its whole UI consists of aiming a standard tree component at a folder full of those objects, and providing a few actions to let the user create more of them. When the application shuts down, it does not need to any special code for persisting them, it is all automatic.
For more information about how that works, see the section on file recognition.
One of the most basic and important things to know about is how modules register objects - this is mainly done through a configuration file inside the module's jar file (if you are using NetBeans 5.0 or greater's module building support, you can usually avoid hand-editing this file). Most things a module does to influence the environment are declarative rather than programmatic - in other words, you put some text in an XML file, or an entry in a jar manifest, or a file in some specific place in the module jar, and your functionality will be discovered when the system starts up - as opposed to writing java code.
Two of the most common needs are opening custom Swing components in the UI, and installing actions in the main menu .
Other basic topics that are worth reading to get the lay of the land are:
There are various tutorials, and the canonical reference to NetBeans APIs is the API javadoc.
This is document currently has draft status
This tutorial will show you how easy is to create an application client on top of the NetBeans Platform. It will be demonstrated on the example of Database Reader.
Install all of the required products (installation guides are available on the product's websites). When it'll be done we have to set up a few things. First of all please start NetBeans IDE 5.5.1 and register GlassFish v2. Right click on the Servers node in the Runtime tab and select Add server (choose Sun Java Application Server).
Now we need to register NetBeans Platform into IDE. It's in fact almost same as to add a new server. In menu Tools -> NetBeans Platform Manager click on a Add Platform button and pass through the wizard (as a new platform select downloaded NetBeans Platform 5.5.1).
It's time to create all projects. We need NetBeans Module Suite project, NetBeans Module (added into your NetBeans Module Suite) project and Enterprise Application project with Application Client and EJB module included. Let's do it. First of all we create NetBeans Module Suite project. Call it dbreader. As used platform choose the new one what you registered before.
Then create NetBeans Module Project. Call it customers. And check that you want to add it into your dbreader suite. All other options leave as default.
Actually we have had NetBeans Modules created and now we have to create Java EE part. So let's create an Enterprise Application with Application Client and EJB module. Call it dbreader-ear. Include Application Client and EJB module. Exclude Web module. Also select Java EE 5 version and choose Sun Java Application Server as development server.
Great ! You have successfully created all required projects. Now you should see something like this in Projects tab.
We need to modify dbreader-ear build.xml script because the dbreader suite jnlp distro has to be packed into dbreader ear. Due to add these lines into dbreader-ear build.xml (instructions for 6.x are in the next part).
<property name="dbreader.home" value="../"/>
<target name="build-dbreader-jnlp">
<java classname="org.apache.tools.ant.Main" dir="${dbreader.home}" failonerror="true" fork="true">
<jvmarg value="-Dant.home=${ant.home}"/>
<arg value="build-jnlp"/>
<classpath path="${java.class.path}"/>
</java>
</target>
<target name="pre-dist" depends="build-dbreader-jnlp">
<!-- dbreader.home must point to DatabaseReader Application home directory -->
<mkdir dir="${build.dir}/lib"/>
<copy todir="${build.dir}/lib">
<fileset dir="${dbreader.home}/build/jnlp/app" includes="*.jar" />
<fileset dir="${dbreader.home}/build/jnlp/branding" includes="*.jar" />
<fileset dir="${dbreader.home}/build/jnlp/netbeans" includes="*.jar" />
</copy>
</target>
You are able to access build.xml file in Files view.
After editing you should see something like this.
<property name="dbreader.home" value="../"/>
<target name="build-dbreader-jnlp">
<java classname="org.apache.tools.ant.Main" dir="${dbreader.home}" failonerror="true" fork="true">
<jvmarg value="-Dant.home=${ant.home}"/>
<arg value="build-jnlp"/>
<classpath path="${java.class.path}"/>
</java>
</target>
<target name="pre-dist" depends="build-dbreader-jnlp">
<!-- dbreader.home must point to DatabaseReader Application home directory -->
<mkdir dir="${build.dir}/lib"/>
<copy todir="${build.dir}/lib">
<flattenmapper/>
<fileset dir="${dbreader.home}/build/jnlp/app" includes="**/*.jar" />
<fileset dir="${dbreader.home}/build/jnlp/branding" includes="**/*.jar" />
<fileset dir="${dbreader.home}/build/jnlp/netbeans" includes="**/*.jar" />
</copy>
</target>
If you're not using Mac then also don't forget to exclude "Apple Application Menu" module (module suite project properties -> libraries -> PlatformX). Also make sure you're including only modules from platformX cluster.
We have dbreader-ear project infrastructure prepared. Now we have to generate entity classes from sample database. Right click on dbreader-ear-ejb project in Project tab and select New -> Entity Classes From Database. In wizard chose as datasource jdbc/sample datasource and select CUSTOMER table.
On the next wizard panel type package for entity classes. Type db. Then Click on create persistence unit. Persistence unit dialog will appear. Click on Create. Now finish the wizard by clicking on the Finish button.
Now we have generated entity classes from jdbc/sample database. Under dbreader-ear-ejb project you can see generated classes.
We need to create stateless session bean with remote interface to communicate with persistence unit. Create one and call it DataBean.
When you have session bean created add business method called getData. You are able to do it by right clicking on the editor pane (in DataBean.java file opened) and select EJB Methods -> Add Business Method. Pass through the wizard and create getData method which returns java.util.List.
Now use entity manager. Once again do a right click on the editor pane and select Persistence -> Use Entity Manager. Entity manager code is generated. Now implement getData method.
public List getData() {
//TODO implement getData
return em.createQuery("SELECT c FROM Customer c").getResultList();
}
After that you should see in editor (in DataBean.java file) something like this.
We prepared EJB module and now we have to implement functionality into dbreader-ear-app-client Application Client module. Open Main.java file in dbreader-ear-app-client project.
Now call your session bean DataBean. Right click on editor pane and select Enterprise Resources -> Call Enterprise Bean. In the dialog select your DataBean and click OK.
Now we need to implement main method and create getCustomers method. Before that add <dbreader_project_home>/build/jnlp/netbeans/boot.jar (or <dbreader_project_home>/build/jnlp/netbeans/org-netbeans-bootstrap/boot.jar in case of NetBeans 6.1) file on classpath. Do it by right clicking on dbreader-ear-app-client project and select Properties. There select Libraries and then click on Add JAR/Folder and in open file dialog select boot.jar file. Don't forget to uncheck the checkbox. We do not want to package this file with dbreader-ear-app-client module. Actually you have to run build-jnlp target on dbreader suite. Before that please perform step Set Up Suite. Then you can right click on dbreader project and select Build JNLP Application.
Implement main method by this code.
public static void main(String[] args) {
try {
String userDir = System.getProperty("user.home") + File.separator + ".dbreader";
org.netbeans.Main.main(new String[] {"--branding", "dbreader", "--userdir", userDir});
} catch (Exception ex) {
ex.printStackTrace();
}
}
Now create getCustomers static method.
public static List getCustomers() {
return dataBean.getData();
}
After doing this you should see something like this in editor pane.
Great ! We have finished development of the dbreader-ear Enterprise Application. Let's go to develop NetBeans Modules.
Now we set up the dbreader NetBeans module suite. We have to set it as standalone application and also we are able to change splash screen. Right click on dbreader project and select Properties. There select Application and then click on the Create Standalone Application.
Also you are able to set up your own splash screen. Do it by same way and under the Application node in project Properties click on Splash Screen.
Now we set up the customers NetBeans Module. We have to add dbreader-ear-ejb.jar, dbreader-ear-app-client.jar and javaee.jar on compile classpath. First of all set sources level of the module to 1.5. Right click on customers project and on the first panel select 1.5 for sources level.
Open project.properties file from project tab.
Add this code into project.properties file. Of course use your own path to dbreader and glassfish.
cp.extra=\ /home/marigan/temp/dbreader/dbreader-ear/dbreader-ear-ejb/dist/dbreader-ear-ejb.jar:\ /home/marigan/temp/dbreader/dbreader-ear/dbreader-ear-app-client/dist/dbreader-ear-app-client.jar:\ /home/marigan/apps/glassfish/lib/javaee.jar
After that you should see something like this in editor pane.
Now we create a new window component which will serve as viewer for database data. Right click on customers project and select New -> Window Component. On the first wizard panel choose editor as Window Position and select Open on Application Start.
On the second panel specify component Class Name Prefix (use Customers) and finish the wizard.
After that you should see this in Project tab.
We have to write application logic for customers top component. Open CustomersTopComponent.java file in design mode and drag and drop a jTable component from palette into it.
Now switch into source view and modify constructor and add initData method.
private CustomersTopComponent() {
initComponents();
setName(NbBundle.getMessage(CustomersTopComponent.class, "CTL_CustomersTopComponent"));
setToolTipText(NbBundle.getMessage(CustomersTopComponent.class, "HINT_CustomersTopComponent"));
// setIcon(Utilities.loadImage(ICON_PATH, true));
initData();
}
private void initData() {
List<Customer> data = Main.getCustomers();
Object[][] rows = new Object[data.size()][3];
int i = 0;
for (Customer c : data) {
rows[i][0] = c.getName();
rows[i][1] = c.getEmail();
rows[i++][2] = c.getPhone();
}
Object[] colums = new Object[] {"Name", "E-mail", "Phone"};
jTable1.setModel(new DefaultTableModel(rows, colums));
}
After that you should see something like this.
Great job !! Everything is done. Now you can run your application. Right click on dbreader-ear project and select Run Project. Wait a minute do build and glassfish to start. Enjoy your application :o)
There of course comes a time when you need to debug your application. Debugging the server side is relatively easy: start Glassfish in Debug mode and simply "Attach" to it ('Attach Debugger...' from the 'Run' menu).
Debugging the client side is a little harder. On NetBeans 6.1, simply right-clicking on the EAR project and select "Debug" doesn't seem to work. It fails with error messages saying that your classes from your other modules are not found on the classpath. Manually referring to them isn't sufficient either, because once you've done that the Ant debug script will complain about not finding classes belonging to the Platform modules you depend on.
The simple solution is to add the following 2 Ant targets to your build.xml :
<target name="Debug platform (Attach-debug)" description="Debug the platform, need to attach the debugger once the JVM is started"
depends="-debug-init-jvm,run"/>
<target name="-debug-init-jvm">
<property name="j2ee.appclient.jvmoptions.param" value="-agentlib:jdwp=transport=dt_socket,server=y,address=9009"/>
</target>
To run the "Debug platform (Attach-debug) target, right-click on the 'build.xml' file in the "Files" (can't see it from the "Project") view and select it from the "Run target" menu item. Once the JVM is started (the console stops scrolling but the program is still running), attach to the JVM just like when debugging the server.
The idea is to call the already-existing "run" target, but specify arguments to be passed to the JVM when its launched. The above arguments will launch the JVM in debug mode, asking it to wait for a connection (default behavior) and the address will be 9009. You could even specify a different port number if you want to run Glassfish in debug mode at the same time (note that the debugger can only attach to one JVM at a time, so you have to detach from the client and then attach to the server).
For more details about the JPDA debugging arguments, see here.
One major difference between developing a platform application and a monolithic Java application is that there's no main method. This sometimes leaves developers wondering where they can insert their own code. This FAQ entry describes some places where this is possible.
Although a bit drastic for most cases, you can replace the main class used to start NetBeans with your own class and then delegate back to NetBeans normal main class. This offers you a hook early in the startup sequence without having to modify the launchers or shell scripts.
Any module may provide a ModuleInstall class. The validate method will be called before your module is even loaded, so it's the first module-level hook typically available in the startup sequence. Note that many services and classes offered by the platform are unlikely to be initialized at this point.
A short time afterwards, the restored() method will be called on each ModuleInstall class. More services and classes will be initialized at this point than with the validate() method, but the GUI will probably not yet be realized. You can post some code to be executed when the UI is fully loaded like this:
@Override
public void restored() {
WindowManager.getDefault().invokeWhenUIReady(
new Runnable() {
public void run() {
// any code here will be run with the UI is available
SomeTopComponent.findInstance().open();
}
});
}
Note that providing a ModuleInstall class will degrade overall startup time somewhat, but as long as you don't overuse ModuleInstall classes and take care to execute any long-running tasks from its methods in a background thread, you should be OK.
Another major class in platform development is the TopComponent class. It offers several method which allow you to hook into its lifecycle.
Here is the sequence of events you can hook into for when a TopComponent is opened:
When you set focus on a TopComponent, the componentActivated method is called. Likewise, the componentDeactivated method is called when focus is moved away from that TopComponent.
Here is the sequence of events you can hook into for when a TopComponent is closed:
Note that you can return false from TopComponent.canClose to prevent the TopComponent from being closed at all.
The ModuleInstall class offers two methods which let you plug into the exit sequence. The closing method is called first and requires that you return a boolean value. If true, then your module agrees to be closed, but if false, then you will prevent the exit sequence from continuing. The close method is called after all ModuleInstall classes return true from the closing method and is the final hook in which modules can participate in the application's lifecycle.
Since NetBeans 6.0 there is a public API to use Autoupdate Services. Autoupdate API provides several services to applications built on NetBeans Platform: it allows users to download and install available updates of installed plugins, search and install new plugins from subscribed Update Centers, browsing and manipulating plugins already installed. To use these services NetBeans Platform supplies a GUI (Plugin Manager in Tools->Plugins menu item) to easy call these services. AutoUpdate API also cares about registration of Update Centers.
It's easy to distribute new and/or updated modules via AutoUpdate, but you might also like to update branding items like the splash screen and version number in the application's title bar to reflect the changes.
To do this, create a new module in your suite. Edit its build.xml to add the following, but replace "app" with the branding token for your application (see your suite's project.properties if you don't know the value to use):
<target name="netbeans-extra" depends="init">
<branding cluster="${cluster}" overrides="${suite.dir}/branding" token="app"/>
</target>
Next, add the following to the modules' nbproject/project.properties file, again replacing "app" with your branding token. You may also need to update the list of files in extra.module.files to include only those JARs which your suite actually brands.
nbm.needs.restart=true
nbm.is.global=true
nbm.target.cluster=app
extra.module.files=\
core/locale/core_app.jar,\
modules/ext/locale/updater_app.jar,\
modules/locale/org-netbeans-core-windows_app.jar,\
modules/locale/org-netbeans-core_app.jar,\
modules/locale/org-netbeans-modules-autoupdate-ui_app.jar,\
modules/locale/org-netbeans-modules-favorites_app.jar,\
modules/locale/org-netbeans-modules-javahelp_app.jar,\
modules/locale/org-netbeans-modules-projectui_app.jar
Finally, run the "nbms" Ant target on your suite and deploy the updates to your AutoUpdate center.
Note that you may encounter problems doing this in NetBeans 6.0.
Thanks to Matteo Di Giovinazzo for sharing how to do this on the dev@openide list.
NetBeans has a learning curve. The goal of this article is to get you over the basic humps quickly. Being proficient does not necessarily mean knowing everything there is to know. It means being able to find what you need to know quickly when you need it. Here are some pointers.
All of the documents linked here are also available from del.icio.us.
It's a good thing to bookmark.
If you want a local copy of it, you can either download it from the update center, or build it from your source checkout
cd $NB_SRC_ROOT ant build-javadoc
Some people claim that they should never need to look at source code - documentation should suffice. That's just silly. The NetBeans codebase is a treasure-trove of examples of how to do things.
Since the end of January 2008 the NetBeans sources are stored in Mercurial repository at hg.netbeans.org.
You can see useful documentation about Mercurial and also about its specifics for NetBeans repository in HgMigrationDocs wiki topic. If you are already familiar with Mercurial you cat go directly to HgHowTos topic.
You will end up with a large number of directories representing top-level NetBeans projects. Most of them will be openable as projects in NetBeans. Most have additional module projects underneath them.
Here's how to build it.
The build of NetBeans will be created in nbbuild/netbeans.
To build platform run
cd $NB_SRC_ROOT ant build-platform
This How-To is based on GlassFish EJB Faq
Important: Application Client must be created as it is described in Java EE Application Client on top of the NetBeans Platform Tutorial otherwise this will not work
protected mypkg.MySessionBeanRemote lookupMySessionBean() {
try {
javax.naming.Context c = new javax.naming.InitialContext();
return (mypkg.MySessionBeanRemote) c.lookup("java:comp/env/ejb/MySessionBean");
} catch(javax.naming.NamingException ne) {
java.util.logging.Logger.getLogger(getClass().getName()).log(java.util.logging.Level.SEVERE,"exception caught" ,ne);
throw new RuntimeException(ne);
}
}
<ejb-ref>
<ejb-ref-name>ejb/MySessionBean</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<remote>mypkg.MySessionBeanRemote</remote>
</ejb-ref>
run.args.extra=-J-da -J-Dorg.omg.CORBA.ORBInitialHost=localhost -J-Dorg.omg.CORBA.ORBInitialPort=3700 \
-cp:a $GLASSFISH_HOME/lib/appserv-rt.jar:$GLASSFISH_HOME/lib/appserv-ext.jar:\
$GLASSFISH_HOME/lib/appserv-deployment-client.jar:$GLASSFISH_HOME/lib/javaee.jar:\
$GLASSFISH_HOME/lib/jmxremote_optional.jar:someejb.jar
to module suite project.properties
// for EJB 3.0 bean
protected mypkg.MyBeanRemote lookupMyBeanRemote30 throws NamingException {
javax.naming.Context ic = new javax.naming.InitialContext();
return (mypkg.MyBeanRemote) ic.lookup("mypkg.MyBeanRemote");
}
// for EJB 2.1 and/or earlier
protected mypkg.MyBeanRemote lookupMyBeanRemote21 throws NamingException {
javax.naming.Context ic = new javax.naming.InitialContext();
Object remote = c.lookup("java:comp/env/ejb/MyBean");
mypkg.MyBeanRemoteHome rv = (mypkg.MyBeanRemoteHome) PortableRemoteObject.narrow(remote, mypkg.MyBeanRemoteHome.class);
return rv.create();
}
Platforms: all
The main menus and toolbars of a NetBeans platform application are configured based on the contents of folders in the system filesystem. There are many benefits of this approach, such as improved performance since the platform can create all the menus and toolbars without having to actually instantiate the actions with which they are associated.
Because the platform builds the menus and toolbars for you, it might seem like you have little control over how those items appear. In practice, you have a great deal of control over the appearance for any action you create. Typically, actions in a NetBeans platform application which will be shown in the main menu or toolbar extend from CallableSystemAction, perhaps indirectly through its CookieAction subclass.
In the code you've written for one of these actions, you can override getMenuPresenter to change the appearance of the menu item associated with your action and/or override getToolbarPresenter to change the appearance of the toolbar component associated with your action.
For example, if you wanted to make the menu item for your action have a blue background and yellow text, you could do something like this:
@Override
public JMenuItem getMenuPresenter() {
JMenuItem item = super.getMenuPresenter();
item.setOpaque(true);
item.setBackground(Color.BLUE);
item.setForeground(Color.YELLOW);
return item;
}
Note that if you are changing the menu item to support a tooltip, the object returned by getMenuPresenter needs a property change listener on the action's SHORT_DESCRIPTION so that its tooltip value is updated correctly upon change.
It's pretty simple to change the font color, style or weight for your node's label. Simply override getHtmlDisplayName and provide some HTML in your return value. (An example can be found in this tutorial.) Here is another example:
public class MovieNode extends AbstractNode {
private Movie movie;
public MovieNode(Movie key) {
super(Children.LEAF, Lookups.fixed(new Object[]{key}));
this.movie = key;
setName(key.getTitle());
setDisplayName(key.getTitle());
getHandle();
setIconBaseWithExtension("org/nb/marilyn/pics/marilyn.gif");
}
@Override
public String getHtmlDisplayName() {
return "<b>" + this.getDisplayName() + "</b>";
}
}
The javadoc for the HtmlRenderer class explains what subset of HTML is supported. You can also change the icon's node by overriding various methods such as getIcon(int type) or getOpenedIcon().
It's also possible, but far more difficult, to control other aspects of the node's appearance; for example, drawing a box around the node or changing its background color. To do this you must create or modify the explorer view in which the node is rendered. Fabrizio Giudici posted code that illustrates this on the dev@openide list.
The splash screen is here:
autoupdate.services/libsrc/org/netbeans/updater/resources/updatersplash.gif
You should be able to brand this as normal, by creating a file in your module at this same path (including the branding token).
This FAQ item should be a companion to the main classpath documentation. Please refer to the original document for additional details.
There are basically three main classloader types used in the platform. Most of the code should be loaded by the Modules classloader. Only in justified special cases the System classloader can be used - e.g. when you need access to resources from all the modules. And finally the resources directly on the classpath from the launch script are loaded by the original classloader (the term boot classloader might be a bit confusing because of the bootstrap classloader used by the JVM).
Most of the classloaders in the NetBeans platform are multi-parented classloaders. This means that the classloader can have zero or more parents. When looking for a resource the classloader uses this algorithm (implemented in class org.netbeans.ProxyClassLoader):
Every module registered by the module system creates one instance of the Module classloader. The classloader loads resources primarily from the module's jar file. This classloader is able to load from more jar files (besides having more classloaders as parents). The original (application) classloader is implicitly one of the parents of each module's classloder - always at the first position.
The implementation class is org.netbeans.StandardModule$OneModuleClassLoader. The ability to use more jar files is implemented in its superclass org.netbeans.JarClassLoader.
The system classloader is regular multiparented classloader that has as its parents all module's classloaders. It is accessible via call to the global lookup (ClassLoader)Lookup.getDefault().lookup(ClassLoader.class); or by using the fact that it is the context classloader on most of the threads: Thread.currentThread().getContextClassLoader();.
This classloader is set up by the launching script. It is usually able to load classes from the original CLASSPATH plus clontents of the folder lib (with usual subfolder lib/ext). If a jar is loaded by this loader and it does not have proper manifest information required by the NetBeans module system the contained resources "bypass" the NetBeans module system. Also such resources are always found first if by accident the same resource is contained here and in a module jar (the module supplied resource is ignored in such case). It is generally discouraced to use this classloader for loading anything in the platform but it is sometimes needed e.g. for the Look And Feel classes (that has to be loaded very early during the startup sequence).
example.gif
Let's have a very simple module a:
Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.modules.a
and module b depending on a:
Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.modules.b OpenIDE-Module-Module-Dependencies: org.netbeans.modules.a Class-Path: ext/library-a-1.0.jar ext/library-b-1.1.jar
Module b also declares a dependency on 2 external libraries - they will be loaded by the very same classloader as b.
Yes. In fact, once you have some code written, request the developer role on contrib.netbeans.org (you need to have an account and be logged in to see the link), so you have write access to CVS there, and go ahead and check it in. You will need to sign a Contributor Agreement to get CVS write access.
For more info on how to start module projects or join existing ones, see the contributing page on netbeans.org .
If you have initially written the module as a standalone module project using the NB 5.0 IDE, beware that the format for module projects inside the netbeans.org CVS tree is slightly different. To convert a standalone module project to a netbeans.org module:
Now you ought to be able to open the new project in the IDE and work with it as usual.
If you had specified an explicit NBM license (=license.file=) before, you might just remove it - netbeans.org modules by default use nbbuild/standard-nbm-license.txt which is appropriate for any SPL module with no external (non-SPL) components.
If you had a module suite project with several module suite component projects, just discard the suite project (netbeans.org modules cannot reside in suites) and copy the component module projects into the netbeans.org CVS tree. You will be deleting <suite-component/> from project.xml and deleting suite.properties rather than platform.properties but the process is otherwise similar.
A future release of the module development support should permit you to simply select Move Project or Copy Project from the GUI and handle these format changes automatically.
Explorer views are generic Swing components, not subclasses of TopComponent , the Swing panel class that is used for top level components (tabs) in the main window. So an explorer view component is added to a TopComponent, using the TopComponent as a Swing container for the view.
A little bit of plumbing is needed to wire up an explorer view to the global Node selection so that code that is sensitive to selection such as context sensitive actions . Basically you want the TopComponent to expose the selection in your Explorer View so that when your view has focus, the global selection that affects everything will be whatever the user selects in your view.
In olden times, there was a convenient class called ExplorerPanel (now in org.openide.compat ) which would do this for you; due to a tragedy of being in the wrong package, it is now deprecated, but the required plumbing is not hard:
public class MyView extends TopComponent implements ExplorerManager.Provider {
private final ExplorerManager manager = new ExplorerManager();
private final JComponent view = new BeanTreeView();
public MyView() {
setLayout (new BorderLayout());
add(view, BorderLayout.CENTER);
manager.setRootContext(someNode);
// Probably boilerplate (depends on what you are doing):
ActionMap map = getActionMap();
map.put(DefaultEditorKit.copyAction, ExplorerUtils.actionCopy(manager));
map.put(DefaultEditorKit.cutAction, ExplorerUtils.actionCut(manager));
map.put(DefaultEditorKit.pasteAction, ExplorerUtils.actionPaste(manager));
// This one is sometimes changed to say "false":
map.put("delete", ExplorerUtils.actionDelete(manager, true));
// Boilerplate:
associateLookup(ExplorerUtils.createLookup(manager, map));
}
// This is optional:
public boolean requestFocusInWindow() {
super.requestFocusInWindow();
// You will need to pick a view to focus:
return view.requestFocusInWindow();
}
// The rest is boilerplate.
public ExplorerManager getExplorerManager() {
return manager;
}
protected void componentActivated() {
ExplorerUtils.activateActions(manager, true);
}
protected void componentDeactivated() {
ExplorerUtils.activateActions(manager, false);
}
}
The primary difference between the above code and ExplorerPanel is that ExplorerPanel automagically persisted paths from the selected nodes to the root, so that it could be deserialized on restart with the same selection it had before shutdown (assuming that selection still existed - this was never terribly robust).
-- Main.timboudreau w/ cut & paste from Jesse Glick - 17 Sep 2005
Integer fontSize = (Integer) UIManager.get("customFontSize");
if (fontSize != null) {
//--fontsize was passed - adjust your fonts accordingly
}
You can also just set your font with UIManager.getFont("controlFont") which will be set according to --fontsize, but sometimes you do need the actual value for using fixed width fonts or computing fixed cell height for an unusual font or similar.
The code in core.swing.plaf processes the --fontsize argument and sets the UIManager key/value pair if it was passed on startup.
An AutoUpdate server (also called an AutoUpdate Center or AUC) it not as complicated as it sounds. It's just a server which contains a set of modules and an XML file that describes them all (the autoupdate XML descriptor).
There are four main steps in setting up your AUC, all of which are quite simple: