Monday, September 5, 2011

Top "MUST HAVE" habits of a great software developer to ensure creating a world class quality coding product

Below are some of top "MUST HAVE" habits of a great software developer to ensure creating a world class quality coding product ::

1) Self discipline. So much bad code is due to laziness by developers who don't do what they know should be done.

2) Assume the code written doesn't work unless it is proven to work.
Don't assume that things will never fail. In other words, assume things will fail and provide for clean handling of it. Error messages reporting errors are required. Crash on error is unacceptable.

3) Hangs are unacceptable. All code should be bounded in time and an error must be reported if it runs over.
Do your own testing. It doesn't matter if you have a separate test group. Do your own testing anyway.

4) Never assume that a user will never do something with the code. Assume that a user will do anything and everything possible. Provide clean handling and error messages for everything not allowed.

5) The developer should insure that the code compiles with zero warning messages.
Always use a source code repository, even in a “team” of one person. The repository should be backed-up properly.

6) Never check-in code to a main repository that doesn't compile cleanly. Check-in to a branch repository for checkpointing or backups is ok.

7) Teamwork - few things are small enough or require so few skills that one person can do them well.

8) Discipline - do things right *all the time* if you want top quality.
Ability, Experience - one needs to learn on the job; they say you tend to get expert only after 10,000 hours at a skill.

9) Breadth - you need to understand other people's vision not just your own, or what you make will suit you and nobody else.

10) Luck - whether your idea or somebody else's, you need a good idea AND the luck to get it to market at the right time.

11) A good team - what you can't put toward the effort yourself, the rest of the team needs to supply.

12) Knowledge - especially of design patterns (and have to remember that they are giving direction, not the right solution) and frameworks

13) TESTS - they are prooving that the code works. He/she must write tests automatically without thinking: do I have to?

14) Digging in problems - it laverages the knowledge and gives him/her deep understanding of technology

15) Curiosity - to be up to date with other concepts

16) Document everything (tomorrow you do not remember what is in your head today).

17) Pay attention to what your customer - requirements analyst says and work with him/her. Do not assume that you know their needs better. It is their needs. Do not assume that your work is just writting code, it is also discussing your plans and results with your clients.

18) Always plan your next task and sketch a model of what you will build.

19) Always check on the internet for things you need. It is very rare that you were the first to need them. For every hint you get try to give something back to the community. If there is an open source project near your needs use it and expand it. It is better to focus on your new task than reinventing the wheel.

20) Always take some time to check if you need to use a new tool or programming language. A good programmer is not tied to a specific language, however he can be very good or specialized at one or more.

21)Proper error/exception handling... make sure that app should not crash

22)He/She should be 'Continuous Learner' and upgrade their skills in respective domain time to time..

23)Last,but not least, Think 'out of box'. Smart people can easily entertain new ideas, thoughts, and ways of doing things.

Cheers!!!

Ujjwal Soni

-- In Dreams And In Love There Are No Impossibilities

Thursday, August 11, 2011

Alfresco Webdav SSO Configuration

Hi,

I finally configured Oracle SSO with Alfresco Webdav. Below is how i achieved that.

I need to run Alfresco on tomcat deployed on other virtual machine, i created a class file as under

-- STEP 1



package my.custom;

import java.io.IOException; 
import java.util.List;
import java.util.Locale;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.transaction.UserTransaction;

import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.web.app.Application;
import org.alfresco.web.app.servlet.AbstractAuthenticationFilter;
import org.alfresco.web.app.servlet.AuthenticationHelper;
import org.alfresco.web.bean.LoginBean;
import org.alfresco.web.bean.repository.User;
import org.alfresco.web.config.LanguagesConfigElement;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.config.ConfigService;
import org.springframework.extensions.surf.util.I18NUtil;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.alfresco.web.bean.repository.Repository;



public class WebDavAuthentication extends AbstractAuthenticationFilter implements Filter {
private static final String LOCALE = "locale";
public static final String MESSAGE_BUNDLE = "alfresco.messages.webclient";
private static Log logger = LogFactory.getLog(OSSOAuthenticationFilter.class);
private ServletContext context;
private String loginPage;
private AuthenticationComponent authComponent;
private AuthenticationService authService;
private TransactionService transactionService;
private PersonService personService;
private NodeService nodeService;
private List m_languages;

public OSSOAuthenticationFilter() {
super();
}

public void destroy() {
// Nothing to do
}

/**
* Run the filter
*
* @param sreq
* ServletRequest
* @param sresp
* ServletResponse
* @param chain
* FilterChain
* @exception IOException
* @exception ServletException
*/
public void doFilter(ServletRequest sreq, ServletResponse sresp, FilterChain chain) throws IOException, ServletException {
// Get the HTTP request/response/session
HttpServletRequest req = (HttpServletRequest) sreq;
HttpServletResponse resp = (HttpServletResponse) sresp;
HttpSession httpSess = req.getSession(true);

String userName = null;
//Get headers setted by the oracle sigle sign one server
java.util.Enumeration reqMap = req.getHeaders("Osso-User-Dn");

if (reqMap == null) {
logger.error("No user logged in");
} else {
while (reqMap.hasMoreElements()){
//Get from the full dn the username
userName = ((String)reqMap.nextElement()).split(",")[0].trim().toString().split("=")[1].trim().toString();
//String tmp = value.split(",")[0].trim().toString();
//userName = tmp.split("=")[1].trim().toString();
}
}

if (logger.isDebugEnabled()) {
logger.debug("OSSO : User = " + userName);
}

// See if there is a user in the session and test if it matches
User user = (User) httpSess.getAttribute(AuthenticationHelper.AUTHENTICATION_USER);

if (user != null) {
try {
// Debug
if (logger.isDebugEnabled())
logger.debug("OSSO : User " + user.getUserName() + " validate ticket");

if (user.getUserName().equals(userName)) {
UserTransaction tx1 = transactionService.getUserTransaction();
try {
tx1.begin();
authComponent.setCurrentUser(user.getUserName());
tx1.commit();
}catch(Exception ex){
logger.error("Failed due to transaction " + ex);
try {
tx1.rollback();
} catch (Exception ex2) {
logger.error("Failed to rollback transaction", ex2);
}

}
I18NUtil.setLocale(Application.getLanguage(httpSess));
chain.doFilter(sreq, sresp);
return;
} else {
// No match
//setAuthenticatedUser(req, httpSess, userName);
//below url is th oracle portal url
resp.sendRedirect("http://hostname:7778/alfresco");
return;
}
} catch (AuthenticationException ex) {
if (logger.isErrorEnabled())
logger.error("Failed to validate user " + user.getUserName(), ex);
}
}

setAuthenticatedUser(req, httpSess, userName);

// Redirect the login page as it is never seen as we always login by name
if (req.getRequestURI().endsWith(getLoginPage()) == true)
{
if (logger.isDebugEnabled())
logger.debug("Login page requested, chaining ...");

resp.sendRedirect(req.getContextPath() + "/faces/jsp/browse/browse.jsp");
return;
}
else
{
//below url is th oracle portal url
resp.sendRedirect("http://hostname:7778/alfresco");
//chain.doFilter(sreq, sresp);
return;
}

}

/**
* Set the authenticated user.
*
* It does not check that the user exists at the moment.
*
* @param req
* @param httpSess
* @param userName
*/
private void setAuthenticatedUser(HttpServletRequest req, HttpSession httpSess, String userName) {
if (userName != null){
UserTransaction tx1 = transactionService.getUserTransaction();
// Set the authentication
try {
tx1.begin();
authComponent.setCurrentUser(userName);
tx1.commit();
} catch (Throwable ex) {
logger.error(ex);
try {
tx1.rollback();
} catch (Exception ex2) {
logger.error("Failed to rollback transaction", ex2);
}
}

// Set up the user information
UserTransaction tx = transactionService.getUserTransaction();
NodeRef homeSpaceRef = null;
User user;
try {
tx.begin();
user = new User(userName, authService.getCurrentTicket(), personService.getPerson(userName));
homeSpaceRef = (NodeRef) nodeService.getProperty(personService.getPerson(userName), ContentModel.PROP_HOMEFOLDER);
if(homeSpaceRef == null) {
logger.warn("Home Folder is null for user '"+userName+"', using company_home.");
homeSpaceRef = (NodeRef) nodeService.getRootNode(Repository.getStoreRef());
}
user.setHomeSpaceId(homeSpaceRef.getId());
tx.commit();
} catch (Throwable ex) {
logger.error(ex);

try {
tx.rollback();
} catch (Exception ex2) {
logger.error("Failed to rollback transaction", ex2);
}

if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
} else {
throw new RuntimeException("Failed to set authenticated user", ex);
}
}

// Store the user
httpSess.setAttribute(AuthenticationHelper.AUTHENTICATION_USER, user);
httpSess.setAttribute(LoginBean.LOGIN_EXTERNAL_AUTH, Boolean.TRUE);

// Set the current locale from the Accept-Lanaguage header if available
Locale userLocale = parseAcceptLanguageHeader(req, m_languages);

if (userLocale != null) {
httpSess.setAttribute(LOCALE, userLocale);
httpSess.removeAttribute(MESSAGE_BUNDLE);
}

// Set the locale using the session
I18NUtil.setLocale(Application.getLanguage(httpSess));
}
}

public void init(FilterConfig config) throws ServletException {
this.context = config.getServletContext();
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);
transactionService = serviceRegistry.getTransactionService();
nodeService = serviceRegistry.getNodeService();

authComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent");
authService = (AuthenticationService) ctx.getBean("authenticationService");
personService = (PersonService) ctx.getBean("personService");

// Get a list of the available locales
ConfigService configServiceService = (ConfigService) ctx.getBean("webClientConfigService");
LanguagesConfigElement configElement = (LanguagesConfigElement) configServiceService.getConfig("Languages").getConfigElement(LanguagesConfigElement.CONFIG_ELEMENT_ID);

m_languages = configElement.getLanguages();
}

/**
* Return the login page address
*
* @return String
*/
private String getLoginPage() {
if (loginPage == null) {
loginPage = Application.getLoginPage(context);
}

return loginPage;
}
}



-- STEP 2 Place this class file under



C:\Alfresco\tomcat\webapps\alfresco\WEB-INF\classes\my\custom



-- STEP 3 Now you need to configure proxy pass in oc4j's httpd.conf file



$ORACLE_HOME/Apache/Apache/conf/httpd.conf, add the following entries:                                                                                    ProxyPass /alfresco/ http://host:8080/alfresco/

ProxyPass /alfresco http://host:8080/alfresco/


ProxyPassReverse /alfresco/ http://host:8080/alfresco/

ProxyPassReverse /alfresco http://host:8080/alfresco/

-- STEP 4 Now you need to enable sso on oracle portal



edit $ORACLE_HOME/Apache/Apache/conf/mod_osso.conf, add the following lines just before the :
require valid-user
AuthType Basic


require valid-user
AuthType Basic

Please restart apache after you have made this configuration 

-- STEP 5 Edit web xml file under

C:\Alfresco\tomcat\webapps\alfresco\WEB-INF

paste below lines before Authentication Filter 

<filter>
<filter-name>Osso Filter</filter-name>
<filter-class>my.custom.OSSOAuthenticationFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>Osso Filter</filter-name>
<url-pattern>/faces/jsp/browse/browse.jsp</url-pattern>
</filter-mapping>

<filter>
<filter-name>Osso Filter</filter-name>
<filter-class>my.custom.OSSOAuthenticationFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>Osso Filter</filter-name>
<url-pattern>/alfresco</url-pattern>
</filter-mapping> 

-- STEP 6 If alfresco is already running then stop and start alfresco
service from start menu under start -> alfresco -> stop alfreco
virtual server



Thats it, now oracle sso is configured successfully for Alfreco



Try opening http://oc4jserverhost/alfresco, it will redirect to oracle
portal sso login page, enter credentials, it will then redirect you to
alfresco home page on successful login.

Any issues implementing this, feel free to contact me..

Cheers,

Ujjwal Soni

Tuesday, August 2, 2011

Conflicting standard.jar with OC4J server

Today i was working on an application that was to be deployed on LIVE oc4j application server. The deployment went successful but when the application was being tested there were many errors as below related to standard. jar that was in OC4J lib and in my application's classpath.

The errors i got are as under ::


11/08/02 13:31:07 vqwiki.WikiException: org.apache.taglibs.standard.tag.common.core.Util.escapeXml(Ljava/lang/String;)Ljava/lang/String;
11/08/02 13:31:07       at vqwiki.servlets.SaveTopicServlet.doPost(SaveTopicServlet.java:150)
11/08/02 13:31:07       at javax.servlet.http.HttpServlet.service(HttpServlet.java:760)
11/08/02 13:31:07       at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
11/08/02 13:31:07       at com.evermind.server.http.ServletRequestDispatcher.invoke(ServletRequestDispatcher.java:835)
11/08/02 13:31:07       at com.evermind.server.http.ServletRequestDispatcher.forwardInternal(ServletRequestDispatcher.java:341)
11/08/02 13:31:07       at com.evermind.server.http.ServletRequestDispatcher.forward(ServletRequestDispatcher.java:230)
11/08/02 13:31:07       at vqwiki.servlets.VQWikiServlet.dispatch(VQWikiServlet.java:107)
11/08/02 13:31:07       at vqwiki.servlets.WikiServlet.doPost(WikiServlet.java:733)
11/08/02 13:31:07       at javax.servlet.http.HttpServlet.service(HttpServlet.java:760)
11/08/02 13:31:07       at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
11/08/02 13:31:07       at com.evermind.server.http.ServletRequestDispatcher.invoke(ServletRequestDispatcher.java:835)
11/08/02 13:31:07       at com.evermind.server.http.ServletRequestDispatcher.forwardInternal(ServletRequestDispatcher.java:341)
11/08/02 13:31:07       at com.evermind.server.http.ServletRequestDispatcher.forward(ServletRequestDispatcher.java:230)
11/08/02 13:31:07       at vqwiki.servlets.FrontControllerFilter.doFilter(FrontControllerFilter.java:91)
11/08/02 13:31:07       at com.evermind.server.http.EvermindFilterChain.doFilter(EvermindFilterChain.java:16)
11/08/02 13:31:07       at vqwiki.servlets.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:74)
11/08/02 13:31:07       at com.evermind.server.http.ServletRequestDispatcher.invoke(ServletRequestDispatcher.java:670)
11/08/02 13:31:07       at com.evermind.server.http.ServletRequestDispatcher.forwardInternal(ServletRequestDispatcher.java:341)
11/08/02 13:31:07       at com.evermind.server.http.HttpRequestHandler.handleNotFound(HttpRequestHandler.java:1038)
11/08/02 13:31:07       at com.evermind.server.http.HttpRequestHandler.processRequest(HttpRequestHandler.java:853)
11/08/02 13:31:07       at com.evermind.server.http.AJPRequestHandler.run(AJPRequestHandler.java:231)
11/08/02 13:31:07       at com.evermind.server.http.AJPRequestHandler.run(AJPRequestHandler.java:136)
11/08/02 13:31:07       at com.evermind.util.ReleasableResourcePooledExecutor$MyWorker.run(ReleasableResourcePooledExecutor.java:192)
11/08/02 13:31:07       at java.lang.Thread.run(Thread.java:534)


I resolved this error by editing my web application's orion-web.xml

I un-commented below line from the file :


 <!-- Uncomment this element to control web application class loader behavior. -->
        <web-app-class-loader search-local-classes-first="true"  include-war-manifest-class-path="true" /> 

Regards,

Ujjwal Soni









Monday, July 25, 2011

Load Data while Scrolling Page Down with jQuery and PHP

Hi All,

Today, i will show you data loading while page scrolling down with jQuery and PHP. We have lots of data but can not display all. This script helps you to display little data and make faster your website.

Database Table


 
CREATE TABLE messages(

mes_id INT PRIMARY KEY AUTO_INCREMENT,

msg TEXT);

load_data.php

When we are scrolling down a webpage, the script($(window).scroll) finds that you are at the bottom and calls the last_msg_funtion(). Take a look at $.post("") eg: $.post("load_data.php?action=get&last_msg_id=35")




<?php
include('config.php');
$last_msg_id=$_GET['last_msg_id'];
$action=$_GET['action'];

if($action <> "get")
{
?>

<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
$(document).ready(function()
{
function last_msg_funtion()
{
var ID=$(".message_box:last").attr("id");
$('div#last_msg_loader').html('<img src="bigLoader.gif">');
$.post("load_data.php?action=get&last_msg_id="+ID,

function(data){
if (data != "") {
$(".message_box:last").after(data);
}
$('div#last_msg_loader').empty();
});
};

$(window).scroll(function(){
if ($(window).scrollTop() == $(document).height() - $(window).height()){
last_msg_funtion();
}
});
});
</script>
</head>
<body>
<?php
include('load_first.php'); //Include load_first.php
?>
<div id="last_msg_loader"></div>
</body>
</html>
<?php
}

else
{
include('load_second.php'); //include load_second.php
}
?>

load_first.php
Contains PHP code to load 20 rows form the message table.
<?php
$sql=mysql_query("SELECT * FROM messages ORDER BY mes_id DESC LIMIT 20");
while($row=mysql_fetch_array($sql))
{
$msgID= $row['mes_id'];
$msg= $row['msg'];
?>
<div id="<?php echo $msgID; ?>" class="message_box" > 
<?php echo $msg; ?>
</div> 
<?php
} 
?>



load_second.php

Contains PHP code to load 5 rows less than last_msg_id form the message table.  


<?php
$last_msg_id=$_GET['last_msg_id'];
$sql=mysql_query("SELECT * FROM messages WHERE mes_id < '$last_msg_id' ORDER BY mes_id DESC LIMIT 5");
$last_msg_id="";
while($row=mysql_fetch_array($sql))
{
$msgID= $row['mes_id'];
$msg= $row['msg']; 
?>
<div id="<?php echo $msgID; ?>" class="message_box" > 
<?php echo $msg;
?>
</div>
<?php
} 
?>


CSS


body
{
font-family:'Georgia',Times New Roman, Times, serif;
font-size:18px;
}
.message_box
{
height:60px;
width:600px;
border:dashed 1px #48B1D9;
padding:5px ;
}
#last_msg_loader
{
text-align: right;
width: 920px;
margin: -125px auto 0 auto;
}
.number
{
float:right;
background-color:#48B1D9;
color:#000;
font-weight:bold;
}




Please let me know any problems implementing this or any suggetions you have.


Cheers,

Ujjjwal Soni

 

Thursday, July 21, 2011

Cool jQuery Progress Indicator

Today I am going to show you how you can create a cool progress indicator to tell your end user that something is going on behind the back of an action. Below is an image of the progress indicator that slides from the top to the middle of the screen then displays the processing message then slides up and disappears once done. This code does not use any other 3rd party jquery plugin to display progress indicator.


<html>
<head>
    <script src="scripts/jquery.js"></script>
    <script type="text/javascript" >
        var $j = jQuery.noConflict();
        $j(document).ready(function(){
            $j("#btnSubmit").click(function(){
                $j("#messenger").css("width", document.body.offsetWidth);
                    $j("#messenger").css("height", document.body.offsetHeight);
                    $j("#messenger").css("opacity",.7);
                    $j("#messenger").fadeIn('fast');
                $j("#messengermessage").css("width", document.body.offsetWidth);
                $j("#messengermessage").animate({opacity: "1", top: "+=" + addToAnimation, height: "100", width: document.body.offsetWidth}, "slow")
                    var myhtml = '<div style="float:left; position:relative; padding-top:30px;"><img src="images/processing.gif" /></div><div style="float:left; position:relative; padding-top:40px;"><font style="font-family:verdana; font-size:14px;color:#000000; font-weight:bold;">saving attachments...</font></div>'
                    $j("#messengermessage").html("");
                    $j("#messengermessage").html(myhtml);
                $j.post('handlers/EmployeeRequisition.ashx', {
                    requestedBy : GetRequestedBy(),
                                requestor : GetRequestor(),
                                requisitionDate : $j("#dtpRequisitionDate").val()
                },
                        function(data) {
                    myhtml = '<div style="float:left; position:relative; padding-top:30px;"><img src="images/processing.gif" /></div><div style="float:left; position:relative; padding-top:40px;"><font style="font-family:verdana; font-size:14px;color:#000000; font-weight:bold;">form saved... </font></div>'
                                $j("#messengermessage").html("");
                                $j("#messengermessage").html(myhtml);
                                $j("#messengermessage").animate({opacity: "1"},2000, function(res) {
                                var subtractThis = document.body.offsetHeight - 500;
                                $j("#messengermessage").animate({opacity: "0", top: "-=" + subtractThis, height: "0", width: document.body.offsetWidth}, "slow")
                                    $j("#messenger").fadeOut('fast');
                            });
            });
        });
    </script>
</head>
<body style="font-family: Verdana; margin: 0px;">
    <form id="frmHR001" runat="server">
    <div>
        ............

    </div>
    <div>

        <input type="button" id="btnSubmit" value="submit" />
    </div>
    <div id="messenger" style="float: none; position: absolute; width: 100%; height: 100%;
            background-color: #000000; display: none; left: 0; top: 0;">
        </div>
        <div id="messengermessage" style="float: none; position: absolute; width: 100%; height: 100px;
            background-color: #ffffff; display: none; left: 0; top: 0; text-align: center;">
            <div style="float: left; position: relative; padding-top: 30px;">
                <img src="images/processing.gif" />
            </div>
            <div style="float: left; position: relative; padding-top: 40px;">
                <font style="font-family: Verdana; font-size: 14px; color: #000000; font-weight: bold;">
                    processing...</font>
            </div>
        </div>
    </form>
</body>
</html>

The code is quite long but then again it achieves our purpose. Let me know if there are any issues implementing this code.



Cheers,

Ujjwal Soni

Tuesday, July 19, 2011

Java Gets New Garbage Collector, But Only If You Buy Support

"The monetization of Java has begun. Sun released the Java 1.6.0_14 JDK and JRE today which include a cool new garbage collector called G1. There is just one catch. Even though it is included in the distribution, the release notes state 'Although G1 is available for use in this release, note that production use of G1 is only permitted where a Java support contract has been purchased.' So the Oracle touch is already taking effect. Will OpenJDK be doomed to a feature-castrated backwater while all the good stuff goes into the new Java SE for Business commercial version?"

To try G1, specify these command line options:
-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC
I don't see anything obvious preventing you from using it (no license/support keys?), it's just not recommended since it's experimental. If you're crazy enough to use it on a production server, you better have a support contract so Sun/Oracle can fix any problems that come along. That seems reasonable.
Although it'd be better if they just said "don't use it for production, period."

Friday, July 8, 2011

Java Hangs When Converting 2.2250738585072012e-308

Java — both its runtime and compiler — go into an infinite loop when converting the decimal number 2.2250738585072012e-308 to double-precision binary floating-point. This number is supposed to convert to 0x1p-1022, which is DBL_MIN; instead, Java gets stuck, oscillating between 0x1p-1022 and 0x0.fffffffffffffp-1022, the largest subnormal double-precision floating-point number.


Send a Java Program Into An Infinite Loop

Compile this program and run it; the program will hang (at least it does on a 32-bit system with the latest JRE/JDK):
class ujjwal{
public static void main(String[] args) {
  System.out.println("Test:");
  double d = Double.parseDouble("2.2250738585072012e-308");
  System.out.println("Value: " + d);
 }
}

Send the Java Compiler Into An Infinite Loop

Try to compile this program; the compiler will hang:
class compilehang {
public static void main(String[] args) {
  double d = 2.2250738585072012e-308;
  System.out.println("Value: " + d);
 }
}

Where’s the Problem?

For the runtime case at least, Konstantin has narrowed the problem down to the “correction loop” in FloatingDecimal.java. See his comments on my PHP bug analysis article.
Like PHP, Java gets stuck crossing the normalized/unnormalized border, but in the opposite direction: it starts with an estimate just below DBL_MIN — 0x0.fffffffffffffp-1022 — and is trying to get up to DBL_MIN. but with a twist: it starts with an estimate that is correct — DBL_MIN — and then adjusts it to 0x0.fffffffffffffp-1022. It then adjusts that back to DBL_MIN, and around it goes…

Bug Report

Konstantin reported this problem to Oracle three weeks ago, but is still waiting for a reply. (Update: as per Konstantin’s comment below, the bug has been assigned “internal review ID of 1949967, which is NOT visible on the Sun Developer Network (SDN)”.)

Update: Previous Bug Reports Describe the Same Problem

Readers found two bug reports that describe the same problem (although not in terms of the magic number 2.2250738585072012e-308): bug number 100119 from 2009, and bug number 4421494 from 2001. (But don’t bother clicking on that last one — the link is now dead, as of 2/3/11.)

Addendum

As pointed out in the comments below, equivalent forms of the number cause the problem as well; examples:
  • 0.00022250738585072012e-304 (decimal point placement)
  • 00000000002.2250738585072012e-308 (leading zeros)
  • 2.225073858507201200000e-308 (trailing zeros)
  • 2.2250738585072012e-00308 (leading zeros in the exponent)
  • 2.2250738585072012997800001e-308 (superfluous digits beyond digit 17)