cancel
Showing results for 
Search instead for 
Did you mean: 

Automatic site creation : surf-config not generated

tonyrivet
Champ in-the-making
Champ in-the-making
Hi everyone,

I would like to create a workflow task which could automatically create a Share site on transition.

I have created a Java JBPM action (extending JBPMSpringActionHandler), executed in my workflow task transition.
As the site pages creation must be done on the Share side, this action simply makes a remote call to the create site Share module:

   
RemoteClient remote = new RemoteClient(); 
   remote.setEndpoint("http");
   remote.setRequestMethod(HttpMethod.POST);
   remote.setRequestContentType("application/json");
   remote.setTicket(ticket);
                  
   Map<String, String> properties = new HashMap<String, String>();
   properties.put("shortName", siteShortName);
   properties.put("sitePreset", sitePreset);
   properties.put("title", siteTitle);
   properties.put("description", siteDesc);
   properties.put("visibility", "PUBLIC");
   properties.put("ticket", ticket);

   JSONObject json = new JSONObject(properties);
                  
   Response response = remote.call("http://localhost:8080/share/service/modules/create-site", json.toString());

I have also extended the create-site module to forward the session ticket to the site creation request:

   if(clientJSON.ticket)
   {
      repoResponse = scriptRemoteConnector.post("/api/sites?alf_ticket="+clientJSON.ticket, clientRequest, "application/json");
   }
   else
   {
      repoResponse = scriptRemoteConnector.post("/api/sites", clientRequest, "application/json");
   }

The action is executed well and the site seems to be correctly created : it appears in the sites list and I can access to the site pages.
However, the created "st:site" node does not contain the surf configuration ("surf-config" node) useful to access the site pages, which must be generated when calling the
"sitedata.newPreset()" method in the module…
And indeed, after restarting the server, the site is not accessible anymore…

It's quite weird because I think I am doing exaclty the same way as a manual site creation (i.e. calling the create-site Share module), and the manual site creation is working perfectly.

So I would like to know if someone has a clue on why the "surf-config" node isn't generated ?
All information about automatic site creation is welcomed !

Thank you in advance.
10 REPLIES 10

jpotts
World-Class Innovator
World-Class Innovator
Is your process running within jBPM embedded within Alfresco? If so, why wouldn't you just use the SiteService to create the site? It's available as a root object to jBPM JavaScript.

Or if you want to do it in Java you could just inject the SiteService into your class and use it from there.

If you're running remotely (like in your own standalone jBPM engine) then just call a custom web script and within the web script use the SiteService to create the site.

This approach ensures that you are using supported API.

Jeff

tonyrivet
Champ in-the-making
Champ in-the-making
Thank you for your answer.

I already tried to use the SiteService to create my site but it only creates the st:site node and does not create the site pages. This is done by calling the sitedata.newPreset() method on the Share tier, as you reported yourself on this JIRA : https://issues.alfresco.com/jira/browse/ALF-4771.

That is why I make a remote call to the create-site Share module, which is meant to ensure the site creation and the surf config generation.
The workaround you published seems to work, but as some developers have commented on the JIRA, the site is not accessible anymore after restarting Alfresco…
The reason is the surf-config node is not created under the st:site node…

Have you any clue to explain this behaviour ?
Maybe this new issue comes with Alfresco 4.0 ? Or maybe I am misunderstanding some part of the process…

Tony

jpotts
World-Class Innovator
World-Class Innovator
I don't, sorry!

Jeff

joemc3
Champ in-the-making
Champ in-the-making
I'm seeing the exact same behavior. 

However, I also tried posting to create-site.post.json.js using POSTER (firefox plugin) using the standard json formatted object and this worked and created the surf-config, which allowed the site to continue working after a server reboot.

I cannot figure out why posting to create-site.post.json.js through my code is not working but posting through POSTER is working.

joemc3
Champ in-the-making
Champ in-the-making
Ok.  I figured this out. 

[Jeff Potts edited this post to remove an unnecessary/insulting text]

Thank you Martin Bergljung for your well written website at (http://ecmstuff.blogspot.com/2012/03/creating-alfresco-share-sites-with.html?showComment=13500713867...).  The key to solving this problem was in his website.

Basically, I did everything suggested in this posting and several other postings.  I was getting the same results.  The surf-config was not being generated and the site wouldn't persist through a reboot.  I could then call sitedata.newPreset() again, which would re-enable the website, but it would always be unavailable after a reboot. 

I found the key in Martin's article.  He makes a call to DOLOGIN, which I couldn't find documented anywhere, to retrieve the JSESSIONID.  He then posts his call to create-site.post.json.js passing this JSESSIONID as a cookie in the header.  With the exception of using the JSESSIONID in the header of the post, the code was identical to what was used in this article and several other articles.  Oh, one other note:  Some articles required the create-site.post.json.js to be modified to pass the alf-ticket parameter to the site api.  I found that I did not need to modify the create-site.post.json.js code.  It worked fine out of the box.

Here is my code.  It's not finalized production code, but it demonstrates how the process works.  This code was written in C# for a .Net windows form.  The form has a text box which contains the URL of the alfresco site, the username and the password to the alfresco site.  The user clicks a login button to make the connection and set the alf-ticket and the JSESSIONID.  The user then fills out a series of other boxes to identify the site title, name, description and visibility.  They then click the create site button to create the site.  Although it really doesn't matter here, my alfresco test sites are all hosted on Amazon EC2.

Here is the code.  I hope it helps someone.


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using httpsclient;
using System.Net;
using System.IO;
using System.Web.Script.Serialization;
using System.Configuration;

namespace AlfrescoLoader
{
    public partial class Form1 : Form
    {
        string BaseURI;
        string JSESSIONID = "";
        string Ticket = "";

        public Form1()
        {
            InitializeComponent();
            txtAlfrescoURL.Text = "http://" + ConfigurationSettings.AppSettings["DefaultURL"];
            txtUsername.Text = ConfigurationSettings.AppSettings["DefaultUsername"];
            txtPassword.Text = ConfigurationSettings.AppSettings["DefaultPassword"];
            ddSiteVisibility.SelectedIndex = 0;
        }

        private Boolean AddSite(string Ticket, string SiteTitle, string SiteName, string SiteDescription, string SiteVisibility)
        {
            try
            {
                // Set the json that will define the site.
                string MySite = @"{""visibility"":""" + SiteVisibility + @""",""sitePreset"":""site-dashboard"",""title"":""" +
                    SiteTitle + @""",""description"":""" + SiteDescription + @""",""shortName"":""" +
                    SiteName + @""",""ticket"":""" + Ticket + @"""}";

                // set the url that we will call.
                string uri = BaseURI + "/share/service/modules/create-site";

                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
                req.ContentType = "application/json";
                req.Accept = "application/json";
                req.Method = "POST";
                req.Headers["Cookie"] = "JSESSIONID=" + JSESSIONID;  //set the cookie to contain the JSESSIONID we retrieved earlier.

                using (Stream stm = req.GetRequestStream())
                {
                    using (StreamWriter stmw = new StreamWriter(stm))
                    {
                        stmw.Write(MySite);
                    }
                }

                HttpWebResponse response = (HttpWebResponse)req.GetResponse();

                Stream stream = response.GetResponseStream();
                string json = "";

                using (StreamReader reader = new StreamReader(stream))
                {
                    while (!reader.EndOfStream)
                    {
                        json += reader.ReadLine();
                    }
                }
                stream.Close();
            }
            catch
            {
                return false;
            }
            return true;
        }

        private string GetLoginTicket(string Username, string Password)
        {
            string uri = BaseURI + "/alfresco/service/api/login";
            string Params = @"{""username"":""" + Username + @""",""password"":""" + Password + @"""}";

            CookieContainer cc = new CookieContainer();
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
            req.ContentType = "application/json";
            req.CookieContainer = cc;
            req.Method = "POST";

            using (Stream stm = req.GetRequestStream())
            {
                using (StreamWriter stmw = new StreamWriter(stm))
                {
                    stmw.Write(Params);
                }
            }

            HttpWebResponse res = (HttpWebResponse)req.GetResponse();

            if (res == null)
                return "Login Failed!";

            Stream stream = res.GetResponseStream();
            string json = "";

            using (StreamReader reader = new StreamReader(stream))
            {
                while (!reader.EndOfStream)
                {
                    json += reader.ReadLine();
                }
            }

            res.Close();

            JavaScriptSerializer serializer = new JavaScriptSerializer();
            Dictionary<string, object> datajson = (Dictionary<string, object>)serializer.DeserializeObject(json);
            Dictionary<string, object> Ticketjson = (Dictionary<string, object>)datajson["data"];
            string Ticket = Ticketjson["ticket"].ToString();
            return Ticket;
        }

        private string DoLogin(string Username, string Password)
        {
            string uri = BaseURI + "/share/page/dologin";
            string logintext = "username=" + Username + "&password=" + Password;

            CookieContainer cc = new CookieContainer();
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
            req.ContentType = "application/x-www-form-urlencoded";  // Posting form data
            req.CookieContainer = cc;
            req.Method = "POST";

            using (Stream stm = req.GetRequestStream())
            {
                using (StreamWriter stmw = new StreamWriter(stm))
                {
                    stmw.Write(logintext);
                }
            }

            HttpWebResponse response = (HttpWebResponse)req.GetResponse();

            // Look through the returned cookies and find the one named "JSESSIONID"
            foreach (Cookie cook in req.CookieContainer.GetCookies(req.RequestUri))
            {
                if (cook.Name.ToString() == "JSESSIONID")
                    return cook.Value.ToString();
            }
            return null;
        }

        private void btnLogin_Click(object sender, EventArgs e)
        {
            BaseURI = txtAlfrescoURL.Text;  //This gets the base URL from a textbox on the form.

            JSESSIONID = DoLogin(txtUsername.Text, txtPassword.Text);  // This will retrieve the JSESSIONID
           
            Ticket = GetLoginTicket(txtUsername.Text, txtPassword.Text);  // This will get my login ticket.

            // show a message on the form to indicate if I logged in successfully or not.
            lblLoginStatus.Text = Ticket;
            if (lblLoginStatus.Text.Substring(0, 6) != "TICKET")
            {
                lblLoginStatus.ForeColor = Color.Red;
            }
            else
            {
                lblLoginStatus.ForeColor = Color.Green;
                lblLoginStatus.Text = "Login Successful! " + lblLoginStatus.Text;
            }
        }

        private void btnCreateSite_Click(object sender, EventArgs e)
        {
            BaseURI = txtAlfrescoURL.Text;
            if (Ticket.Substring(0, 6) != "TICKET")
            {
                lblCreateSiteResults.Text = "Not logged in!";
                lblCreateSiteResults.ForeColor = Color.Red;
            }

            if (txtSiteTitle.Text.Length == 0 || txtSiteName.Text.Length == 0 || txtSiteDescription.Text.Length == 0)
            {
                lblCreateSiteResults.Text = "Must fill in Site Title, Name and Description!";
                lblCreateSiteResults.ForeColor = Color.Red;
            }

            Boolean ReturnStatus = AddSite(Ticket, txtSiteTitle.Text, txtSiteName.Text, txtSiteDescription.Text, ddSiteVisibility.SelectedItem.ToString());
            if (ReturnStatus)
            {
                lblCreateSiteResults.Text = "Site " + txtSiteName.Text + " created successfully!";
                lblCreateSiteResults.ForeColor = Color.Green;
            }
            else
            {
                lblCreateSiteResults.Text = "Failed to Create Site";
                lblCreateSiteResults.ForeColor = Color.Red;
            }
        }

    }
}

ahmedsyscs
Champ in-the-making
Champ in-the-making
Thanks joemc3, this worked for me, except I did not need the second login to retrieve an alf_ticket. By logging in to share only and using the JSESSIONID, it was enough of a credential to invoke the create-site script.

Again thanks: your code was very helpful (I implemented in Java).

np13223
Champ in-the-making
Champ in-the-making
Can you submit/share the java implementation?

bug_develop
Champ in-the-making
Champ in-the-making
MY FIRST POST! My Java IMPLEMENTATION! I've used Apache HttpClient 4.2.5 (GA)

<java>
import java.util.ArrayList;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

public class TestShareCreateSitePost {

   public static void main(String[] args) throws Exception {
      System.out.println(createSite());
   }

   private static String createSite() {
      try {
         DefaultHttpClient client = new DefaultHttpClient();
         HttpPost post = new HttpPost(
               "http://localhost:8080/share/page/dologin");
         List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
         nameValuePairs.add(new BasicNameValuePair("username", "admin"));
         nameValuePairs.add(new BasicNameValuePair("password", "admin"));
         post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
         client.execute(post);
         CookieStore cookieStore = client.getCookieStore();
         client = new DefaultHttpClient();
         client.setCookieStore(cookieStore);
         post = new HttpPost(
               "http://localhost:8080/share/service/modules/create-site");
         post.setHeader("Content-Type", "application/json");
         post.setEntity(new StringEntity(createSiteParameters(
               "JavaTest-001", "Sito di test by JAVA", "JavaTest-001"),
               "UTF-8"));
         ResponseHandler<String> responseHandler = new BasicResponseHandler();
         String response = client.execute(post, responseHandler);
         return response;
      } catch (Exception e) {
         e.printStackTrace();
      }
      return "Error!";
   }

   private static String createSiteParameters(String title,
         String description, String shortName) {
      String site = "{\"visibility\":\"PRIVATE\", "
            + "\"sitePreset\":\"site-dashboard\", " + "\"title\":\""
            + title + "\", " + "\"description\":\"" + description + "\", "
            + "\"shortName\":\"" + shortName + "\"}";
      System.out.println(site);
      return site;
   }
}
</java>

ishaan
Champ in-the-making
Champ in-the-making
Can you please post the java implementation, it will be helpful…!!