001 /*
002 * Copyright 2008-2017 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
023 import javax.annotation.Nullable
024
025 import static org.codehaus.griffon.runtime.groovy.mvc.GroovyAwareMVCGroup.CURRENT_MVCGROUP
026
027 /**
028 * Enables MVC groups to be used as component nodes
029 *
030 * @author Andres Almiray
031 * @author Alexander Klein
032 */
033 @SuppressWarnings("rawtypes")
034 class MetaComponentFactory extends AbstractFactory {
035 Object newInstance(FactoryBuilderSupport builder, Object name, Object value, Map attributes) {
036 Map attrs = resolveAttributes(attributes)
037 String mvcId = resolveMvcId(name, value, attrs)
038 Map mvcArgs = resolveMvcArgs(attrs)
039 Map mvcArgsCopy = [*:mvcArgs]
040 attributes.clear()
041 attributes.putAll(attrs)
042
043 MVCGroup parentGroup = builder.getVariables().get(CURRENT_MVCGROUP)
044 def receiver = parentGroup ?: builder.application.mvcGroupManager
045 MVCGroup mvcGroup = receiver.createMVCGroup(mvcType, mvcId, mvcArgs)
046 def root = mvcGroup.rootNode
047
048 new DestroyEventHandler(mvcId, mvcGroup, builder.application)
049
050 builder.context.root = root
051 builder.context.mvcGroup = mvcGroup
052 builder.context.mvcArgs = mvcArgsCopy
053 root
054 }
055
056 protected Map resolveAttributes(Map attributes) {
057 attributes
058 }
059
060 protected String resolveMvcId(Object name, Object value, Map attributes) {
061 String mvcType = ''
062 if (value != null && value instanceof CharSequence) {
063 mvcType = value.toString()
064 } else {
065 throw new IllegalArgumentException("In $name value must be an MVC group type")
066 }
067
068 return attributes.containsKey('mvcId') ? attributes.remove('mvcId') : mvcType
069 }
070
071 protected Map resolveMvcArgs(Map attributes) {
072 attributes.remove('mvcArgs') ?: [:]
073 }
074
075 private static class DestroyEventHandler implements RunnableWithArgs {
076 private final String parentId
077 private final MVCGroup childGroup
078 private final GriffonApplication application
079
080 DestroyEventHandler(String parentId, MVCGroup childGroup, GriffonApplication application) {
081 this.parentId = parentId
082 this.childGroup = childGroup
083 this.application = application
084 application.eventRouter.addEventListener(ApplicationEvent.DESTROY_MVC_GROUP.name, this)
085 }
086
087 @Override
088 void run(@Nullable Object... args) {
089 Object destroyedGroup = args[0]
090 if (destroyedGroup.mvcId == parentId) {
091 childGroup.destroy()
092 application.eventRouter.removeEventListener(ApplicationEvent.DESTROY_MVC_GROUP.name, this)
093 }
094 }
095 }
096
097 boolean onHandleNodeAttributes(FactoryBuilderSupport builder, Object node, Map attributes) {
098 try {
099 return builder.context.mvcGroup.controller.metaClass.invokeMethod(builder.context.mvcGroup.controller, 'onHandleNodeAttributes', builder, node, attributes)
100 } catch (MissingMethodException e) {
101 return false
102 }
103 }
104
105 boolean onNodeChildren(FactoryBuilderSupport builder, Object node, Closure childContent) {
106 def root = builder.context.root
107 builder = builder.context.mvcGroup.builder
108 Closure handleChildContent = builder.getVariables().get('handleChildContent')
109 if (handleChildContent != null) {
110 handleChildContent(childContent)
111 } else {
112 builder.container(root, childContent)
113 }
114 false
115 }
116
117 boolean isHandlesNodeChildren() {
118 false
119 }
120
121 @Override
122 void setChild(FactoryBuilderSupport builder, Object parent, Object child) {
123 safeInvoke(builder.parentContext.mvcGroup.builder, 'setChild', builder, parent, child)
124 }
125
126 @Override
127 void setParent(FactoryBuilderSupport builder, Object parent, Object child) {
128 safeInvoke(builder.context.mvcGroup.builder, 'setParent', builder, parent, child)
129 }
130
131 @Override
132 void onNodeCompleted(FactoryBuilderSupport builder, Object parent, Object node) {
133 safeInvoke(builder.context.mvcGroup.builder, 'onNodeCompleted', builder, parent, node)
134 }
135
136 static protected def safeInvoke(Object obj, String method, Object... args) {
137 try {
138 return obj.metaClass.invokeMethod(obj, method, args)
139 } catch (MissingMethodException e) {
140 return null
141 }
142 }
143 }
|