Wednesday, May 19, 2010

Moving Drupal sub-site from Dev to Production

Hey All, I recently moved a drupal sub-site from dev machine to production. The base url for my site on the dev machine was something like http://example.com/sub1 and the base url on production had to be http://www.sample.net. These were the steps that I followed:
1. Create a sql dump of the drupal database by using the following command on a linux terminal:

mysqldump -h localhost -u [MySQL user, e.g. root] -p[database password] -c [name of the database] > sqldump.sql

2. Next thing would be to create a tar file of the folder corresponding to the sub-site under the sites folder. For example, I created a tar file of the folder located at /sites/example.com.sub1 by using the command below

tar -pczf sub1.tar.gz /sites/example.come.sub1

3.Make sure all the drupal modules that the sub-site on the dev machine uses are also available on the production machine. Note that drupal modules are stored as a part of the File System and not stored on the drupal database.

4. If you created a custom theme on the dev machine, transfer the folder corresponding to that theme to the production machine as well. You can either use a FTP client software such as FileZilla or SSH Secure to do so. Some people feel comfortable creating a tar file of the custom theme and transferring the tar file to the production machine and later uncompressing the tar file at the destination location. Either ways it works.

5. Transfer the sql dump and the tar file that we created in Step 1 and 2 to the production machine.

6. Unzip the tar file inside the sites folder. Rename the folder to match the domain name. In my case I named the folder to sample.net

7. Create a database using the sql dump. Rename the database if you wish to. If you choose to rename the database, make sure that you change the $db_url variable within the sites/sample.net/settings.php file.

8. Make corresponding changes to the server's vhost file to resolve the new domain. Note that you can add this vhost entry even before transferring the files.

9. Open a browser and type the url www.sample.net. If you did everything right, it should bring up the drupal site mirroring the site that you created on the dev machine.

10. Check the File System of the sample.net site. Go to Administer ->Site Configuration-> File System. Make sure the file system is changed to the one on production machine. In my case it had to be sites/sample.net/files rather than sites/example.net.sub1/files. Note that since we used the same database from the dev machine, few of the settings could have dev machine's settings.

Issue:

One major issue that I faced was, while adding content to the site on the dev machine, users had hardcoded few of the links to the files. For example, to insert an image, the link was /sub1/files/images/image1.jpg . The contents when they were transferred to the production machine, were just the same. I used an UPDATE query on the database in the production machine to UPDATE those hardcoded links. All that the query had to do was to identify /sub1 and replace it with an empty string. Node_revisions is the table where drupal stores the content body and teasers. Hence the query below solved the issue

update node_revisions set teaser=replace(teaser, "/sub1",""),body=replace(body, "/sub1","");

Note: Using an UPDATE query is not always the best approach, but it worked for me. If there is any other solution to solving this links issue, let me know..

Hope that helps..!

Wednesday, April 28, 2010

XML Beans scomp - java.io.IOException: CreateProcess

This a famous exception that occurs while using XML beans.
Use the following checklist before running the scomp command
  1. Check if the JAVA_HOME environment variable is pointing to the Java root directory
  2. Check if CLASSPATH & PATH environment variables has java bin directory as the first entry
  3. Check if the XSD being used is properly defined and complete. The XSD should not be a partial XSD that has to imported by another XSD.
  4. Don't forget to restart the command promp after setting the environment variables
Use the following to compile the XSD into a JAR.
scomp –out <destination\jarname> <source\xsdname>

Thursday, April 15, 2010

SQL Server - varchar hours to int minutes

My table had a column of type varchar. It contained Hours in the format 40:20 where 40 is the hours and 20 is the minutes. I wanted to convert it into minutes of type int. 40:20 should be converted to 2420.

I used the following strategy:
1) Split the varchar using ":" delimiter.
select * from dbo.split('40:20',':')
This will return two rows. Row one contains 40 and row two contains 20.






2) Now multiply the first row with 60 to convert 40 hours into minutes and then add it with the value in the second row. i.e., (40*60)+20
The complete SQL query is as follows. It also includes the split function call.
WITH items as(

select function_call.items, row_number() over (order by function_call.dummy) rownumber
from (
        select items, 'dummy' dummy from dbo.split('40:20',':')) as function_call
)
select distinct ((cast((select items from items where rownumber = 1) as int)* 60) + cast((select items from items where rownumber = 2) as int)) minutes from items
The output of the above query execution is as follows:


I used the following split function, reused from another site:
CREATE FUNCTION dbo.Split(@String varchar(8000), @Delimiter char(1))

returns @temptable TABLE (items varchar(8000))
as
begin
declare @idx int
declare @slice varchar(8000)
select @idx = 1
if len(@String)<1 or @String is null return
while @idx!= 0
begin
set @idx = charindex(@Delimiter,@String)
if @idx!=0
set @slice = left(@String,@idx - 1)
else
set @slice = @String
if(len(@slice)>0)
insert into @temptable(Items) values(@slice)
set @String = right(@String,len(@String) - @idx)
if len(@String) = 0 break
end
return
end
The split function can be independantly used as follows:
select * from dbo.split('40:20',':')

Wednesday, April 7, 2010

Tomcat as Service - Service Startup on System Startup

If you want to start tomcat on system startup automatically, you can create tomcat service as follows. This is part of my bat file which I invoke using iZpack (an open source installer tool).

@echo on

"%~1\Apache Software Foundation\bin\tomcat6" //IS//Tomcat6 --Startup auto --JvmMx 516 --JvmMs 256 --Install "%~1\Apache Software Foundation\bin\tomcat6.exe" --Jvm auto --StartMode jvm --StopMode jvm --StartClass org.apache.catalina.startup.Bootstrap --StartParams start --StopClass org.apache.catalina.startup.Bootstrap --StopParams stop --StartPath "%~1\Apache Software Foundation" --StopPath "%~1\Apache Software Foundation" --Classpath "%~1\Apache Software Foundation\bin\bootstrap.jar"

if not errorlevel 0 goto unInstall else goto end
:unInstall
echo uninstalling.......

"%~1\Apache Software Foundation\bin\tomcat6" //DS//Tomcat6

"%~1\Apache Software Foundation\bin\tomcat6" //IS//Tomcat6 --Startup auto --JvmMx 516 --JvmMs 256 --Install "%~1\Apache Software Foundation\bin\tomcat6.exe" --Jvm auto --StartMode jvm --StopMode jvm --StartClass org.apache.catalina.startup.Bootstrap --StartParams start --StopClass org.apache.catalina.startup.Bootstrap --StopParams stop --StartPath "%~1\Apache Software Foundation" --StopPath "%~1\Apache Software Foundation" --Classpath "%~1\Apache Software Foundation\bin\bootstrap.jar"

:end
echo exiting....
In the above code, %~1 is for passing a runtime variable whose value has spaces. In my case 1 contained the installation directory path, with spaces - "C:\Program Files\"
 
Save the code as a .bat file and execute it. Make sure that you have already installed tomcat in the location as mentioned in the code. In my case, Tomcat was installed under "C:\Program Files\".


Symlink - infinite folder issue

Hey All,

Recently I ended up in setting a Symlink for one of my sub-sites driven by Drupal. The url for my sub-site was somewhat like this "www.example.com/sub1". What I actually did was created a symlink at the root called sub1. The site worked fine and I never realized that even if a user types "www.example.com/sub1/sub1" the same homepage is served to the user by the server. It does not stop there, when I typed www.example.com/sub1/sub1/sub1 , the same happens..The same is true for infinite number of /sub1. That was totally insane. How could have I not thought about such an issue. Obviously it will work that way because the Symlink was pointing to the drupal root. So no matter how many /sub1 I type, the symlink will keep adding sub1 to the url and still point to the same homepage. Not that there are that many physical existence of sub1 folders, but as you know symlink is just a way to pretend as if the files physically exist.

Something had to be done there to avoid sinking into multiple/infinite folders of the same name sub1.

Solution:

Open the vhosts.d file (the configuration file for your site, note that this file's name might change depending on how your server is configured). Add the following < Directory /drupal/sub1/sub1/ > Order Deny,Allow Deny from all < /Directory >

Note that I have assumed that drupal is installed in the root. Actually this can work for any symlink issue (not necessarily to be used with drupal). All it does is asks the server not to serve a client's request or even a bot's request if they ask for www.example.com/sub1/sub1 . Note that by denying access to the second level folder designation, all other infinite folder access can be avoided (for example www.example.com/sub1/sub1/sub1/sub1/ can be denied as well).

Hope that helps!!!!

Tuesday, April 6, 2010

How to Create multi-sites using Drupal

Listed are the steps to create multiple sites under a sub-directory using a single Drupal codebase.
  1. Create a new database if you choose to have the subsite independent of the main Drupal site. Note that the sub-site can also use the same database of the main drupal site.
  2. Create a folder under the /drupal/sites/ folder. Note that I have assumed the drupal installation is on the root. Change the path as per your case. The new folder thus created has some naming constraints. For example, if the main drupal site's name is example.com and you wish to have a subsite by the name example.com/sub1, then the name of the folder will have to be "example.com.sub1". Copy the drupal/sites/default folder contents into the new example.com.sub1 folder.
  3. Open the settings.php file inside the /drupal/sites/example.com.sub1 folder. Remember to make this settings.php file writable, because Drupal will need the file to to writable in later steps of this process.Use >>sudo chmod 666 setting.php in a shell program to make the file writable if you need root user rights.
  4. Find the line that sets the db_url. Change the database name to the new database created in Step1. Change the base_url to "www.example.com/sub1" . Not that the base_url should not have a trailing slash after "sub1". Drupal automatically adds it. Save the settings.php file and close it. We will not be doing any more changes to the settings.php file.
  5. Open the .htaccess file under /drupal (where ever drupal has been installed).
  6. Add the following redirect rules to the .htaccess file:
  7. RewriteBase /

RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_URI} ^/sub1/.* RewriteRule ^(.*)$ /sub1/index.php?q=$1 [L,QSA]

Note that the RewriteBase / might already be there in the .htaccess file. If it is there and is commented, un-comment it. Make sure the RewriteEngine is on as well. Save the file.

8. Using Putty or any shell program, change directory to the folder where drupal is installed. For example if drupal is installed in the root of the server, go to the root and create a Symlink (symbolic link) by typing the command below ln -s . sub1 The line above creates a symlink by the name sub1 that points to the drupal root. What this actually means is, the sub-site will share the same Drupal codebase, however has its own database and other settings. We can even create separate themes and modules folder under sites/example.com.sub1 folder and place the sub-site specific themes and modules there. Go to www.example.com/sub1/install.php in a browser. You will be led through the normal Drupal installation process. Making the settings.php fle writable as part of the step 3, helps here. Note that Drupal is installed for the subsite, from the same single Drupal codebase. Any updates done to Drupal's codebase such as maintenance tasks, will be applied to all the sites. Good Luck..!

Drupal CMS Internal Server Error 500

Drupal one of the best CMS ever. Thought of installing a new Drupal website this morning. I have worked with several other Drupal sites before and never had any other site in the past give such a weird error as the one shown below:

Internal Server Error The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator, abc@abc.com and inform them of the time the error occurred, and anything you might have done that may have caused the error.

More information about this error may be available in the server error log.

All I did was installed Drupal. Site was just fine. Enabled Clean Urls and went to the site's homepage, there comes the error. However I was able to access the site by directly typing the hardcoded url's, not the clean ones. So the site was up, it was not a Drupal installation issue. If it was not a Drupal issue, then the next bet would be the server configuration files. Druapl highly is dependent on the server configuration to work right. All that was required was to uncomment the following line from the .htaccess file that handles drupal re-directs.

RedirectBase /

That brought the drupal site up. Note that by uncommenting the above line, even the sub-sites installed as sub-directories (www.example.com/subdir) or subsites (www.subsite.example.com) will work.

Monday, April 5, 2010

Favicons

Here is a simple way to add favicon to you webpage. It is done using JSP and javascript:

<script language="javascript">

var link = document.createElement('link');
link.type = 'image/x-icon';
link.rel = 'shortcut icon';
link.href = '<%=request.getContextPath()%>/images/logos/favicon.ico';
document.getElementsByTagName('head')[0].appendChild(link);

</script>

Make sure to add your icon into the specified location relative to the context root.

Monday, March 8, 2010

Spring and JNDI

You can inject a jndi object to Spring bean as follows: In your server.xml file configure objects to be registered in JNDI (sample is for tomcat server) as follows:

<context source="org.eclipse.jst.jee.server:Sample" reloadable="true" path="/Sample" docbase="Sample"> <resource factory="org.apache.naming.factory.BeanFactory" auth="Container" type="com.test.SampleBean" name="services/SampleBean"> </context>

The resource tag within the context tag registers the bean in JNDI. Now, to inject the JNDI object into a Spring bean during bean initialization, do the following in you spring.xml bean configuration

<bean class="org.springframework.jndi.JndiObjectFactoryBean" id="SampleBeanWithJNDIInjection"><property name="jndiName"><value>java:comp/env/services/SampleBean</value></property><property name="resourceRef" value="true"></property> </bean>

The above configuration, loads the bean available in the JNDI directory into the new Spring Bean