Wednesday, March 31, 2010

Grails change server url

http://n4.nabble.com/Change-grails-serverUrl-td1392842.html :
Change  grails.serverURL = "http://localhost:8080/${appName}" to  grails.serverURL = "http://localhost:8080/" in Config.groovy


and 


Change "app.context=" to "app.context=/" in application.properties. That's it.


One could use UrlMappings to retain support for older URLs.(If older URLs containing the app context name in them are already being used by dependent components/clients.) until all dependents/clients are notified that they need not use the app contextname in the urls. They should thus change service URLs from http://domainName/app.contextName/ to http://domainName/

Monday, March 29, 2010

Grails enable access log for embedded Jetty server

Create the file jetty-env.xml in /web-app/WEB-INF folder.
http://communitymapbuilder.org/display/JETTY/jetty-env.xml: says this xml is used for JNDI config.

http://docs.codehaus.org/display/JETTY/Logging+Requests :
Use the lower example.
<?xml version="1.0"?>
          <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD
Configure//EN"
               "http://jetty.mortbay.org/configure.dtd">
<Configure class="org.mortbay.jetty.webapp.WebAppContext">              
<Call name="addHandler">
    <Arg>
    <New class="org.mortbay.jetty.handler.RequestLogHandler">
      <Set name="requestLog">
        <New id="RequestLogImpl" class="org.mortbay.jetty.NCSARequestLog">
          <Arg><SystemProperty name="jetty.logs" default="./logs"/>/yyyy_mm_dd.request.log</Arg>
          <Set name="retainDays">90</Set>
          <Set name="append">true</Set>
          <Set name="extended">false</Set>
          <Set name="LogTimeZone">GMT</Set>
        </New>
      </Set>
    </New>
    </Arg>
  </Call>
</Configure>

Using the upper example:
<?xml version="1.0"?>
          <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD
Configure//EN"
               "http://jetty.mortbay.org/configure.dtd">
<Configure class="org.mortbay.jetty.webapp.WebAppContext">              
<Set name="handler">
      <New id="Handlers" class="org.mortbay.jetty.handler.HandlerCollection">
        <Set name="handlers">
         <Array type="org.mortbay.jetty.Handler">
           <Item>
             <New id="Contexts" class="org.mortbay.jetty.handler.ContextHandlerCollection"/>
           </Item>
           <Item>
             <New id="DefaultHandler" class="org.mortbay.jetty.handler.DefaultHandler"/>
           </Item>
           <Item>
             <New id="RequestLog" class="org.mortbay.jetty.handler.RequestLogHandler"/>
           </Item>
         </Array>
        </Set>
      </New>
    </Set>


    <Ref id="RequestLog">
      <Set name="requestLog">
        <New id="RequestLogImpl" class="org.mortbay.jetty.NCSARequestLog">
          <Arg><SystemProperty name="jetty.logs" default="./logs"/>/yyyy_mm_dd.request.log</Arg>
          <Set name="retainDays">90</Set>
          <Set name="append">true</Set>
          <Set name="extended">false</Set>
          <Set name="LogTimeZone">GMT</Set>
        </New>
      </Set>
    </Ref>
</Configure>

Causes the logging to be good but application initialization remians incomplete. If you look at the console logs, following steps are missing:

17:06:36,064 INFO  [/YourGrailsAppName][] Initializing Spring FrameworkServlet 'grails'
17:06:36,064 INFO  [GrailsDispatcherServlet][] FrameworkServlet 'grails': initia
lization started
17:06:36,189 INFO  [GrailsDispatcherServlet][] Using MultipartResolver [org.code
haus.groovy.grails.web.multipart.ContentLengthAwareCommonsMultipartResolver@c244
96]
17:06:36,189 INFO  [GrailsDispatcherServlet][] FrameworkServlet 'grails': initia
lization completed in 125 ms

Eventually an access log file named for eg. 2009_05_20.request.log is created in your application's logs folder.

Wednesday, March 24, 2010

LOG4J :D

How to redirect log messages to different appenders:
http://veerasundar.com/blog/2009/08/log4j-tutorial-how-to-send-log-messages-to-different-log-files/ :

http://groovy.dzone.com/news/groovy-and-log4j

Sample config:
logdir = /home/tapomay/logs

log4j.rootLogger=INFO, root

log4j.logger.DEFAULTLOGGER=DEBUG, root
log4j.appender.root=org.apache.log4j.DailyRollingFileAppender
log4j.appender.root.File=${logdir}/app.log
log4j.appender.root.DatePattern='.'yyyy-MM-dd-HH
log4j.appender.root.layout=org.apache.log4j.PatternLayout
log4j.appender.root.layout.ConversionPattern=<%d> %5p [%t](%C{1}) - %m%n

log4j.appender.LOGGER1=org.apache.log4j.DailyRollingFileAppender
log4j.appender.LOGGER1.File=${logdir}/app.module1.log
log4j.appender.LOGGER1.DatePattern=yyyy-MM-dd-HH
log4j.appender.LOGGER1.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGGER1.layout.ConversionPattern=<%d> %5p [%t](%C{1}) - %m%n

log4j.appender.LOGGER2=org.apache.log4j.DailyRollingFileAppender
log4j.appender.LOGGER2.File=${logdir}/app.module2.log
log4j.appender.LOGGER2.DatePattern=yyyy-MM-dd-HH
log4j.appender.LOGGER2.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGGER2.layout.ConversionPattern=<%d> %5p [%t](%C{1}) - %m%n

log4j.appender.LOCK=org.apache.log4j.DailyRollingFileAppender
log4j.appender.LOCK.File=${logdir}/app.locks.log
log4j.appender.LOCK.DatePattern=yyyy-MM-dd-HH
log4j.appender.LOCK.layout=org.apache.log4j.PatternLayout
log4j.appender.LOCK.layout.ConversionPattern=<%d> %5p [%t](%C{1}) - %m%n


log4j.additivity.LOGGER1=false
log4j.additivity.LOGGER2=false
log4j.additivity.LOCK=false

log4j.logger.LOGGER1=INFO, LOGGER1
log4j.logger.LOGGER2=DEBUG, LOGGER2
log4j.logger.LOCK=INFO, LOCK

In JAVA:
public static Logger DEFAULT = Logger.getLogger("DEFAULTLOGGER");
public static Logger LOG1 = Logger.getLogger("LOGGER1");
public static Logger LOG2 = Logger.getLogger("LOGGER2");
public static Logger LOG_LOCK = Logger.getLogger("LOCK");

 

Parse XML string into groovy.util.Node and serialize it back to XML string using XmlNodePrinter.*

import groovy.xml.MarkupBuilder

def SITEMAP= """

  
      http://www.example.com/
      2005-01-01
      monthly
      0.8
  
  
      http://www.example.com/catalog?item=12&desc=vacation_hawaii
      weekly
  
  
      http://www.example.com/catalog?item=73&desc=vacation_new_zealand
      2004-12-23
      weekly
  
  
      http://www.example.com/catalog?item=74&desc=vacation_newfoundland
      2004-12-23T18:00:15+00:00
      0.3
  
  
      http://www.example.com/catalog?item=83&desc=vacation_usa
      2004-11-23
  

"""
def sitemapProrocolSchema="""
  
      http://host3.volti.com/
      
      
      
  
"""

def xml = """

  Java
  Groovy
  JavaScript

"""

Node urlset = new XmlParser().parseText(SITEMAP)

StringWriter xmlStringWriter= new StringWriter()
XmlNodePrinter printer= new XmlNodePrinter(new PrintWriter(xmlStringWriter, true))

XmlNodePrinter.NamespaceContext namespace= new XmlNodePrinter.NamespaceContext(printer)
namespace.registerNamespacePrefix('xmlns','http://www.sitemaps.org/schemas/sitemap/0.9')

printer.print(urlset, namespace)
println xmlStringWriter.toString()

Monday, March 22, 2010

XML sitemaps

http://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=156184 says:
We recommend that you resubmit a Sitemap no more than once per hour



To resubmit your Sitemap using an HTTP request:
  1. Issue your request to the following URL:
    www.google.com/webmasters/tools/ping?sitemap=sitemap_url
    For example, if your Sitemap is located at http://www.example.com/sitemap.gz, your URL will become:
    www.google.com/webmasters/tools/ping?sitemap=http://www.example.com/sitemap.gz
  2. URL encode everything after the /ping?sitemap=:
    www.google.com/webmasters/tools/ping?sitemap=http%3A%2F%2Fwww.yoursite.com%2Fsitemap.gz
  3. Issue the HTTP request using wgetcurl, or another mechanism of your choosing.
A successful request will return an HTTP 200 response code

http://www.sitemapwriter.com/notify.php : submit xmlsitemap to Google, Yahoo!, Ask.com, Bing (Live.com) and Moreover.com at once


http://www.sitemaps.org/protocol.php : xmlsitemap protocol






<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
   <url>
      <loc>http://www.example.com/
      <lastmod>2005-01-01
      <changefreq>monthly
      <priority>0.8
   
 

http://www.iteam5.net/francesco/sitemap_gen/ : ASP scripts for sitemap gen


http://www.davidtan.org/where-to-submit-ping-your-xml-sitemaps/ : ping URLs for google, bing, yahoo, ask, msn(moreover)

  1. http://api.moreover.com/ping?u=http://yourdomain.com/yoursitemap.xml
  2. $pingurl = “www.google.com/webmasters/tools/ping?sitemap=” . urlencode($url);
  3. $pingurl = “http://www.bing.com/webmaster/ping.aspx?siteMap=” . urlencode($url);
  4. $pingurl = “http://search.yahooapis.com/SiteExplorerService/V1/updateNotification?appid=” . $appid . “&url=” . urlencode($url);
  5. $pingurl = “http://submissions.ask.com/ping?sitemap=” . urlencode($url);
http://search.yahooapis.com/SiteExplorerService/V1/updateNotification?appid=YahooDemo&url=http://www.domain.com/sitemap.xml can be used


BUT
http://choosyinfo.com/how-to-ping-your-sitemap-to-bing-google-and-yahoo.html says you could just use
http://search.yahooapis.com/SiteExplorerService/V1/ping?sitemap=[sitemap address]
http://www.catanich.com/sitemap-ping-services.asp confirms this.




To serve the sitemap.xml as static content from grails server:
http://markmail.org/message/53gvhz5evsdcwszg#query:grails%20serve%20static%20files+page:1+mid:jk77y24e6nn42dqq+state:results : says just copy it to the web-app folder


Use http://web-sniffer.net/ to check http request and response headers. Verify that you server is serving your sitemap as content-type= xml


http://www.blogjer.com/2008/03/05/cross-domain-sitemap-via-robotstxt/ :cross domain sitemaps
If you are hosting on your domain sitemaps for your clients' website(different domains)


http://www.opinionatedgeek.com/DotNet/Tools/UrlEncode/Encode.aspx : You can use this url encoder before using your sitemap url in the ping request
So the ping url for google becomes "www.google.com/webmasters/tools/ping?sitemap=http%3a%2f%2fwww.domain.com%2fsitemap.xml" 
instead of "www.google.com/webmasters/tools/ping?sitemap=http://www.domain.com/sitemap.xml"

Friday, March 12, 2010

Advanced Grails stuff

http://agileice.blogspot.com/2009/11/injecting-resources-in-easyb-grails.html

http://archive.grails.codehaus.org/lists/user@grails.codehaus.org/msg/40a20b40710050951w42793b24h9b0c9f80ca66e29c@mail.gmail.com

http://solveme.wordpress.com/2008/08/27/unable-to-install-breakpoint-due-to-missing-line-number-attributes/

http://www.grails.org/doc/1.0.x/ref/Domain%20Classes/save.html

http://www.javaworld.com/community/node/3017  :RESTing easy with Groovy’s HTTPBuilder/RESTClient


http://groovy.codehaus.org/modules/http-builder/doc/index.html :almost all about HttpBuilder


http://mrhaki.blogspot.com/2010/01/grails-goodness-access-grails.html :Access Grails Application in BootStrapAccess Grails Application in BootStrap



Q: How do I get access to the application context from sources in src/groovy?

There is no ApplicationContextHolder class equivalent to ApplicationHolder. To access to a service class called EmailService from a Groovy class in src/groovy, access the Spring bean using:
import org.codehaus.groovy.grails.web.context.ServletContextHolder as SCH
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes as GA
def ctx = SCH.servletContext.getAttribute(GA.APPLICATION_CONTEXT) def emailService = ctx.emailService
In 1.1 this is simpler:
import org.codehaus.groovy.grails.commons.ApplicationHolder as AH
def ctx = AH.application.mainContext
def emailService = ctx.emailService

Thursday, March 11, 2010

GRAILS domain class 'id' field is stubborn- I want a completely different primary key.

http://groovy.dzone.com/tips/initial-value-primary-key
Discusses an issue with setting initial value of id.


static mapping = {
03.id(generator: 'org.hibernate.id.enhanced.SequenceStyleGenerator',
04.params: [sequence_name: 'first_seq', initial_value: 50])
05.}



GOTCHA:

I got it to work, but it's not particularly groovy:

class Branch {
   String id

   static transients = ['name']


   void setName(String name) {
      id = name
   }
   String getName() {
      return id
   }
   static mapping = {
      table 'BK_BRANCH'
      version false
      id generator: 'assigned', column: 'BRANCH_NM'
   }
}

Basically it just allows you to work with the 'name' attribute but it's just a wrapper around the real 'id' attribute.

One gotcha - to save new instances, you need to call save(insert: true) otherwise the insert fails since it seems to see that the id is assigned and assumes it's an update. This is probably due to calling saveOrUpdate() under the hood, which uses null/non-null PK as the flag to determine whether to call save() or update().

- BurtBeckwith

Want to convert JSON to Grails domain class object

http://json-lib.sourceforge.net/apidocs/net/sf/json/JSONObject.html#toBean(net.sf.json.JSONObject, java.lang.Class, java.util.Map)

Check out the method "toBean()". It says:

JSONObject.toBean():returns JSONObject

public static Object toBean(JSONObject jsonObject,
                            Class beanClass,
                            Map classMap)
Creates a bean from a JSONObject, with a specific target class. If beanClass is null, this method will return a graph of DynaBeans. Any attribute that is a JSONObject and matches a key in the classMap will be converted to that target class. The classMap has the following conventions:
  • Every key must be an String.
  • Every value must be a Class.
  • A key may be a regular expression.
My usage:
Map classMap = new HashMap();
classMap.put("thumbPic", Picture.class);
classMap.put("lowPic", Picture.class);
classMap.put("highPic", Picture.class);
classMap.put("category", Category.class);
classMap.put("family", Family.class);
classMap.put("description", Description.class);
classMap.put("warranties", Warranty.class);
classMap.put("gallery", Gallery.class);
classMap.put("mediaObjects", Multimedia.class);
classMap.put("attributes", Attribute.class);
// create domain object of type Category
                JSONUtils.getMorpherRegistry().registerMorpher(new DateMorpher(["MM/dd/yyyy HH:m m:ss"] as String[])); // creating JSON object. JSONObject jsonObject = JSONObject.fromObject(mockData); // getting object Object object = (Object) JSONObject.toBean(jsonObject, beanClass,classMap);
Also check Grails Converters Reference http://grails.org/Converters+Reference

Thursday, March 4, 2010

ApplicationContext and ServletContext within GRAILS services


Q: How do I get a resource from the servletContext or applicationContext from a service?

To get the ApplicationContext, have your service implement ApplicationContextAware and declare an 'applicationContext' field. Then from within your service:
def resource = applicationContext.getResource("foo")
Accessing the Servlet Context:
import org.codehaus.groovy.grails.web.context.ServletContextHolder as SCH
def servletContext = SCH.servletContext

Wednesday, March 3, 2010

http://www.javascripttoolbox.com/bestpractices/

GIT commands that I use

git reset HEAD^ --hard
Rolled back the latest commit and removed the additions/modifications/deletions made in the latest commit


git reset HEAD --hard
Removed un-commited changes





git pull origin/gitURI master
basic pull operation

git branch --no-track 
created a branch without affiliation to any remote public repo branch i.e I must always specify the remote branch to push to/pull from.

good:
http://www.gitready.com/beginner/2009/03/09/remote-tracking-branches.html

GRAILS troubleshooting

  1. grails-debug: Instead of running just grails run-app you can use grails-debug run-app which will allow you to hook up your ide to grails and insert break points.
  2. grails -Dgrails.full.stacktrace=true run-app: This should give you the full stack trace. It isn't always useful but when you have nothing to go on it is a place to start.
  3. ?showSource = If you are in development mode and you have a gsp error you can use this command to figure out what the problem actually is.


source= http://stateyourbizness.blogspot.com/2008/05/debugging-grails.html