001 /*
002 * Copyright 2008-2016 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package griffon.builder.core.factory
017
018 import griffon.core.ApplicationEvent
019 import griffon.core.GriffonApplication
020 import griffon.core.RunnableWithArgs
021 import griffon.core.mvc.MVCGroup
022 import org.codehaus.griffon.runtime.groovy.mvc.GroovyAwareMVCGroup
023
024 import javax.annotation.Nullable
025
026 import static org.codehaus.griffon.runtime.groovy.mvc.GroovyAwareMVCGroup.CURRENT_MVCGROUP
027
028 /**
029 * Enables MVC groups to be used as component nodes
030 *
031 * @author Andres Almiray
032 * @author Alexander Klein
033 */
034 @SuppressWarnings("rawtypes")
035 class MetaComponentFactory extends AbstractFactory {
036 Object newInstance(FactoryBuilderSupport builder, Object name, Object value, Map attributes) {
037 Map attrs = resolveAttributes(attributes)
038 String mvcId = resolveMvcId(name, value, attrs)
039 Map mvcArgs = resolveMvcArgs(attrs)
040 Map mvcArgsCopy = [*:mvcArgs]
041 attributes.clear()
042 attributes.putAll(attrs)
043
044 MVCGroup parentGroup = builder.getVariables().get(CURRENT_MVCGROUP)
045 def receiver = parentGroup ?: builder.application.mvcGroupManager
046 MVCGroup mvcGroup = receiver.createMVCGroup(mvcType, mvcId, mvcArgs)
047 def root = mvcGroup.rootNode
048
049 new DestroyEventHandler(mvcId, mvcGroup, builder.application)
050
051 builder.context.root = root
052 builder.context.mvcGroup = mvcGroup
053 builder.context.mvcArgs = mvcArgsCopy
054 root
055 }
056
057 protected Map resolveAttributes(Map attributes) {
058 attributes
059 }
060
061 protected String resolveMvcId(Object name, Object value, Map attributes) {
062 String mvcType = ''
063 if (value != null && value instanceof CharSequence) {
064 mvcType = value.toString()
065 } else {
066 throw new IllegalArgumentException("In $name value must be an MVC group type")
067 }
068
069 return attributes.containsKey('mvcId') ? attributes.remove('mvcId') : mvcType
070 }
071
072 protected Map resolveMvcArgs(Map attributes) {
073 attributes.remove('mvcArgs') ?: [:]
074 }
075
076 private static class DestroyEventHandler implements RunnableWithArgs {
077 private final String parentId
078 private final MVCGroup childGroup
079 private final GriffonApplication application
080
081 DestroyEventHandler(String parentId, MVCGroup childGroup, GriffonApplication application) {
082 this.parentId = parentId
083 this.childGroup = childGroup
084 this.application = application
085 application.eventRouter.addEventListener(ApplicationEvent.DESTROY_MVC_GROUP.name, this)
086 }
087
088 @Override
089 void run(@Nullable Object... args) {
090 Object destroyedGroup = args[0]
091 if (destroyedGroup.mvcId == parentId) {
092 childGroup.destroy()
093 application.eventRouter.removeEventListener(ApplicationEvent.DESTROY_MVC_GROUP.name, this)
094 }
095 }
096 }
097
098 boolean onHandleNodeAttributes(FactoryBuilderSupport builder, Object node, Map attributes) {
099 try {
100 return builder.context.mvcGroup.controller.metaClass.invokeMethod(builder.context.mvcGroup.controller, 'onHandleNodeAttributes', builder, node, attributes)
101 } catch (MissingMethodException e) {
102 return false
103 }
104 }
105
106 boolean onNodeChildren(FactoryBuilderSupport builder, Object node, Closure childContent) {
107 def root = builder.context.root
108 builder = builder.context.mvcGroup.builder
109 Closure handleChildContent = builder.getVariables().get('handleChildContent')
110 if (handleChildContent != null) {
111 handleChildContent(childContent)
112 } else {
113 builder.container(root, childContent)
114 }
115 false
116 }
117
118 boolean isHandlesNodeChildren() {
119 false
120 }
121
122 @Override
123 void setChild(FactoryBuilderSupport builder, Object parent, Object child) {
124 safeInvoke(builder.parentContext.mvcGroup.builder, 'setChild', builder, parent, child)
125 }
126
127 @Override
128 void setParent(FactoryBuilderSupport builder, Object parent, Object child) {
129 safeInvoke(builder.context.mvcGroup.builder, 'setParent', builder, parent, child)
130 }
131
132 @Override
133 void onNodeCompleted(FactoryBuilderSupport builder, Object parent, Object node) {
134 safeInvoke(builder.context.mvcGroup.builder, 'onNodeCompleted', builder, parent, node)
135 }
136
137 static protected def safeInvoke(Object obj, String method, Object... args) {
138 try {
139 return obj.metaClass.invokeMethod(obj, method, args)
140 } catch (MissingMethodException e) {
141 return null
142 }
143 }
144 }
|