incubator-sling-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Sling > GSoC 2010 mini-CMS project
Date Tue, 10 Aug 2010 13:06:00 GMT
<html>
<head>
    <base href="https://cwiki.apache.org/confluence">
            <link rel="stylesheet" href="/confluence/s/1810/9/1/_/styles/combined.css?spaceKey=SLING&amp;forWysiwyg=true"
type="text/css">
    </head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
    <h2><a href="https://cwiki.apache.org/confluence/display/SLING/GSoC+2010+mini-CMS+project">GSoC
2010 mini-CMS project</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://cwiki.apache.org/confluence/display/~fpaparoni">Federico
Paparoni</a>
    </h4>
        <br/>
                         <h4>Changes (2)</h4>
                                 
    
<div id="page-diffs">
            <table class="diff" cellpadding="0" cellspacing="0">
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >If the resource doesn&#39;t exist,
a new item is created. If the resource name ends with /\* or /, the name of the item will
be created using an algorith that also uses the name of new node. <br> <br></td></tr>
            <tr><td class="diff-changed-lines" >h1. <span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">{color:#003366}{*}Authentication{*}{color}</span>
<span class="diff-added-words"style="background-color: #dfd;">Authentication</span>
<br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">
<br>You can submit new entry only if you have already authenticated with Sling. So you
can see that on the [/apps/david/menu.esp|http://code.google.com/p/davidgsoc2010/source/browse/trunk/core/src/main/resources/initial-content/apps/david/menu.esp]
script there is a check for the credentials <br> <br>{code} <br>...... <br>...
<br>&lt;td width=&quot;33%&quot; align=&quot;right&quot;&gt;
<br>	Logged as: &lt;b id=&quot;username&quot;&gt;????&lt;/b&gt;
<br>&lt;/td&gt; <br>&lt;/tr&gt; <br>&lt;/table&gt;
<br>&lt;script language=&quot;javascript&quot;&gt; <br>	var info
= Sling.getSessionInfo(); <br>	if (info.userID==&quot;anonymous&quot;) <br>
	document.getElementById(&quot;username&quot;).innerHTML =  <br>			info.userID+&quot;&lt;a
href=&#39;/system/sling/form/login?resource=/content/david.html&#39;&gt;Login&lt;/a&gt;&quot;;
<br>	else <br>		document.getElementById(&quot;username&quot;).innerHTML
= info.userID; <br>&lt;/script&gt; <br>... <br>... <br>{code}
<br></td></tr>
        </table>
</div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <h1><a name="GSoC2010mini-CMSproject-Overview%28fromSLING1438%29"></a>Overview
(from SLING-1438)</h1>

<p>This is a Google Summer of Code 2010, Federico Paparoni has been accepted as a student
to work on it, mentored by Bertrand Delacretaz</p>

<p>The goal is to create a mini-CMS with Sling, that demonstrates Sling best practices.</p>

<p>See <a href="http://tinyurl.com/asfgsoc" class="external-link" rel="nofollow">http://tinyurl.com/asfgsoc</a>
for the full list of GSoC 2010 projects at the ASF, and <a href="http://community.apache.org/gsoc"
class="external-link" rel="nofollow">http://community.apache.org/gsoc</a> for general
GSoC information.</p>


<h1><a name="GSoC2010mini-CMSproject-"></a><font color="#003366"><b>Introduction</b></font></h1>

<p>Apache Sling is an opensource project with a lot of technologies and features. The
goal of this project is to create a mini-CMS, that developers can use to understand how to
develop a simple application with Sling.&nbsp;</p>

<p>So it is necessary to know a little about two main topics: OSGi and JCR. The following
links are useful resources to read something about these technologies.</p>

<p><b><em>OSGi</em></b></p>
<ul>
	<li><a href="http://en.wikipedia.org/wiki/OSGi" class="external-link" rel="nofollow">http://en.wikipedia.org/wiki/OSGi</a></li>
	<li><a href="http://felix.apache.org/" class="external-link" rel="nofollow">http://felix.apache.org/</a></li>
	<li><a href="http://www.osgi.org/Links/BasicEducation" class="external-link" rel="nofollow">http://www.osgi.org/Links/BasicEducation</a></li>
</ul>


<p><b><em>JCR</em></b></p>
<ul>
	<li><a href="http://jackrabbit.apache.org/" class="external-link" rel="nofollow">http://jackrabbit.apache.org/</a></li>
	<li><a href="http://www.ibm.com/developerworks/java/library/j-jcr/" class="external-link"
rel="nofollow">http://www.ibm.com/developerworks/java/library/j-jcr/</a></li>
	<li><a href="http://wiki.apache.org/jackrabbit/DavidsModel" class="external-link"
rel="nofollow">http://wiki.apache.org/jackrabbit/DavidsModel</a></li>
</ul>


<p>The repository for this project can be found at&nbsp;<a href="http://code.google.com/p/davidgsoc2010/"
class="external-link" rel="nofollow">http://code.google.com/p/davidgsoc2010/</a>.</p>

<h1><a name="GSoC2010mini-CMSproject-"></a><font color="#003366"><b>Some
words about David Mini CMS</b></font></h1>

<p>This project shows some features of Apache Sling and can be used for educational
purpose to move your first steps with this framework.</p>

<p>David uses the following opensource library/technologies:</p>

<p><font color="#000000">&nbsp;</font></p>

<ul>
	<li><font color="#003366"><a href="http://jquery.com/" class="external-link"
rel="nofollow">jQuery&nbsp;</a></font> 1.4.2</li>
	<li><a href="http://jqueryui.com/" class="external-link" rel="nofollow">jQueryUI&nbsp;</a>
1.8</li>
	<li><a href="http://gmarwaha.com/blog/?p=7" class="external-link" rel="nofollow">LavaLamp
</a> &#45; A menu plugin for jQuery with cool hover effects&nbsp;</li>
	<li><a href="http://www.roytanck.com/2008/03/06/wordpress-plugin-wp-cumulus-flash-based-tag-cloud/"
class="external-link" rel="nofollow">WP-Cumulus SWF</a> &#45;&nbsp;used to
display tag cloud</li>
	<li><a href="http://itextpdf.com/" class="external-link" rel="nofollow">iText&nbsp;</a></li>
	<li><a href="http://ckeditor.com/" class="external-link" rel="nofollow">CKEditor&nbsp;</a></li>
</ul>


<p>The available features are</p>
<ul>
	<li>CRUD (Create, Read, Update and Delete) for the content</li>
	<li>Full HTML creation of article</li>
	<li>Creation of PDF rappresentation of a single post or the entire list of contents
available</li>
	<li>Tagging system</li>
	<li>Search by title,text,tag</li>
	<li>Send email to someone with the link of article</li>
	<li>Background service that checks number of articles/tags in the repository</li>
</ul>


<p>These aren't space age features, but are useful to understand how to create an application
using Apache Sling</p>

<h1><a name="GSoC2010mini-CMSproject-FirststepsintoSling"></a><b>First
steps into Sling</b></h1>

<p>Firstly you must setup the environment for Sling, so you can follow the guide at&nbsp;<a
href="http://sling.apache.org/site/getting-and-building-sling.html" class="external-link"
rel="nofollow">http://sling.apache.org/site/getting-and-building-sling.html</a>.</p>

<p>Now that you created your environment, you can setup some other tools that can be
useful during the development:</p>
<ul>
	<li><a href="http://curl.haxx.se/" class="external-link" rel="nofollow">cURL</a>
: Command line tool to send HTTP request</li>
	<li><a href="http://svn.apache.org/repos/asf/sling/trunk/contrib/explorers/jquery/"
class="external-link" rel="nofollow">JCR Explorer</a> : Extension that create a useful
explorer for the JCR repository you are working in</li>
	<li><a href="http://www.bitkinex.com/" class="external-link" rel="nofollow">BitKinex</a>
:&nbsp;FTP/SFTP/HTTP/WebDAV Client that can be used to manage the files you uploaded in
Sling</li>
</ul>


<p>It's time to make our "Hello world" in Apache Sling.&nbsp;<br/>
Open a console and simply launch the next command:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">curl -F<span class="code-quote">"sling:resourceType=foo/bar"</span>
-F<span class="code-quote">"title=Hello world"</span> http:<span class="code-comment">//admin:admin@localhost:8080/content/myfirstnode</span>
</pre>
</div></div>

<p>This is a simple HTTP request, where you pass some parameters and values. Using it
you have created a first resource under Sling.&nbsp;<br/>
The resource is a JCR node, as every resource in Sling, put under folder /content. This node
has two parameters, title and sling:resourceType.&nbsp;</p>

<p>Node creation is a simple task, but you must understand how you can render the information
stored in the nodes using Sling.<br/>
The first document you can read is the next one:&nbsp;<a href="http://dev.day.com/content/ddc/blog/2008/07/cheatsheet/_jcr_content/par/download/file.res/cheatsheet.pdf"
class="external-link" rel="nofollow">http://dev.day.com/content/ddc/blog/2008/07/cheatsheet/_jcr_content/par/download/file.res/cheatsheet.pdf</a><br/>
It simply describes how content resolution works in Sling.&nbsp;</p>

<p>Another important information to better understand Sling, is that a resource is rendered
by a script.<br/>
Script files are stored under the folders /apps or /libs and there is a wide choice of possible
scripting engine:&nbsp;</p>
<ul>
	<li>ESP</li>
	<li>JSP</li>
	<li>Java Servlet</li>
	<li>Scala</li>
	<li>Python</li>
	<li>Groovy</li>
	<li>Ruby</li>
</ul>


<p>To select a script, Sling uses the node's sling:resourceType property. So if we say
that&nbsp;sling:resourceType is foo/bar, Sling will search under the /apps/foo/bar/ folder.<br/>
The following links describes how the scripts work and what type of variables we have during
the script execution:</p>
<ul>
	<li><a href="https://cwiki.apache.org/SLING/scripting-variables.html" class="external-link"
rel="nofollow">https://cwiki.apache.org/SLING/scripting-variables.html</a></li>
	<li><a href="https://cwiki.apache.org/SLING/url-to-script-resolution.html" class="external-link"
rel="nofollow">https://cwiki.apache.org/SLING/url-to-script-resolution.html</a></li>
</ul>


<h1><a name="GSoC2010mini-CMSproject-"></a><font color="#003366"><b>Content
loading</b></font></h1>

<p>You can setup some initial contents that can be used in your application. It is a
useful thing, because with a simple configuration you have some nodes already created when
your application starts.</p>

<p>In David there are two different nodes created when you deploy your application:
<a href="http://code.google.com/p/davidgsoc2010/source/browse/trunk/core/src/main/resources/initial-content/content/david.json"
class="external-link" rel="nofollow">/content/david</a> and <a href="http://code.google.com/p/davidgsoc2010/source/browse/trunk/core/src/main/resources/initial-content/content/tags.json"
class="external-link" rel="nofollow">/content/tags</a> .</p>

<p>These nodes are defined in the application folders, using a JSON format. Every information
stored in these JSON will be a property of the created nodes.&nbsp;</p>

<p>The most important property is the next one</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java"><span class="code-quote">"sling:resourceType"</span>:
<span class="code-quote">"david"</span>
</pre>
</div></div>
<p>This property defines "david" as resource type, so Sling knows that it will search
under the folder /apps/david to find the scripts that will be called on this node.</p>

<p>These JSON files are loaded using the <a href="http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html"
class="external-link" rel="nofollow">Maven Bundle Plugin</a> , as you can see in
the David <a href="http://code.google.com/p/davidgsoc2010/source/browse/trunk/core/pom.xml"
class="external-link" rel="nofollow">core/pom.xml</a> file&nbsp;</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">&lt;!-- initial content to be loaded on bundle installation
--&gt;
&lt;Sling-Initial-Content&gt;
	initial-content;overwrite:=<span class="code-keyword">true</span>;uninstall:=<span
class="code-keyword">true</span>
&lt;/Sling-Initial-Content&gt;                 
</pre>
</div></div>
<p>JSON isn't the only way to load initial content. Further informations about content
loading can be found in the <a href="http://sling.apache.org/site/content-loading-jcrcontentloader.html"
class="external-link" rel="nofollow">Content Loading Bundle Documentation</a>.</p>

<h1><a name="GSoC2010mini-CMSproject-"></a><font color="#003366"><b>Create
new entry</b></font></h1>

<p>There is a script that provide this basic function, <a href="http://code.google.com/p/davidgsoc2010/source/browse/trunk/core/src/main/resources/initial-content/apps/david/new.esp"
class="external-link" rel="nofollow">/apps/david/new.esp</a>. As you can see in David
I choose the ESP scripting language, but as we already said, you can choose among a lot of
scripting engines with Sling. This script loads two other script files, used in every script
of David: <a href="http://code.google.com/p/davidgsoc2010/source/browse/trunk/core/src/main/resources/initial-content/apps/david/header.esp"
class="external-link" rel="nofollow">/apps/david/header.esp</a> and <a href="http://code.google.com/p/davidgsoc2010/source/browse/trunk/core/src/main/resources/initial-content/apps/david/menu.esp"
class="external-link" rel="nofollow">/apps/david/menu.esp</a>. These scripts, as
the name suggests, contain header informations and the menu for David.&nbsp;</p>

<p>In the header there are jQuery functions and CSS definitions, useful for the whole
CMS. In the menu script we can find the definition of a classic menu.</p>

<p>Turning back to the new.esp script, we can see in the following code as header and
menu are loaded, using an ESP function.</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">...
...
&lt;title&gt;David Mini CMS&lt;/title&gt;
&lt;%
load(<span class="code-quote">"header.esp"</span>);
%&gt;

&lt;/head&gt;
&lt;body onload=<span class="code-quote">"checkAuth()"</span>&gt;
	&lt;div id=<span class="code-quote">"lCenter"</span>&gt;
	&lt;div id=<span class="code-quote">"desktop"</span>&gt;
	&lt;%
	load(<span class="code-quote">"menu.esp"</span>);
	%&gt;
	&lt;div id=<span class="code-quote">"contentPanel"</span> class=<span
class="code-quote">"centralPanel"</span>&gt;
...
...
</pre>
</div></div>
<p>So we loaded these two scripts in new.esp. In addition to this, in this script we
defined a simple form, with some input text and a CKEditor panel.&nbsp;</p>

<p>Once the user fills the input, the page is like in the following image</p>

<p><span class="image-wrap" style=""><img src="http://davidgsoc.files.wordpress.com/2010/08/new.png"
style="border: 0px solid black" /></span></p>

<p>The submit button of this page is bounded to a jQuery function defined in the <a
href="http://code.google.com/p/davidgsoc2010/source/browse/trunk/core/src/main/resources/initial-content/apps/david/header.esp"
class="external-link" rel="nofollow">header.esp</a> file. To create a new entry we
have only to create a HTTP POST request, including the informations the user put in the input
texts. The function that create the new entry is the following:</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">......
...
<span class="code-comment">//Function called when there is a click of the
</span><span class="code-comment">//submit button in <span class="code-keyword">new</span>.esp
page
</span>$('#button').click(function() {

    <span class="code-comment">//Retrieve the input texts from the HTML
</span>    <span class="code-keyword">var</span> title = $(<span class="code-quote">"#title"</span>).val();
    <span class="code-keyword">var</span> text = $(<span class="code-quote">"#editor1"</span>).val();
    <span class="code-keyword">var</span> editor_data = CKEDITOR.instances.editor1.getData();
    text=editor_data;
    <span class="code-keyword">var</span> tagValues = $(<span class="code-quote">"#tags"</span>).val();

    <span class="code-comment">//Now create a list with tags
</span>    tagValues=tagValues.split(<span class="code-quote">","</span>);


    <span class="code-keyword">for</span>(<span class="code-keyword">var</span>
i=0; i&lt;tagValues.length; i++) {
	tagValues[i] = tagValues[i].replace(/ /g,'');
    }

    <span class="code-keyword">var</span> token = <span class="code-keyword">new</span>
Array();
    <span class="code-keyword">for</span>(<span class="code-keyword">var</span>
i=0; i&lt;tagValues.length; i++)
		<span class="code-keyword">if</span>(tagValues[i] != "")
			token.push(tagValues[i]);

    <span class="code-comment">//Every information is stored in the <span class="code-quote">"data"</span>
variable
</span>    <span class="code-keyword">var</span> data=<span class="code-quote">"title="</span>+title+<span
class="code-quote">"&amp;text="</span>+text+<span class="code-quote">"&amp;sling:resourceType=david&amp;jcr:mixinTypes=mix:referenceable"</span>;

    <span class="code-keyword">for</span> (<span class="code-keyword">var</span>
j = 0 ; j &lt; token.length ; j++){
		data=data.concat(<span class="code-quote">"&amp;tag="</span>+token[j]);
    }

    <span class="code-comment">//The current date will be used to create the folders
</span>    <span class="code-comment">//in the Sling repository where we will
put the content
</span>    <span class="code-keyword">var</span> currentDate = <span
class="code-keyword">new</span> Date();
    <span class="code-keyword">var</span> year = currentDate.getYear()+1900;
    <span class="code-keyword">var</span> month = currentDate.getMonth()+1;
    <span class="code-keyword">var</span> day = currentDate.getDate()+1;

    <span class="code-keyword">if</span> (month&lt;10)
	month = <span class="code-quote">"0"</span> + month;
    <span class="code-keyword">if</span> (day&lt;10)
	day = <span class="code-quote">"0"</span> + day;


    <span class="code-comment">//The url is under the David root node /content/david
</span>    <span class="code-comment">//created during the initial content loading
</span>    <span class="code-keyword">var</span> url=<span class="code-quote">"/content/david/"</span>+year+<span
class="code-quote">"/"</span>+month+<span class="code-quote">"/"</span>+day+<span
class="code-quote">"/"</span>;

    <span class="code-comment">//Simple AJAX call to create a HTTP POST request
</span>    $.ajax({
	type: <span class="code-quote">"POST"</span>,
	url: url,
	data: data,
	success: function(msg){
		alert(<span class="code-quote">"Entry saved"</span>);
		window.location = <span class="code-quote">"/content/david.html"</span>;
	},
	error: function(msg){
		alert(<span class="code-quote">"Error during save"</span>);
	}
    });
});
...
...
...
</pre>
</div></div>
<p>If we click on the button and everything goes well, we will see a popup with the
text "Entry saved" and our article will be in the repository at the path <em>/content/david/YEAR/MONTH/DAY/somethingliketitle.</em></p>

<p>As you can see, there isn't a definition for the name of the entry but anyway we
will have this entry saved...how is it possible?</p>

<p>The request URL we created is where we would like to insert our entry. If this URL
already exist, we will only update properties of this node (and so you can already understand
that the edit page will be equal to this one).</p>

<p>If the resource doesn't exist, a new item is created. If the resource name ends with
/&#42; or /, the name of the item will be created using an algorith that also uses the
name of new node.</p>

<h1><a name="GSoC2010mini-CMSproject-Authentication"></a>Authentication</h1>

<p>You can submit new entry only if you have already authenticated with Sling. So you
can see that on the <a href="http://code.google.com/p/davidgsoc2010/source/browse/trunk/core/src/main/resources/initial-content/apps/david/menu.esp"
class="external-link" rel="nofollow">/apps/david/menu.esp</a> script there is a check
for the credentials</p>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">......
...
&lt;td width=<span class="code-quote">"33%"</span> align=<span class="code-quote">"right"</span>&gt;
	Logged as: &lt;b id=<span class="code-quote">"username"</span>&gt;????&lt;/b&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;script language=<span class="code-quote">"javascript"</span>&gt;
	<span class="code-keyword">var</span> info = Sling.getSessionInfo();
	<span class="code-keyword">if</span> (info.userID==<span class="code-quote">"anonymous"</span>)
		document.getElementById(<span class="code-quote">"username"</span>).innerHTML
= 
			info.userID+<span class="code-quote">"&lt;a href='/system/sling/form/login?resource=/content/david.html'&gt;Login&lt;/a&gt;"</span>;
	<span class="code-keyword">else</span>
		document.getElementById(<span class="code-quote">"username"</span>).innerHTML
= info.userID;
&lt;/script&gt;
...
...
</pre>
</div></div>
    </div>
        <div id="commentsSection" class="wiki-content pageSection">
        <div style="float: right;">
            <a href="https://cwiki.apache.org/confluence/users/viewnotifications.action"
class="grey">Change Notification Preferences</a>
        </div>
        <a href="https://cwiki.apache.org/confluence/display/SLING/GSoC+2010+mini-CMS+project">View
Online</a>
        |
        <a href="https://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=20316370&revisedVersion=18&originalVersion=17">View
Changes</a>
                |
        <a href="https://cwiki.apache.org/confluence/display/SLING/GSoC+2010+mini-CMS+project?showComments=true&amp;showCommentArea=true#addcomment">Add
Comment</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>

Mime
View raw message