As a Sitecore developer who is a fan of leveraging Lucene in my projects I've always been aggravated that, starting with Sitecore 6, I couldn't use Luke to view my indexes. As Jens Mikkelsen points out  this was due to custom compression that Sitecore uses for the Lucene index.

To get around these compression issues Jens, and others, have come up with the Index Viewer shared source module and this tool was the only way to help with Sitecore-Lucene indexes. Until now. I've figured out to get around the custom compression and allow Luke to view our indexes!

The breakthrough was based on a comment by Alexy on where we could look into defining our own compression implementation. I started digging through the Lucene code and the answer was right there for us!
Here's the solution.

  1. Go get a copy of SharpZipLib
  2. Grab a copy of Lucene.Net.dll from your Sitecore 6 web root
  3. Grab the code below and add it to your project along with references to the above two dll's
  4. Compile the project and move the resulting DLL and ICSharpCode.SharpZipLib.dll to your Sitecore /bin directory
  5. Update the Web.Config appSetting "Lucene.Net.CompressionLib.class" with your new info
  6. Rebuild your search indexes
  7. Grab the latest Luke and point it at your index


Custom Compression Code (based on this class):

public class SharpZipLibAdapter : SupportClass.CompressionSupport.ICompressionAdapter
{
public byte[] Compress(byte[] input, int offset, int length)
{
// Create the compressor with highest level of compression
Deflater compressor = new Deflater();
compressor.SetLevel(Deflater.BEST_COMPRESSION);

// Give the compressor the data to compress
compressor.SetInput(input, offset, length);
compressor.Finish();

/*
* Create an expandable byte array to hold the compressed data.
* You cannot use an array that's the same size as the orginal because
* there is no guarantee that the compressed data will be smaller than
* the uncompressed data.
*/
MemoryStream bos = new MemoryStream(input.Length);

// Compress the data
byte[] buf = new byte[1024];
while (!compressor.IsFinished)
{
int count = compressor.Deflate(buf);
bos.Write(buf, 0, count);
}

// Get the compressed data
return bos.ToArray();
}

public byte[] Uncompress(byte[] input)
{
Inflater decompressor = new Inflater();
decompressor.SetInput(input);

// Create an expandable byte array to hold the decompressed data
MemoryStream bos = new MemoryStream(input.Length);

// Decompress the data
byte[] buf = new byte[1024];
while (!decompressor.IsFinished)
{
int count = decompressor.Inflate(buf);
bos.Write(buf, 0, count);
}

// Get the decompressed data
return bos.ToArray();
}

public byte[] Compress(byte[] input)
{
// Create the compressor with highest level of compression
Deflater compressor = new Deflater();
compressor.SetLevel(Deflater.BEST_COMPRESSION);

// Give the compressor the data to compress
compressor.SetInput(input);
compressor.Finish();

/*
* Create an expandable byte array to hold the compressed data.
* You cannot use an array that's the same size as the orginal because
* there is no guarantee that the compressed data will be smaller than
* the uncompressed data.
*/
MemoryStream bos = new MemoryStream(input.Length);

// Compress the data
byte[] buf = new byte[1024];
while (!compressor.IsFinished)
{
int count = compressor.Deflate(buf);
bos.Write(buf, 0, count);
}

// Get the compressed data
return bos.ToArray();
}
}

Disclaimer: This was tested with Sitecore 6.2.0.100104

Sitecore Media URL

August 5, 2010

For one of my the latest projects the content editors were always trying to get the actual URL to a Sitecore media library item, but there is no easy way to see this in Sitecore. As developers we know it is in the form of /~/media/[ShortID].ashx or /~/media/[Path].ashx, but editors don't want to think about that. They just want it figured out and displayed in front of them.

What I wanted was something similar to the "Quick Info" section that gives develoeprs/admins a quick view into the important properties of a Sitecore item. This is what I came up with.

This minor change to the editor will allow a user to click on the URL of their choice and copy it to the clipboard.

To add this to your site you need a single class and a change to a pipeline.

/// <summary>
/// The ShowMediaPath class.
/// </summary>
public class ShowMediaInfo
{
private static readonly string SECTION_NAME = "MediaInfo";

/// <summary>
/// Gets a value indicating whether this section is collapsed.
/// </summary>
/// <value>
/// <c>true</c> if this section is collapsed; otherwise, <c>false</c>.
/// </value>
private static bool IsSectionCollapsed
{
get
{
UrlString collapsedSections = new UrlString(Registry.GetString("/Current_User/Content Editor/Sections/Collapsed"));
string value = collapsedSections[SECTION_NAME];
return (string.IsNullOrEmpty(value) || (value == "1"));
}
}

/// <summary>
/// Processes the specified args.
/// </summary>
/// <param name="args">The args.</param>
public void Process(RenderContentEditorArgs args)
{
Item current = args.Item;
if (current != null && current.Template.FullName.StartsWith("System/Media"))
{
MediaItem mediaItem = current;

if (mediaItem != null)
{
bool renderMediaInfo = !IsSectionCollapsed || UserOptions.ContentEditor.RenderCollapsedSections;

args.EditorFormatter.RenderSectionBegin(args.Parent,
"MediaInfo",
SECTION_NAME,
"Quick Info (Media)",
"People/32x32/atom.png",
IsSectionCollapsed,
UserOptions.ContentEditor.RenderCollapsedSections);

if (renderMediaInfo)
{
RenderMediaInfo(args, mediaItem);
}

args.EditorFormatter.RenderSectionEnd(args.Parent, renderMediaInfo, true);
}
}
}

/// <summary>
/// Renders the media info.
/// </summary>
/// <param name="args">The args.</param>
/// <param name="mediaItem">The media item.</param>
private static void RenderMediaInfo(RenderContentEditorArgs args, MediaItem mediaItem)
{
StringBuilder sectionText = new StringBuilder();

sectionText.Append("<table cellpadding=\"4\" cellspacing=\"0\" border=\"0\">");
sectionText.Append("<col style=\"white-space:nowrap\" align=\"right\" valign=\"top\" />");
sectionText.Append("<col style=\"white-space:nowrap\" valign=\"top\" />");

// we will give them absolute URL's
MediaUrlOptions o = new MediaUrlOptions { AbsolutePath = true };

// Get the path of the media item using it's path
o.UseItemPath = true;
sectionText.Append("<tr><td>Url by Path:</td><td>");
sectionText.AppendFormat("<input class=\"scEditorHeaderQuickInfoInput\" readonly=\"readonly\" onclick=\"javascript:this.select();return false\" value=\"{0}\"/>", MediaManager.GetMediaUrl(mediaItem, o));
sectionText.Append("</td></tr>");

// Get the path of the media item using it's ID
o.UseItemPath = false;
sectionText.Append("<tr><td>Url by ID:</td><td>");
sectionText.AppendFormat("<input class=\"scEditorHeaderQuickInfoInput\" readonly=\"readonly\" onclick=\"javascript:this.select();return false\" value=\"{0}\"/>", MediaManager.GetMediaUrl(mediaItem, o));
sectionText.Append("</td></tr>");

// is it File or DB media?
sectionText.Append("<tr><td>Media Location:</td><td>");
sectionText.Append(mediaItem.FileBased ? "File System" : "Database");
sectionText.Append("</td></tr>");

sectionText.Append("</table>");

args.EditorFormatter.AddLiteralControl(args.Parent, sectionText.ToString());
}
}

You will need also to modify a pipeline. I would suggest creating a ShowMediaInfo.config in the /App_Config/Include directory with the following:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<pipelines>
<renderContentEditor>
<processor patch:before="processor[@type='Sitecore.Shell.Applications.ContentEditor.Pipelines.RenderContentEditor.RenderSkinedContentEditor, Sitecore.Client']"
type="NAMESPACE.ShowMediaInfo, ASSEMBLY" />
</renderContentEditor>
</pipelines>
</sitecore>
</configuration>

The idea for this was based on some code that a colleague of mine at Hedgehog Development had written