Thursday, December 15, 2011

Two hours with Rasmus Lerdorf, the creator of PHP

I had the pleasure to meet Rasmus Lerdorf, the creator of PHP in a two hour session organized by South Florida PHP Users Group in Nova South Eastern University.

As one of the earliest PHP adopters I share a lot of feelings for the language and it was great to see so many young people in the room together with not so young like me ;-) and some older than me. It is great to see a language going on for so long. I would say it was a celebration of more than 15 years of PHP coding.

Even though I have been working more with python, ruby and Java for the last 5 years PHP always comes back: I need to patch a built in PHP software, configure it or even get a quick snippet and modify it to get my work done.

So with a lot of quotations here is an extract of the introductory ideas this MIT awarded "top 100 innovators in the world" shared with us.

The idea behind PHP was always "the need for speed and performance". Rasmus "did not worry about correctness but about resolving the problem". He is a guy that "does not love to program" and that is precisely why you want to use PHP because instead he actually "loves to solve problems".

"You have to add non scalable features in order to make php not scalable". The "documentation was always done before the function was implemented". He constantly "insisted in having lot of examples as part of the documentation"

PHP was born while "thinking in the ecosystem". Basically shared hosting demanded control on memory and CPU (QoS) to adequate existing servers to the needs of multiple applications.

PHP "runs crappy code extremely fast" so it is better for startups than other languages like Java. It simply scales well.

I asked the question about why he considered Java not scalable and he clarified:
-It does scale but it comes out of the box with features that allow the requests to be sticked in memory, a thing php by default does not allow. Also when it comes to go beyond one server it is then more difficult in java just because of this.

Of course one can argue sticky sessions are enough for most projects. Yes the user session will expire and then you will need to re login but things like remember-me will help (not that I like it really). Not big deal considering how many times this actually happens, I would say nobody complained to me on the clusters I have setup for which in really weird circumstances a shared clustered session was used.

He described some features that make PHP even faster today:
  1. libevent allows event driven programming ala nodejs.
  2. zeromq for better and simplest socket programming. I have to add that messaging is in fact something I would say will gain more and more momentum within the software community. The world is asynchronous as the creator of Erlang language said said.
  3. FastCGI Process Manager (FPM) allows dividing the workload while sending jobs to workers. This is the PHP way to say no to threads.

Rasmus talked about performance and brought some examples providing some guidance to improve it:
  1. Use wisely your datastores. Do not try to replace sql with nosql, it simply does not work that way.
  2. Turn off logging in production (error_reporting(-1) is expensive).
  3. Use strace: Look for ENOENT, excessive stats (lstat), check your realpath_cache_size.
  4. Use a profiler: callgrind, xdebug, xhprof, xhgui.
  5. Set default timezone (look at phpinfo).
  6. Watch for inclusions. Too many inclusions degrade performance. An example of a bad application is Magento which includes thousand pf files.
  7. HipHop-PHP can be used to do static analysis. They need to parse php better than the php parser itself because their goal is to translate PHP to native code. Be prepared to wait for the compiler but this is a good exercise to find problems in your code.

Here are some architecture reminders/suggestions from Rasmus:
  1. Use different domain/subdomain for static assets.
  2. Keep cookies short (MTU size maters and will translate in more roundtrips when it is overflown).
  3. Multiply by 5 times the amount of cores and that is the amount of real concurrent users. I have to say I have been calculating allowed concurrent users for years and the metric about just the cores is not that simple. It even depends on what the application is using of course so a word of advice from my end would be take a look at your system metrics for example with vmstat, top and other system commands. The use of automated stress tests driven by for example jmeter are a must do in my opinion.
  4. Use out-of-band processing with Gearman, PHP-FPM or custom via ZeroMQ.
  5. Tweak ORM and caching.

Finally he talked about the PHP 5.3 features, how PHP 6 development was stopped, the problems inherent to support Unicode and the efforts that are still being made in the current version 5 to support little by little more Unicode functionality. Here are some of those new features:
  1. Better performance through lot of code optimization.
  2. Support for closures.
  3. Namespaces. There is a big debate around the decision to use a backslash instead of a dot for the namespaces. To be honest I do feel that as awkward but as Rasmus said "we will need to get used to it".
  4. Late Static Binding support.
  5. Garbage Colector which you should not need in web apps but if you have long running scripts then ii will definitely help.
  6. NEWDOC which is like HEREDOC but does not perform any parsing inside the string block.
  7. Remember "Go To Statement Considered Harmful", the famous letter from Edsger Dijkstra? The controversy is still on as PHP allows "goto" to eliminate verbosity or the use of break. In my opinion the discussion about the name is secondary. You can use break or continue to a a label in Java for example so if a goto has just the meaning of breaking the loop to a variable I think is awkward but but I am fine with it. However allowing goto to go to any part of the code block is not precisely a multi level break or continue, it is something more than that. If that is harmful, confusing, miss leading or not I leave it to the discussion. Perhaps just adjusting the multi level sysntax from PHP to accept a letter instead of a "magic" number would be a better approach.
  8. DateInterval/DatePeriod classes.
  9. date_create_from_format
  10. FastCGI Process manager (FPM)
  11. For people moving to ngnix from apache .php_ini allows for custom php directives just like .htaccess for Apache.
  12. Traits: Compiler assisted copy and paste to resolve the lack of multiple inheritance.

Thank you Rasmus for PHP. Let's celebrate how lucky we are that not a single language could ever win all battles. Different languages exist to resolve similar problems unders different scenarios. This is not any different than we, human beings. We need different skills in a team as much as we need different languages in modern computing.

and different human beings exist to reso

Workspace defines a VM that does not contain a valid jre/lib/rt.jar in Snow Leopard OSX

I was getting this error today after trying to use "mvn eclipse:eclipse" to generate Eclipse project files out of a maven project:
[WARNING] Workspace defines a VM that does not contain a valid jre/lib/rt.jar: /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home

There is a proposed patch for this bug but at the time of this writing I could not figure out a better way than running the below commands:
cd /System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home
sudo mkdir -p jre/lib
cd jre/lib
sudo ln -s ../../../Classes/classes.jar rt.jar

Remove context from url from Tomcat applications

If you are like me you love tomcat simplicity and you are used to deploy your WAR files or exploded directories in webapps folder directly. However in order to serve URLs without the context included you will need to stop that practice.

You might come with a hack like I discover a while back, but as you can read there that will result in the same application being deployed several times.

Here is how to configure tomcat (Tested in tomcat 7) to serve content from two different URLs
  1. Make your websites resolve to real IPs. For production you rely on external DNS, for other environments you rely on internal DNS and many times in you /etc/hosts:
    $ vi /etc/hosts
    ...
    127.0.0.1   bhubdev.nestorurquiza.com
    127.0.0.1   bhubdev2.nestorurquiza.com
    ...
    
  2. You need to add them both to Engine section in conf/server.xml:
    ...
     <host name="bhubdev.nestorurquiza.com"  appBase="bhub-app"
        unpackWARs="true" autoDeploy="true"
        deployOnStartup="true" />
      <host name="bhubdev2.nestorurquiza.com"  appBase="bhub2-app"
        unpackWARs="true" autoDeploy="true"
        deployOnStartup="true" />
    
    
  3. Create these folders (two per domain as you can see). Be sure to change to proper paths in your system:
    $ mkdir /Users/nestor/Downloads/apache-tomcat-7.0.22/bhub-app
    $ mkdir /Users/nestor/Downloads/apache-tomcat-7.0.22/conf/Catalina/bhubdev.nestorurquiza.com
    $ mkdir /Users/nestor/Downloads/apache-tomcat-7.0.22/bhub2-app
    $ mkdir /Users/nestor/Downloads/apache-tomcat-7.0.22/conf/Catalina/bhub2dev.nestorurquiza.com
    
  4. Restart tomcat.
  5. Deploy the WAR files as:
    /Users/nestor/Downloads/apache-tomcat-7.0.22/bhub-app/ROOT.war
    /Users/nestor/Downloads/apache-tomcat-7.0.22/bhub2-app/ROOT.war
    
  6. Alternatively deploy the exploded WAR file as:
    unzip bhub-app.war -d /Users/nestor/Downloads/apache-tomcat-7.0.22/bhub-app/ROOT/
    unzip bhub-app2.war -d /Users/nestor/Downloads/apache-tomcat-7.0.22/bhub2-app/ROOT/
    

Now if you use maven and you want to deploy from there you probably have something like the below if you are still deploying to webapp folder (using ant tasks to deploy either the WAR file or the exploded directory)
...

    ${MVN_TOMCAT_HOME_DEPLOY}
...

    
    
        
    

...

    Deploying WAR locally
    

...

You will need to update that to point to the new directories and not to webapps anymore.
...

  ${CATALINA_HOME}
...

    
    
        
    

...

    
    

...

Do not forget to add to your profile the needed for Maven environment variable:
$ vi ~/.profile:
#old needed variable
#export MVN_TOMCAT_HOME_DEPLOY=/opt/tomcat/webapps
#new needed variable
export CATALINA_HOME=/opt/tomcat
$ source ~/.profile

Wednesday, December 14, 2011

Monitor Event Log in Windows 2008

I already described how we can monitor event logs from windows but that procedure will not work for Windows 2008 and Windows 7 because eventtriggers.exe has been deprecated.

Here is a new script you will need to use in Windows 7/2008 together with "Windows Task Scheduler". The comments on the top of the script should be straightforward to understand how to get an email alert every time an application ERROR event is registered in the Event logs.

'''''''''''''''''''''''''''''''''''''''''''''''
'
' c:\scripts\events\sendEventErrorByEmail.vbs
'
' @Author: Nestor Urquiza
' @Created: 12/14/2011
'
'
' @Description: Alerts a Windows Admin there are errors in Event Viewer. 
' It could be scheduled to run every maxMinutes but
' Using it as an action for a custom Scheduled Task with a trigger on event filters:
'
' Task Scheduler Library: Create Task | Triggers | New Trigger | Begin the Task On an Event | Settings Custom | New Event Filter | Event Level Error | By Log | Event Logs | Windows Logs | Application
'
'
'
'

'
'
' @Compatibility: Tested so far in WindowsXP, Vista, 7, 2000, 2003, 2008
'
'
' @Parameters
' 1. A prefix body message in case specific errors are to be sent 
'    (a combination of batch and eventtriggers will do the trick)
'
'
' @Filters: I am filtering only "Application" events. Change the SQL query if you want to apply a different filter or not filter at all
'
'
'
''''''''''''''''''''''''''''''''''''''''''''''''

'Constants
strSmartHost = "mail.sample.com"
strSmartPort = 25
maxMinutes = 1
strComputer = "."
emailFrom = "donotreply@nestorurquiza.com"
emailTo = "nurquiza@nestorurquiza.com"

'System config
Set wshShell = WScript.CreateObject( "WScript.Shell" )
strComputerName = wshShell.ExpandEnvironmentStrings( "%COMPUTERNAME%" )
Set objSWbemServices = GetObject("winmgmts:" _
 & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colTimeZone = objSWbemServices.ExecQuery _
 ("SELECT * FROM Win32_TimeZone")
For Each objTimeZone in colTimeZone
 offset = objTimeZone.Bias
Next

'Parameters
Dim strBody
If (Wscript.Arguments.Count > 0) Then
  strBody = Wscript.Arguments(0)
End If

'Start date to look for events
dtmDate = DateAdd("n",-maxMinutes,Now())
dateToWMIDateString = Year(dtmDate) & padZeros(Month(dtmDate)) & padZeros(Day(dtmDate)) & padZeros(Hour(dtmDate)) & padZeros(Minute(dtmDate)) & padZeros(Second(dtmDate)) & ".000000" & offset

'Get events matching the query
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}//" & _
        strComputer & "\root\cimv2")
Set colLogFiles = objWMIService.ExecQuery _
    ("Select * from Win32_NTLogEvent " _
        & "Where Logfile='Application' and Type='Error' and TimeGenerated > '" &  dateToWMIDateString & "'" )

'Accumulate all events dates and details
For Each objLogFile in colLogFiles
    dtmInstallDate = objLogFile.TimeGenerated
    WMIDateStringToDate = CDate(Mid(dtmInstallDate, 5, 2) & "/" & _
     Mid(dtmInstallDate, 7, 2) & "/" & Left(dtmInstallDate, 4) _
         & " " & Mid (dtmInstallDate, 9, 2) & ":" & _
             Mid(dtmInstallDate, 11, 2) & ":" & Mid(dtmInstallDate, _
                 13, 2))
    WMIDateStringToDate = DateAdd("n", offset, WMIDateStringToDate)
    details = details & vbCrLf & WMIDateStringToDate  & " - [" & _
                   objLogFile.Type & "] " & _
                   objLogFile.Message
    'Wscript.Echo details
Next

'Send email with details about matching events
If (Not IsNull(details) And details <> "") Then
    'Prepare email
    Set objEmail = CreateObject("CDO.Message")
    objEmail.From = emailFrom
    objEmail.To = emailTo
    objEmail.Subject = "[" & strComputerName & "] " & "Event Viewer Alert"
    If (Not IsNull(strBody) And strBody <> "") Then
        objEmail.Textbody = strBody & ". "
    End If
    objEmail.Textbody = objEmail.Textbody & details

    'Custom server
    objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
    objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = strSmartHost
    objEmail.Configuration.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = strSmartPort
    objEmail.Configuration.Fields.Update

    'Send it
    objEmail.Send
End If

Function padZeros(dtmDate)
If Len(dtmDate) = 1 Then
    padZeros = "0" & dtmDate
Else
    padZeros = dtmDate
End If
End Function

BTW you will notice the Event filter contains the below which could give you some hints to research even more powerful ways to control different event alerts:

    
      
    
  
Here is how to get SSL authentication or TLS Authentication support.

Wednesday, December 07, 2011

Arial Font from JasperReports for free and legally

If you are planning to ship documents to your clients and you need to use one of the commercial most used fonts like Arial you are in your way to pay a good chunk of money. There is not even a clear price on what they might cost because basically it depends on your application (read the license goes with how much money you are making with your product).

Thanks to the information I found in this post it took me little time to legally use a close to the proprietary Arial font in our application. If you plan to distribute or license your application you will need to buy Arial font or find a different project with a more commercial friendly license (like BSD) as the license for Liberation fonts is GPL. must then

  1. Download and extract the Red Hat Open Source GPL licensed Liberation Fonts
  2. From iReport Preferences on a Mac or Options for the rest of the mortals navigate through "iReport | Fonts | Install Font", then import "LiberationSans-Regular.ttf" from the exploded directory created as part of the above step. Click next and pick the bold, Italic and BoldItalic versions for LiberationSans. LiberationSans is the closest font to Arial. The rest of the Liberation Fonts are closer to Times New Roman and Courier New fonts
  3. Pick a good family name that will later use in your style fontName property, for example "LiberationSans". Check the "Embed this font in the PDF document"
  4. Include your font in a hello world jrxml like I show below and run it from iReport. Play with the properties and you should see bold and italic rendered as well (I am in this example striking through and underlining as well).
    <?xml version="1.0" encoding="UTF-8"?>
    <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="hello" language="groovy" pageWidth="595" pageHeight="842" whenNoDataType="AllSectionsNoDetail" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20">
     <property name="ireport.zoom" value="1.0"/>
     <property name="ireport.x" value="0"/>
     <property name="ireport.y" value="0"/>
     <style name="Default" isDefault="true" fontName="LiberationSans" fontSize="20" isBold="true" isItalic="true" isUnderline="true" isStrikeThrough="true"/>
     <background>
      <band splitType="Stretch"/>
     </background>
     <title>
      <band height="79" splitType="Stretch">
       <staticText>
        <reportElement x="12" y="10" width="531" height="57"/>
        <textElement/>
        <text><![CDATA[Hello JasperReports!!!]]></text>
       </staticText>
      </band>
     </title>
     <pageHeader>
      <band height="35" splitType="Stretch"/>
     </pageHeader>
     <columnHeader>
      <band height="61" splitType="Stretch"/>
     </columnHeader>
     <detail>
      <band height="125" splitType="Stretch"/>
     </detail>
     <columnFooter>
      <band height="45" splitType="Stretch"/>
     </columnFooter>
     <pageFooter>
      <band height="54" splitType="Stretch"/>
     </pageFooter>
     <summary>
      <band height="42" splitType="Stretch"/>
     </summary>
    </jasperReport>
    
  5. Now you should see from iReport your font correctly embedding in the resulting PDF
  6. From iReport navigate to the Fonts settings as I explained before and then pick "LiberationSans" and export it as liberation-sans.jar
  7. Include the jar in your application classpath
  8. Now your app is serving close to Arial font styled content

Followers