001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Rodrigo Westrupp
028: */
029:
030: package com.caucho.amber.field;
031:
032: import com.caucho.amber.type.RelatedType;
033: import com.caucho.config.ConfigException;
034: import com.caucho.java.JavaWriter;
035: import com.caucho.log.Log;
036: import com.caucho.util.L10N;
037:
038: import javax.persistence.CascadeType;
039: import java.io.IOException;
040: import java.util.logging.Level;
041: import java.util.logging.Logger;
042:
043: /**
044: * A child field that is cascadable from parent to child
045: * on persist, merge, remove or update operations.
046: */
047: abstract public class CascadableField extends AbstractField {
048: private static final L10N L = new L10N(CascadableField.class);
049: private static final Logger log = Log.open(CascadableField.class);
050:
051: private CascadeType[] _cascadeTypes;
052:
053: CascadableField(RelatedType sourceType) {
054: super (sourceType);
055: }
056:
057: CascadableField(RelatedType sourceType, String name,
058: CascadeType[] cascadeTypes) throws ConfigException {
059: super (sourceType, name);
060:
061: _cascadeTypes = cascadeTypes;
062:
063: if (log.isLoggable(Level.FINER)) {
064: String s = "";
065:
066: if (_cascadeTypes != null) {
067: boolean isFirst = true;
068:
069: for (int i = _cascadeTypes.length - 1; i >= 0; i--) {
070: if (isFirst)
071: isFirst = false;
072: else
073: s += ", ";
074:
075: s += _cascadeTypes[i];
076: }
077: }
078:
079: log
080: .log(
081: Level.FINER,
082: L
083: .l(
084: "CascadableField.<constructor> class: '{0}' cascade: '{1}'",
085: this .getClass().getName(),
086: s));
087: }
088: }
089:
090: /**
091: * Returns true if this is cascadable
092: * from parent to child.
093: */
094: public boolean isCascade(CascadeType cascade) {
095: if (_cascadeTypes == null)
096: return false;
097:
098: for (int i = 0; i < _cascadeTypes.length; i++) {
099: if (_cascadeTypes[i] == CascadeType.ALL)
100: return true;
101:
102: if (_cascadeTypes[i] == cascade)
103: return true;
104: }
105:
106: return false;
107: }
108:
109: /**
110: * Sets the cascade types for this field
111: * from parent to child.
112: */
113: public void setCascadeType(CascadeType[] cascadeTypes) {
114: _cascadeTypes = cascadeTypes;
115: }
116:
117: /**
118: * Generates the (pre) cascade operation from
119: * parent to this child. This field will only
120: * be cascaded first if the operation can be
121: * performed with no risk to break FK constraints.
122: *
123: * Default is to pre-cascade the persist() operation only.
124: *
125: * Check subclasses for one-to-one, many-to-one,
126: * one-to-many and many-to-many relationships.
127: */
128: public void generatePreCascade(JavaWriter out, String aConn,
129: CascadeType cascadeType) throws IOException {
130: if (cascadeType != CascadeType.PERSIST)
131: return;
132:
133: generateInternalCascade(out, aConn, cascadeType);
134: }
135:
136: /**
137: * Generates the (post) cascade operation from
138: * parent to this child. This field will be
139: * (post) cascaded if the operation on the
140: * parent is required to be performed first
141: * to avoid breaking FK constraints.
142: *
143: * Default is to post-cascade all operations,
144: * except the persist() operation.
145: *
146: * Check subclasses for one-to-one, many-to-one,
147: * one-to-many and many-to-many relationships.
148: */
149: public void generatePostCascade(JavaWriter out, String aConn,
150: CascadeType cascadeType) throws IOException {
151: if (cascadeType == CascadeType.PERSIST)
152: return;
153:
154: generateInternalCascade(out, aConn, cascadeType);
155: }
156:
157: /**
158: * Returns true if the field is cascadable.
159: */
160: public boolean isCascadable() {
161: return true;
162: }
163:
164: /**
165: * Generates the flush check for this child.
166: * See DependentEntityOneToOneField.
167: */
168: public boolean generateFlushCheck(JavaWriter out)
169: throws IOException {
170: return false;
171: }
172:
173: protected void generateInternalCascade(JavaWriter out,
174: String aConn, CascadeType cascadeType) throws IOException {
175: if (isCascade(cascadeType)) {
176: String getter = generateSuperGetter();
177:
178: out.println("if (" + getter + " != null) {");
179: out.pushDepth();
180:
181: out.print(aConn + ".");
182:
183: switch (cascadeType) {
184: case PERSIST:
185: out.print("persistFromCascade");
186: break;
187:
188: case MERGE:
189: out.print("merge");
190: break;
191:
192: case REMOVE:
193: out.print("remove");
194: break;
195:
196: case REFRESH:
197: out.print("refresh");
198: break;
199: }
200:
201: out.println("(" + getter + ");");
202:
203: // XXX: jpa/0h27, jpa/0o33
204: if (cascadeType == CascadeType.PERSIST
205: && this instanceof EntityManyToOneField) {
206: out.println("((com.caucho.amber.entity.Entity) "
207: + getter + ").__caucho_flush();");
208: }
209:
210: out.popDepth();
211: out.println("}");
212: }
213: }
214: }
|