public override bool Render(IInternalContextAdapter context, TextWriter writer, INode node)
		{
			IEngineContext railsContext = EngineContextLocator.Instance.LocateCurrentContext();
			IViewComponentRegistry registry = railsContext.Services.GetService<IViewComponentFactory>().Registry;
			IViewComponentDescriptorProvider viewDescProvider =
				railsContext.Services.GetService<IViewComponentDescriptorProvider>();
			ICacheProvider cacheProvider = railsContext.Services.CacheProvider;

			INode compNameNode = node.GetChild(0);

			if (compNameNode == null)
			{
				String message = String.Format("You must specify the component name on the #{0} directive", Name);
				throw new ViewComponentException(message);
			}

			string componentName = compNameNode.FirstToken.Image;

			if (componentName == null)
			{
				String message = String.Format("Could not obtain component name from the #{0} directive", Name);
				throw new ViewComponentException(message);
			}

			if (componentName.StartsWith("$"))
			{
				String nodeContent = compNameNode.Literal.Trim('"', '\'');
				SimpleNode inlineNode = runtimeServices.Parse(new StringReader(nodeContent), context.CurrentTemplateName, false);

				inlineNode.Init(context, runtimeServices);
				componentName = (string) Evaluate(inlineNode, context);
			}

			IDictionary componentParams = CreateParameters(context, node);

			Type viewComptype = registry.GetViewComponent(componentName);

			ViewComponentDescriptor descriptor = null;
			CacheKey key = null;

			if (viewComptype != null)
			{
				descriptor = viewDescProvider.Collect(viewComptype);
			}

			bool isOutputtingToCache = false;
			ViewComponentCacheBag bag = null;

			if (descriptor != null && descriptor.IsCacheable)
			{
				key = descriptor.CacheKeyGenerator.Create(componentName, componentParams, railsContext);

				if (key != null)
				{
					ViewComponentCacheBag cachedContent = (ViewComponentCacheBag) cacheProvider.Get(key.ToString());

					if (cachedContent != null)
					{
						// Restore entries

						foreach(KeyValuePair<string, object> pair in cachedContent.ContextEntries)
						{
							context[pair.Key] = pair.Value;
						}

						// Render from cache

						writer.Write(cachedContent.Content);

						return true;
					}

					isOutputtingToCache = true;
					bag = new ViewComponentCacheBag();
				}
			}

			ViewComponent component = viewComponentFactory.Create(componentName);

			if (component == null)
			{
				throw new MonoRailException("ViewComponentFactory returned a null ViewComponent for " + componentName + ". " +
				                            "Please investigate the implementation: " + viewComponentFactory.GetType().FullName);
			}

			try
			{
				ASTDirective directiveNode = (ASTDirective) node;
				IViewRenderer renderer = (IViewRenderer) directiveNode.Directive;

				NVelocityViewContextAdapter contextAdapter = new NVelocityViewContextAdapter(componentName, node, viewEngine, renderer);
				contextAdapter.Context = isOutputtingToCache ? new CacheAwareContext(context, bag) : context;

				INode bodyNode = null;

				if (node.ChildrenCount > 0)
				{
					bodyNode = node.GetChild(node.ChildrenCount - 1);
				}

				TextWriter output = isOutputtingToCache ? bag.CacheWriter : writer;

				contextAdapter.BodyNode = bodyNode;
				contextAdapter.ComponentParams = componentParams;
				contextAdapter.TextWriter = output;

				component.Init(railsContext, contextAdapter);

				ProcessSubSections(component, contextAdapter);

				const string ViewComponentContextKey = "viewcomponent";
				object previousComp = context[ViewComponentContextKey];

				try
				{
					context[ViewComponentContextKey] = component;

					component.Render();

					if (contextAdapter.ViewToRender != null)
					{
						RenderComponentView(context, contextAdapter.ViewToRender, output, contextAdapter);
					}

					if (isOutputtingToCache)
					{
						// Save output

						cacheProvider.Store(key.ToString(), bag);

						// Output to correct writer

						writer.Write(bag.Content);
					}
				}
				finally
				{
					if (previousComp != null)
					{
						context[ViewComponentContextKey] = previousComp;
					}
					else
					{
						context.Remove(ViewComponentContextKey);
					}
				}
			}
			finally
			{
				viewComponentFactory.Release(component);
			}

			return true;
		}
		public CacheAwareContext(IInternalContextAdapter context, ViewComponentCacheBag bag)
		{
			this.context = context;
			this.bag = bag;
		}