Difference between revisions of "ADempiere Best Practices"

From ADempiere
Jump to: navigation, search
This Wiki is read-only for reference purposes to avoid broken links.
(Coding Standards)
(Coding Style)
Line 64: Line 64:
 
= Coding Style =
 
= Coding Style =
 
See [[Image:Libero-formatter.xml|Eclipse Code Formatter Profile]] .
 
See [[Image:Libero-formatter.xml|Eclipse Code Formatter Profile]] .
 +
 +
1. Use DB.getSQLValueEx instead of DB.getSQLValue. It's much better to throw an exception if error. If you use DB.getSQLValue, will not make the difference between "did not find any value" and was an exceptional SQL.
 +
 +
2. Do not use the conversion from Integer to int, Double to double and so on, because from java5 is doing autoboxing.
 +
 +
3. Allways use bracelets {}.
 +
 +
4. Don't use transaction names if is not necessary. Better put null.
  
 
Known issues:
 
Known issues:

Revision as of 11:12, 18 December 2008

Overview

 DISCLAIMER: Target of this document is developers who want to help us fixing and completing
 ADempiere's manufacturing functionality (libero).

Goal

Team

Teo Sarca Arhipac : Libero stabilization

Cristina Ghita Arhipac : Libero stabilization

Trifon D3Soft

Victor Perez e-Evolution

Dominik Zajac BayCIX GmbH

Development Methodology

Sugesstion & Questions Development Methodology

Eclipse Process Framework Project (EPF) Demo

SVN Commit Policy

FIRST DRAFT PLEASE ADD TO AS YOU SEE FIT... The following guidelines describe the best practice when committing code in the Adempiere repository.

  • All commits should be atomic: that is they are the complete code patch that addresses a Bug Report [BR] or Feature Request [FR] in sourceforge. If the contribution is unusually large it may be committed in small parts but then commit should be distinct functional parts.
  • Commit Early in YOUR day: Only commit if you are around to support or even revert in case of a problems.
  • All commits related to BR or FR: with consensus on the functional and technical change how the change will be accomplished (in general).
  • Update before commit: Do an SVN update and ensure all still compiles locally before you commit.
  • Reference the BR/FR in the commit comments: include the full url to the sourceforge BR/FR, but also include a short, but descriptive, comment that does not require the reader to go to the BR/FR in sourceforge unless they require details.
Example:
[ 2354040 ] Implementation Replication Mode, Type, Event
http://sourceforge.net/tracker/index.php?func=detail&aid=2354040&group_id=176962&atid=879335
Enhance replication to allow export and import of documents and then execute the document status action.


  • Syncronise & Build: after committing sync again with the repository and confirm all still builds without errors.
  • On successful commit Update the BR/FR: include the SVN revision reference and set the status & resolution fields as appropriate.


Reference

SVN Best Practices

Suggestions & Questions of Commit Policy

Coding Standards

Sugesstion & Questions Coding Standards

Coding Style

See Eclipse Code Formatter Profile .

1. Use DB.getSQLValueEx instead of DB.getSQLValue. It's much better to throw an exception if error. If you use DB.getSQLValue, will not make the difference between "did not find any value" and was an exceptional SQL.

2. Do not use the conversion from Integer to int, Double to double and so on, because from java5 is doing autoboxing.

3. Allways use bracelets {}.

4. Don't use transaction names if is not necessary. Better put null.

Known issues:

  1. At present eclipse formatter is not supporting fluent interfaces (see eclipse bug #196001)


How to use Adempiere Query class?

How to return only ONE persistent object?

StringBuilder whereClause = new StringBuilder();
		whereClause.append("AD_Client_ID=?");          // #1
		whereClause.append(" AND AD_Org_ID=?");        // #2
		whereClause.append(" AND C_AcctSchema_ID=?");  // #3
		whereClause.append(" AND Account_ID=?");       // #4

 MAccount existingAccount = new Query(ctx, I_C_ValidCombination.Table_Name, whereClause.toString(), null)
 		.setParameters(new Object[]{AD_Client_ID, AD_Org_ID, C_AcctSchema_ID, Account_ID})
 		.first();

If you know that your query should return ONLY one result, then you can assert this, and use firstOnly method instead of first method:

 MAccount existingAccount = new Query(ctx, I_C_ValidCombination.Table_Name, whereClause, null)
 		.setParameters(new Object[]{AD_Client_ID, AD_Org_ID, C_AcctSchema_ID, Account_ID})
 		.'''firstOnly'''();

How to return ARRAY of objects?

public static MAchievement[] getOfMeasure (Properties ctx, int PA_Measure_ID)
{
	final String whereClause = COLUMNNAME_PA_Measure_ID+"=?"; 
	List<MAchievement> list = new Query(ctx, I_PA_Achievement.Table_Name, whereClause, null)
		.setParameters(new Object[]{PA_Measure_ID})
		.setOrderBy(COLUMNNAME_SeqNo+", "+COLUMNNAME_DateDoc)
		.list();
	return list.toArray(new MAchievement[list.size()]);
}

How to return ARRAY of objects and process elements?

public static MAchievement[] getOfMeasure (Properties ctx, int PA_Measure_ID)
{
	String whereClause = COLUMNNAME_PA_Measure_ID+"=? AND "+COLUMNNAME_IsAchieved+"=?"; 
	List<MAchievement> list = new Query(ctx, MAchievement.Table_Name, whereClause, null)
		.setParameters(new Object[]{PA_Measure_ID, true})
		.setOrderBy(COLUMNNAME_SeqNo+", "+COLUMNNAME_DateDoc)
		.list();
	for(MAchievement achievement : list)
	{
	  s_log.fine(" - " + achievement);
	  // do some processing here
	}
	return list.toArray(new MAchievement[list.size()]);
}

How to return one member of an object?

	public static int getWindow_ID(String windowName)
        {
	    int retValue = 0;
 	    String whereClause = COLUMNNAME_Name+"=?";
	    MWindow win = new Query(Env.getCtx(), MWindow.Table_Name, whereClause, null)
		  .setParameters(new Object[]{windowName})
 		  .first();	
 	     return = win.getAD_Window_ID(); 
        }
 

How to pass Timestamp parameter?

Timestamp dateAcct = ...;
String trxName = ...;

StringBuilder whereClause = new StringBuilder();
		whereClause.append("C_CashBook_ID=?");				//	#1
		whereClause.append(" AND TRUNC(StatementDate)=?");		//	#2
		whereClause.append(" AND Processed=?");				//	#3
		
MCash retValue = new Query(ctx, MCash.Table_Name, whereClause.toString(), trxName)
	.setParameters(new Object[]{C_CashBook_ID, TimeUtil.getDay(dateAcct), true})
	.first()
;

How to use Query class with complex where clause: EXISTS?

StringBuilder whereClause = new StringBuilder();
	whereClause.append("C_Cash.AD_Org_ID=?");			// #1
	whereClause.append(" AND TRUNC(C_Cash.StatementDate)=?");	// #2
	whereClause.append(" AND C_Cash.Processed='N'");		
	whereClause.append(" AND EXISTS (SELECT * FROM C_CashBook cb");
	whereClause.append(" WHERE C_Cash.C_CashBook_ID=cb.C_CashBook_ID AND cb.AD_Org_ID=C_Cash.AD_Org_ID");
	whereClause.append(" AND cb.C_Currency_ID=?)");			// #3
MCash retValue = new Query(ctx, MCash.Table_Name, whereClause, trxName)
	.setParameters(new Object[]{AD_Org_ID,TimeUtil.getDay(dateAcct),C_Currency_ID})
	.first()
;

References

EE Best Practices

Precise Java

Sugesstion & Questions Coding Style

When on a single thread class, StringBuilder should be used for String concatenation. If the class is not single threaded, then, StringBuffer should be used for String concatenation.

Testing Policy

  • Submit your changes to local testing or a peer review before committing unless you are approved by 1st level committer
  • Publish your test results

Test Units

  • ... (test unit contributions needed)


Documentation Policy

  • Document your sourcecode changes in this wiki under appropriate topic.
  • Solicit help from others if you cannot document well. Or just start a stub and allow others to expand it.
  • Intentionally hiding information may get your contribution categorised as proprietary and not fit for admission into trunk.