PowerShell Script

If you’d rather use PowerShell to upgrade mojoPortal, see automatically-updating-mojoportal-using-powershell

I highly recommend using the PowerShell version of the upgrade script, rather than the Java version below, as it’s easier to tailor to your unique needs.

 

Java Auto Upgrade Tool

If you prefer a slightly more automated process than the steps that go into upgrading mojoPortal (as detailed at upgrading-mojo), please feel free to take a look at a little Java Auto Upgrade Tool, MojoRising:

  • Runnable Jar File + Config File (just download, edit the config file, and run)
  • Source Code (eg, to tweak within Eclipse)
  • NOTE:  I make no warranties that the above tool won’t destroy your installation of mojoPortal .  Although it’s simply automating steps described at upgrading-mojo (and is therefore pretty benign, since it won’t overwrite unique files/folders, like your custom skins/documents in your Data folder), there’s no guarantees that something won’t go wrong; therefore, be sure back up your site/files before upgrade.  Anyways, read on for more details!

Description:

Mojo Upgrade

Upgrading mojoPortal, even manually, is a very easy process, since the brunt of the work you must do is copy files from one location to another.  However, if you’re like me and enjoy automating what is to be done more than once, this tool will save you from a bit of mind-numbing work.  Specifically, this tool accomplishes the following tasks, in this order:

  • On opening of the application, the current version of MojoPortal is determined (from CodePlex) and displayed.  This value is compared with the detected version of each site as listed within the config.properties file.
  • Disables set up in user.config and web.config
  • Finds/stores the existing machinekey from web.config in memory to paste back later (so that you don’t have to manually reinsert the machinekey)
  • If an “App_Online.htm” file exists in the root directory, it is renamed to “App_Offline.htm” to tell people app is offline in case they hit the site during upgrade.
  • If “Upgrade Core” is clicked, the tool copies/replaces (using Java FileChannels) files from your predefined source directory to your destination (as pre-filled by selecting one of your sites from the drop down list).  In my own testing, this Java app takes between 1:40 and 2:40 to copy all the files, which is a bit faster than a standard copy/replace using the Windows 7 GUI.  The tool does not delete your entire destination directory before copy; it just overwrites matching file/directories.  Therefore, you still may want to do a clean install from time to time to clear out any older mojo files.
  • If you select a site that already has Form Wizard Pro or Event Calendar Pro installed, you will also see buttons to allow you to copy files the appropriate FWP or ECP files to the destination directory
  • Next the tool adds some styles to ClientScript/mojofckstyles.xml – Where the FCKEditor styles are located.
  • Then MojoRising changes the forms auth cookie from .mojochangeme to whatever you predefine in the config.properties file
  • Next we enable set up in both user.config and web.config
  • Replace the machinekey in the new web.config file with the original machinekey
  • If an “App_Offline.htm” file exists in the root directory, it is renamed to “App_Online.htm”.
  • Now we hit the set up URL for the site: http://www.yoursite.com/setup
  • After 15 seconds we check back at the set up url to see if we can find some completion text which would indicate that the site upgraded successfully.  If it hasn’t we make a few more passes.
  • Once the site has upgraded successfully, we disable set up in web.config and user.config.
  • Finally, we hit the site’s main page to restart the .NET app.

Known Bugs (none I know of, as the following has been fixed)

  • Strangely, I have noticed that occasionally the MemberList.aspx file in the root directory isn’t properly overwritten by the Java app.  I’m still investigating why this occurs, but for now, I simply have a batch file to accomplish the copy after my upgrades are done.  Eg:  

SET COPYCMD=/Y

copy “C:UsersYOURUSERNAMEDocumentsScriptsCMS-Mojobatch-copyMemberList.aspx” “\wsnetcwis248WWWROOTmojoMemberList.aspx”

Features That Could Be Built In If I Or Someone Else Decides It’s Important Enough

  • A bit better error handling
  • Create as an applet
  • Automate the entire thing so that no buttons are to be clicked at all (ie, you open up the jar and it auto-upgrades every single site that’s listed in the config.properties file)
  • Other ideas?

 

Directions:

  1. First download the runnable jar above, or, if you want to tweak the code, the source files.  In this example we’ll be using the runnable jar.
  2. Open the accompanying “config.properties” file using your text-editor of choice, like HTML Kit or even Note Pad.
  3. Edit the settings of the config file according to your needs.  Eg, specify a default source folder for mojoPortal (the folder you’ll be copying from).  Also, if you have multiple sites, it’s helpful to specify your site names (for display in the dropdown), site paths (UNC path or other path to the server where mojo resides), and the root url of your site (eg, http://www.yoursite.com).  Also add your site’s cookie names for forms authentication.  You may also want to predefine a default source folder for Form Wizard Pro or Event Calendar Pro
  4. Next, open the jar file, select your site, and click “Upgrade Core” to upgrade Mojo.  Everything else should be taken care of automatically.

 

An example of one of the classes I used for the tool is shown below (the meat of the application):

WorkMojo class:

import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileSystemView;
import java.awt.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.LinkedList;
import java.util.List;

public class WorkMojo extends JPanel {

//Attributes
private static final String DEFAULT_SOURCE = “C:\Users\sgeisert.SC\Documents\MojoRelease”;
private static final String DEFAULT_DESTINATION = “O:\”;
private static final int BUFFER = 1024 * 1024;

private JFileChooser chooseFile;
private File filSource;
private File filDestination;
private static String initialDestination;
private DefaultListModel listModelFiles;
//private static String setupFolder = AppConfig.getSiteInfo().get(“Test Server”).getSiteURL() + AppConfig.getMojoSetupFolder();
private static String setupFolder = AppConfig.getSiteInfo().get(Util.getKey()).getSiteURL() + AppConfig.getMojoSetupFolder();
private static boolean isCoreUpgrade;

private JProgressBar progressBar;
private int progressValue;

public static AppConfig config;

/**
* Get/sets
* @return
*/
public static void setInitialDestination(String initialDestination) {
WorkMojo.initialDestination = initialDestination;
}

public static String getInitialDestination() {
return initialDestination;
}

/**
* FileCopy constructor, requires source, destination directories
* and type of upgrade
* @param pSrcDir
* @param pDestDir
* @param pIsCoreUpgrade
*/
public WorkMojo(File pSrcDir, File pDestDir, boolean pIsCoreUpgrade) {

super(new BorderLayout(0, 5));

//Set upgrade type
isCoreUpgrade = pIsCoreUpgrade;

//Set up file chooser
chooseFile = new JFileChooser(pSrcDir);
chooseFile.setFileFilter(new FileFilter() {
public boolean accept(File f) {
return true;
}

public String getDescription() {
return “all files”;
}
});

//Set destination directory and get paths
filDestination = pDestDir;

//check if destination directory needs to be created
if (!filDestination.exists())
{
filDestination.mkdir();
}

//used to create a list of files
listModelFiles = new DefaultListModel();

//create an array of files from directory
File[] files = pSrcDir.listFiles();

//add files to vector model
for (int i = 0; i < files.length; i++) {
listModelFiles.addElement(files[i]);
}

//create thread to do copy
Runnable runner = new Runnable() {
public void run() {
onCopy();
}
};
new Thread(runner).start(); //Start thread on copy

//Add GUI objects related to file copy object
JList list = new JList(listModelFiles);
list.setCellRenderer(new FileCellRenderer());
add(new JScrollPane(list), BorderLayout.CENTER);
progressBar = new JProgressBar(JProgressBar.HORIZONTAL);
progressBar.setStringPainted(true);
progressBar.setString(“Ready”);
add(progressBar, BorderLayout.SOUTH);
}

/**
* onCopy is ran by separate thread to initiate copy process,
* including setting up folders
*/
private void onCopy() {

//for linked list of files
List<File> files = new LinkedList<File>();

//# elements in model
int size = listModelFiles.size();

//used to build size of transfer
int totalSize = 0;

//for each file in model,
for (int i = 0; i < size; i++) {
filSource = (File)listModelFiles.elementAt(i);
File destFile = new File(filDestination, filSource.getName());

//check is file
if (filSource.isFile()) {

//If so, add to size of transfer
totalSize += filSource.length();

//add file to linked list of files
files.add(filSource);

// uncomment below code to NOT overwrite existing files
// if (!destFile.isFile()) {
// totalSize += sourceFile.length();
// files.add(sourceFile);
// }
}
else //we have a folder, so we’ll have to mkdirs first
{
try {
copyFolder(filSource, destFile);
} catch (IOException e) {
e.printStackTrace();
}
}
}

//initialize progressbar and set max to transfer size
progressBar.setMinimum(0);
progressBar.setMaximum(totalSize);
progressBar.setValue(0);
progressValue = 0;

//iterate through linked list and copy files
try {
for (int i = 0; i < files.size(); i++) {
filSource = (File)files.get(i);

copyFile(filSource, new File(filDestination, filSource.getName()));
}

//reset progressbar
progressBar.setString(“Ready”);
progressBar.setValue(0);

//Function to handle post copy work
doFinalSetup(isCoreUpgrade);

} catch (IOException e) {
e.printStackTrace();
}

}

/**
* Based on whether or not this is an update to the core, perform various
* post copy tasks, including enabling set up, hitting the set up URL,
* then changing web.config/user.config’s DisableSetup options back to true
* @param pIsCoreUpgrade
*/
public void doFinalSetup(boolean pIsCoreUpgrade)
{
if (pIsCoreUpgrade)
{
//Copy is complete for core upgrade, now configure styles
configureStyles();

//Change the cookie name in web.config to the cookie referenced by the chosen key
changeAuthCookie(AppConfig.getSiteInfo().get(Util.getKey()).getSiteCookie());
}

//Enable setup in user.config after copy is complete
//(because we are going to hit the set up page now)
//Result: <add key=”DisableSetup” value=”false” />
disableSetup(false, AppConfig.getUserConfigFile());
//Enable set up in web.config
disableSetup(false, “web.config”);

//Hit set up page
Browser.displayURL(setupFolder);
//Once set up’s complete, disable set up in both user/web.config
if (isSetupComplete())
{
//Disable set up in user.config
disableSetup(true, AppConfig.getUserConfigFile());
//Disable set up in web.config
disableSetup(true, “web.config”);

//Hit main url just to restart the app
Browser.displayURL(AppConfig.getSiteInfo().get(Util.getKey()).getSiteURL());
}
else
{
JOptionPane.showMessageDialog(null, “Site set up did NOT complete successfully. Please check your set up.”);
}
}

/**
* Little timing function to check a web page to see if the actual set up
* has completed
* @return
*/
public boolean isSetupComplete(){

boolean tmp;

//Waiting a few seconds for the setup utility to run.
//15 seconds was enough of a wait for my set up
Util.wait(15);

//Make a few passes to check if set up is complete
for (int i = 0; i < 6; i++) {

//Fetch contents of Setup URL, parse the HTML, and
//and check presence of completion text, “Your installation is up to date.”
//If it’s there, we know we made it
tmp = ReadURL.contains(setupFolder, AppConfig.getMojoSetupComplete());

//We’re done, return true
if (tmp)
{
return true;
}

//Wait 5 seconds and try again
Util.wait(5);
}

//Looks like we didn’t make it.
return false;
}

/**
* creates folders
* @param pSrcDir
* @param pDestDir
* @throws IOException
*/
public void copyFolder(File pSrcDir, File pDestDir) throws IOException
{
if (pSrcDir.isDirectory())
{
if (! pDestDir.exists())
{
pDestDir.mkdir();
//pDestDir.setExecutable(true);
}

String[] subFiles = pSrcDir.list();

for (int i=0; i < subFiles.length; i++)
{
copyFolder(new File(pSrcDir, subFiles[i]), new File(pDestDir, subFiles[i]));
}
}
else //dealing w/ a file from source
{
if(pDestDir.isDirectory())
{
copyFile(pSrcDir, new File(pDestDir, pSrcDir.getName()));
}
else //Destination is a file
{
//If the file exists at the destination, delete it before copying
if (pDestDir.exists())
{
pDestDir.delete();
}
copyFile(pSrcDir, pDestDir);
}
}
}

/**
* copyFile – where heavy lifting is done
* @param pInputFile
* @param pOutputFile
* @throws IOException
*/
private void copyFile(File pInputFile, File pOutputFile) throws IOException {

//set up file channel object
FileChannel inputFile = null;
FileChannel outputFile = null;

try {
//Provide feedback to user
progressBar.setString(“Copying ” + pInputFile.getName());
int fileLength = (int)pInputFile.length();
int piece = fileLength / BUFFER;
int remainder = fileLength % BUFFER;
final int[] pieces;

//set up buffer
if (remainder != 0) {
pieces = new int[piece + 1];
pieces[piece] = remainder;
} else {
pieces = new int[piece];
}

for (int i = 0; i < piece; i++) {
pieces[i] = BUFFER;
}

//Do copy and update progress value along the way
outputFile = new FileOutputStream(pOutputFile, true).getChannel();
inputFile = new FileInputStream(pInputFile).getChannel();
int location = 0;
for (int i = 0; i < pieces.length; i++) {
outputFile.transferFrom(inputFile, location, pieces[i]);
location += pieces[i];
progressValue += pieces[i];
updateProgressBar();
}
} finally { //close file stream
if (outputFile != null) {
outputFile.close();
}
if (inputFile != null) {
inputFile.close();
}
}
}

/**
* Handles updating of progress bar’s value
*/
private void updateProgressBar() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
progressBar.setValue(progressValue);
}
});
}

/**
* Enables/disables Setup in User.Config or Web.Config
*
* @param pStartVal
* @param pEndVal
* @param pInWhatFile
*/
public static void disableSetup(boolean pValue, String pInWhatFile){
try {
new FileEdit(getInitialDestination() + pInWhatFile,
“<add key=”” + AppConfig.getSetupKey() + “” value=”” + !pValue + “” />”,
“<add key=”” + AppConfig.getSetupKey() + “” value=”” + pValue + “” />”);
}
catch (Exception e) {
e.printStackTrace();
}
}

/**
* Changes cookie from default value in web.config
* @param pNewCookie
*/
public static void changeAuthCookie(String pNewCookie){
try {
new FileEdit(getInitialDestination() + “web.config”,
AppConfig.getMojoSiteCookie(),
pNewCookie);
}
catch (Exception e) {
e.printStackTrace();
}
}

/**
* /Deletes web.config file on server (destination)
* @return
*/
public static boolean deleteWebConfig()
{
File tmp = new File(getInitialDestination() + “web.config”);

return tmp.delete();
}

/**
* Configure styles in xml file
*/
public void configureStyles(){
try {
new FileEdit(getInitialDestination() + “ClientScript\mojofckstyles.xml”,
“<Style name=”Heading 1″ element=”h3″ /> <Style name=”Heading 2″ element=”h4″ /> <Style name=”Heading 3″ element=”h5″ />”,
“<Style name=”Heading 1″ element=”h1″ /> <Style name=”Heading 2″ element=”h2″ /> <Style name=”Heading 3″ element=”h3″ /> <Style name=”Heading 4″ element=”h4″ /> <Style name=”Heading 5″ element=”h5″ />”);
}
catch (Exception e) {
e.printStackTrace();
}
}

/**
* Only install FWP if it exists at the destination. This function checks that
* @return
*/
public static boolean checkFormWizardPro(){

return (new File(getInitialDestination() + AppConfig.getFWPfolder()).exists());
}

/**
* Only install ECP if it exists at the destination
* @return
*/
public static boolean checkEventCalendarPro(){

return (new File(getInitialDestination() + AppConfig.getECPfolder()).exists());
}

//Shows table of inputted files
private static class FileCellRenderer extends DefaultListCellRenderer {
private FileSystemView theFileSystemView;

public FileCellRenderer() {
super();
theFileSystemView = FileSystemView.getFileSystemView();
}

public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (!(value instanceof File)) return this;
File file = (File)value;
setText(file.getAbsolutePath());
setIcon(theFileSystemView.getSystemIcon(file));
return this;
}
}

/**
* For testing this class
* @param args
*/
public static void main(String[] args) {
final JFrame frame = new JFrame(“Mojo File Copy”);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setContentPane(new WorkMojo(new File(DEFAULT_SOURCE), new File(DEFAULT_DESTINATION), false));
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.pack();
frame.setVisible(true);
}
});
}
}