![]() | ![]() | ![]() | ![]() |
||||||||||||||
|
DeveloperGuide ProjectForge® 2011 | ![]() | ||||||||||||||||
![]() |
| ![]() |
|||||||||||||||
|
|||||||||||||||||
| 1 | Eclipse XML settings. |
Preferences
->
Java
->
Build Path
->
Classpath:
M2_REPO=/Users/kai/.m2/repository
mvn eclipse:clean
mvn -DdownloadSources=true eclipse:eclipse
.project
file.
mvn clean install
misc/eclipse/codingstyle.xml
(Window->Preferences->Java->Code Style->Formatter import).
misc/eclipse/codetemplates.xml
(Code Style->Code Templates import).

| Figure 1: | Eclipse XML settings. |
| Name: |
log4j
|
|---|---|
| Description: |
Log4j Logger declaration
|
| Pattern: | private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(${enclosing_type}.class); |
META-INF/context.xml
and set the property
development
to true.
BaseActionBean.isDevelopmentSystem()
. It's actually used for system administration menu for dumping data base to xml.
log4j.properties
and set the debug level for all or the special categories you want to debug.
| 1 2 3 | Archon:~ admin$ createuser -U postgres kai psql -U postgres grant projectforge to kai |
dropdb, createdb
and
psql
directly from the shell (if not, check the AdministrationGuide for configuration of
pg_hba.conf
.
build.xml
and
pom.xml
| 1 2 | <property name="version" value="3.6.1" /> |
ant pre-dist
Version.java, version.xml, version.dtd.
mvn clean install site
target/ProjectForge.war
and
target/site.
Use
mvn -o install site
if not all maven repositories are available or if you are working off line. If any test case was failed the archive is not built. Please fix
the failed test cases before continue.
ant dist
WEB-INF/lib
and
META-INF.
META-INF
is not contained of avoiding the overwriting of settings in
META-INF/context.xml.
Hint
Don't forget to check the user preferences in the admin web. Because if any changes in the user preferences objects are done, all user preferences are lost, because the deserialization of the xml-objects does not work.
In that case, please update and test the methodUserPreferencesMigrator.
src/main/resources/data/init-test-data.xml.gz
. If you want to change it, start ProjectForge with the standard context.xml (hsqldb) with parameter
development=true
with an empty database (maybe you have to delete the hypersonic database files before starting). Login with
initialize/test
as described in the AdministrationGuide and do the modifications as wanted via ProjectForge. Dump the data base via System administration menu
(only visible in development mode). Modify the result xml file:
UserPreferencesDO
and
PFUserDO/timezone
.
init-test-data.xml.gz
and check-in.
InitDatabaseDaoWithTestDataTest
for running successfully (maybe some modifications are needed to pass through).
mvn clover2:instrument clover2:aggregate clover2:clover
File: server.xml |
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <?xml version="1.0" encoding="UTF-8"?> <Server port="8005" shutdown="SHUTDOWN"> <Listener SSLEngine="on" className="org.apache.catalina.core.AprLifecycleListener"/> <Listener className="org.apache.catalina.core.JasperListener"/> <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener"/> <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/> <GlobalNamingResources> <Resource auth="Container" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase"/> </GlobalNamingResources> <Service name="Catalina"> <Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/> <Connector SSLEnabled="true" acceptCount="100" clientAuth="false" disableUploadTimeout="true" enableLookups="true" keystoreFile="${user.home}/.keystore" keystorePass="changeit" maxSpareThreads="75" maxThreads="200" minSpareThreads="5" port="8443" scheme="https" secure="true" sslProtocol="TLS"/> <Engine debug="0" defaultHost="localhost" name="Standalone"> <!--Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase" /--> <Host appBase="webapps" debug="0" name="localhost" unpackWARs="true"> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="common" prefix="localhost_access_log." suffix=".txt"/> <Context docBase="ProjectForge" path="/ProjectForge" reloadable="true" source="org.eclipse.jst.jee.server:ProjectForge"/></Host> </Engine> </Service> </Server> |
| 1 2 | keytool -genkey -keystore tomcat-localhost.keystore -alias tomcat -keyalg RSA -keysize 1024 -keypass changeit -storepass changeit |
ShortDisplayNameCapable
for manipulating the history output of a data object (e. g. TaskDO implements this interface). Implement the interface method in your data
object:
| 1 2 3 4 5 6 7 8 9 10 | public class TaskDO extends DefaultBaseDO implements ShortDisplayNameCapable { ... @Transient public String getShortDisplayName() { return this.getName() + " (#" + this.getId() + ")"; } ... } |
stripWicketTags
to
false
in
context.xml.
In productive (aka deployment) mode and in mobile pages Wicket tags are always stripped.
[prefix].title.add, [prefix].title.edit, [prefix].title.list
WicketApplication
as bookmarks if used by the menu (bookmarking is also useful for shorter bookmars for the users).
IListPageColumnsCreator.
You should also support
returnToPage
and
sortable
(the tables should not be sortable on SearchPage).
File: AddressListPage.java |
|
| 1 2 3 4 5 6 7 | @SuppressWarnings("serial") public List<IColumn<AddressDO>> createColumns(final WebPage returnToPage, final boolean sortable) { ... view.add(new ListSelectActionPanel(view.newChildId(), rowModel, AddressEditPage.class, address.getId(), returnToPage, ... ... columns.add(new CellItemListenerPropertyColumn<AddressDO>(new Model<String>(getString("modified")), getSortable("lastUpdate", sortable), "lastUpdate", ... |
File: AddressDao.java |
|
| 1 2 3 4 5 6 7 8 9 10 11 12 | @Override public List<AddressDO> getList(BaseSearchFilter filter) { final AddressFilter myFilter; if (filter instanceof AddressFilter) { myFilter = (AddressFilter) filter; } else { myFilter = new AddressFilter(filter); } QueryFilter queryFilter = new QueryFilter(myFilter); ... } |
File: AddressFilter.java |
|
| 1 2 3 4 5 6 7 8 9 | public AddressFilter() { } public AddressFilter(BaseSearchFilter filter) { super(filter); ... } |
PFTokenizerImpl.jflex
file you need to rebuild the
PFTokenizerImpl.java:
jflex --nobak src/main/java/org/projectforge/lucene/PFTokenizerImpl.jflex
org.projectforge.registry.DaoRegistry.java
applicationContext-business.xml.
org.projectforge.database.HibernateCoreEntities.java
Example
This code is an example for DO's containing one dependent DO:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public ProjektDao()
{
super(ProjektDO.class);
baseDaoReindexRegistry.registerDependent(KundeDO.class, this);
}
@Override
public void reindexDependents(BaseDO< ? > obj)
{
if (obj instanceof KundeDO) {
@SuppressWarnings("unchecked")
List<ProjektDO> list = getHibernateTemplate().find("from ProjektDO p where p.kunde.id=?", ((KundeDO) obj).getId());
reindex(list, null);
} else {
super.reindexDependents(obj);
}
}
Example
This code is an example for DO's containing more than one dependent DO:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public EmployeeDao()
{
super(EmployeeDO.class);
baseDaoReindexRegistry.registerDependent(PFUserDO.class, this);
baseDaoReindexRegistry.registerDependent(Kost1DO.class, this);
}
@Override
public void reindexDependents(BaseDO< ? > obj)
{
Set<Serializable> alreadyReindexed = new HashSet<Serializable>(); // For avoiding multiple re-indexing.
if (obj instanceof PFUserDO) {
@SuppressWarnings("unchecked")
List<EmployeeDO> list = getHibernateTemplate().find("from EmployeeDO e where e.user.id=?", ((PFUserDO)obj).getId());
reindex(list, alreadyReindexed);
} else if (obj instanceof Kost1DO) {
@SuppressWarnings("unchecked")
List<EmployeeDO> list = getHibernateTemplate().find("from EmployeeDO e where e.kost.id=?", ((Kost1DO)obj).getId());
reindex(list, alreadyReindexed);
} else {
super.reindexDependents(obj);
}
}
ResponseFilter
of Micromata WebUtils. This filter modifies the response header of all in
web.xml
registered files for caching that resource files by the client's browser. This speed-ups ProjectForge!
File: GetImageDimensionsTest.java |
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | ... private static final String PATH = "src/main/webapp/images"; private static final String DIMENSION_FILE = "src/main/resources/" + WebConstants.FILE_IMAGE_DIMENSIONS; private static final String[] IMAGE_SUFFIXES = new String[] { "png", "gif", "jpg"}; @Test public void doit() throws IOException { log.info("Create dimension file of all webapp images."); @SuppressWarnings("unchecked") final Collection<File> files = FileUtils.listFiles(new File(PATH), IMAGE_SUFFIXES, true); final File absolutePathFile = new File(PATH); final String absolutePath = absolutePathFile.getAbsolutePath(); final List<ImageDimension> dimensions = new ArrayList<ImageDimension>(); for (final File file : files) { final Image image = Toolkit.getDefaultToolkit().getImage(file.getAbsolutePath()); final ImageIcon icon = new ImageIcon(image); final String filename = file.getAbsolutePath().substring(absolutePath.length() + 1); final ImageDimension dimension = new ImageDimension(filename, icon.getIconWidth(), icon.getIconHeight()); dimensions.add(dimension); } final FileWriter writer = new FileWriter(DIMENSION_FILE); final XStream xstream = new XStream(); xstream.alias("images", List.class); xstream.alias("image", ImageDimension.class); String xml = xstream.toXML(dimensions); writer.append(xml); IOUtils.closeQuietly(writer); log.info("Creation of dimension file done: " + DIMENSION_FILE); } ... |
File: src/main/resources/imageDimensions.xml |
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | <images> <image> <path>accept.png</path> <width>16</width> <height>16</height> </image> <image> <path>add.png</path> <width>16</width> <height>16</height> </image> ... </images> |
File: Kost1ListPage.java |
|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | private enum Col { STATUS, KOST, DESCRIPTION; } void exportExcel() { ... final ExportWorkbook xls = new ExportWorkbook(); final ContentProvider contentProvider = new XlsContentProvider(xls); xls.setContentProvider(contentProvider); final ExportSheet sheet = xls.addSheet(sheetName); final ExportColumn[] cols = new ExportColumn[] { // new I18nExportColumn(Col.KOST, "fibu.kost1", 10), // Id, i18n key, length new I18nExportColumn(Col.DESCRIPTION, "description", 30), new I18nExportColumn(Col.STATUS, "status", 10)}; sheet.setColumns(cols); // Insert here cell formats if needed. final PropertyMapping mapping = new PropertyMapping(); for (final Kost1DO kost : kost1List) { mapping.add(Col.KOST, kost.getFormattedNumber()); mapping.add(Col.STATUS, kost.getKostentraegerStatus()); mapping.add(Col.DESCRIPTION, kost.getDescription()); sheet.addRow(mapping.getMapping(), 0); } DownloadUtils.setDownloadTarget(xls.getAsByteArray(), filename); } |
| 1 2 3 4 5 6 | final ContentProvider sheetProvider = sheet.getContentProvider(); sheetProvider.putFormat(Col.START_TIME, "yyyy-MM-dd HH:mm"); sheetProvider.putFormat(Col.STOP_TIME, "HH:mm"); sheetProvider.putFormat(Col.DURATION, "[h]:mm"); sheetProvider.putFormat(Col.ID, "0"); sheetProvider.putFormat(Col.BETRAG, "#,##0.00;[Red]-#,##0.00"); |
ProjectForge
If you like to customize the look of a specific Space, you need to build a new GWiki skin.
To get a gernerally idea of GWiki skins, have a look
to
it's documentation at http://labs.micromata.de/gwiki/gwikidocs/howtos/en/CreateStyleandSkins
For ProjectForge needs, an example skin already
exists (gwiki-style-ProjectForge-example), so you can adopt it's project structure and code to build your own skin. You can download the skin
from the ProjectForge svn repository.
standardhead.gspt
and
standardfoot.gspt
Hint
You should include the original ProjectForge-include files, e.g.: <@include file="inc/ProjectForge/headMenu.gspt" @> Actually there is no reason to try another approach.
gwikiplugin.xml
and
pom.xml
you can build the skin with the command
mvn install
ProjectForge -> Spaces
Installed Plugin Index
. Here you can see and manage all installed Plugins.
Wiki Control
Plugin Admin
, if nesaccery
Edit
Settings
tab and click on the
Content
area
MemoDO.java
for seeing how easy it is to define persistent data models.
MemoDao.java
as an example on writing own data access objects. Data access objects are responsible for reading and writing objects from and into the
data-base. Your Dao is available by adding a
pluginContext.xml
in your resource path (see example).
MemoRight.java
for defining which user should have access to your data objects.
MemoPluginUpdates.java
for seeing how easy it is to define your data-base setup and update scripts for any further release of your plugin.
MemoListPage.java, MemoListForm.java and MemoListPage.html
for implementing list pages with filters and full text search engine support.
MemoFormRenderer.java, MemoEditForm.java and MemoEditPage.java
for implementing edit formular pages with insert, update, delete functionality.
MemoPlugin.java
for putting all the stuff together. This class is used to register all your components (data base object, data access object, menu entries
and web pages) as well as the i18n resource bundle (e. g.
MemoI18nResources*.properties
).
config.xml
by adding your plugins (coma separated):
File: config.xml |
|
| 1 2 3 4 5 6 7 8 | <config> ... <pluginMainClasses> org.projectforge.plugins.todo.ToDoPlugin, org.projectforge.plugins.memo.MemoPlugin </pluginMainClasses> ... </config> |
WEB-INF/lib
directory and restart ProjectForge.