001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.cnd.modelimpl.csm.core;
043:
044: import java.io.DataInput;
045: import java.io.DataOutput;
046: import java.io.IOException;
047: import java.util.ArrayList;
048: import java.util.HashMap;
049: import java.util.List;
050: import java.util.Map;
051: import java.util.zip.Adler32;
052: import java.util.zip.Checksum;
053: import org.netbeans.modules.cnd.api.project.NativeFileItem;
054: import org.netbeans.modules.cnd.api.project.NativeProject;
055: import org.netbeans.modules.cnd.modelimpl.debug.TraceFlags;
056: import org.netbeans.modules.cnd.modelimpl.repository.ProjectSettingsValidatorKey;
057: import org.netbeans.modules.cnd.modelimpl.repository.RepositoryUtils;
058: import org.netbeans.modules.cnd.repository.spi.Key;
059: import org.netbeans.modules.cnd.repository.spi.Persistent;
060: import org.netbeans.modules.cnd.repository.spi.PersistentFactory;
061: import org.netbeans.modules.cnd.repository.support.SelfPersistent;
062:
063: /**
064: * When project restored, we should validate whether settings for each item
065: * (include path, system and user macros) have changed since storing project in persistence.
066: * This class performes this validation.
067: *
068: * Its lifecycle supposed to be short.
069: * It is created (and used) twice:
070: *
071: * 1) when project is shutting down, it is created, then storeSettings() is called
072: *
073: * 2) when project is restored, it is created, restoreSettings() is called,
074: * the isChanged() is called for each native file item
075: *
076: * @author Vladimir Kvashin
077: */
078: public class ProjectSettingsValidator {
079:
080: private static final boolean TRACE = Boolean
081: .getBoolean("cnd.modelimpl.validator.trace");
082:
083: public ProjectSettingsValidator(ProjectBase csmProject) {
084: this .csmProject = csmProject;
085: Object platformProject = csmProject.getPlatformProject();
086: if (platformProject instanceof NativeProject) {
087: nativeProject = (NativeProject) platformProject;
088: }
089: }
090:
091: public void storeSettings() {
092: if (nativeProject == null) {
093: return;
094: }
095: long time = 0;
096: if (TraceFlags.TIMING) {
097: System.err.printf(
098: "ProjectSettingsValidator.storeSettings for %s\n",
099: csmProject.getName());
100: time = System.currentTimeMillis();
101: }
102: data = new Data();
103: List<NativeFileItem> sources = new ArrayList<NativeFileItem>();
104: List<NativeFileItem> headers = new ArrayList<NativeFileItem>();
105: for (NativeFileItem item : nativeProject.getAllFiles()) {
106: if (!item.isExcluded()) {
107: switch (item.getLanguage()) {
108: case C:
109: case CPP:
110: sources.add(item);
111: break;
112: case C_HEADER:
113: headers.add(item);
114: break;
115: default:
116: break;
117: }
118: }
119: }
120: updateMap(headers);
121: updateMap(sources);
122: Key key = new ProjectSettingsValidatorKey(csmProject
123: .getUniqueName().toString());
124: RepositoryUtils.put(key, data);
125: if (TraceFlags.TIMING) {
126: time = System.currentTimeMillis() - time;
127: System.err
128: .printf(
129: "ProjectSettingsValidator.storeSettings for %s took %d ms\n",
130: csmProject.getName(), time);
131: }
132: }
133:
134: private void updateMap(List<NativeFileItem> items) {
135: for (NativeFileItem item : items) {
136: long crc = calculateCrc(item);
137: data.setCrc(item.getFile().getAbsolutePath(), crc);
138: }
139: }
140:
141: public void restoreSettings() {
142: if (nativeProject == null) {
143: return;
144: }
145: Key key = new ProjectSettingsValidatorKey(csmProject
146: .getUniqueName().toString());
147: data = (Data) RepositoryUtils.get(key);
148: assert data != null : "Can not get project settings validator data by the key "
149: + key; //NOI18N
150: }
151:
152: public boolean exists(FileImpl fileImpl) {
153: return data.exists(fileImpl.getAbsolutePath());
154: }
155:
156: public boolean arePropertiesChanged(NativeFileItem item) {
157: if (nativeProject == null) {
158: return false;
159: }
160: assert data != null;
161: long savedCrc = data.getCrc(item.getFile().getAbsolutePath());
162: long currentCrc = calculateCrc(item);
163: if (TRACE)
164: System.err.printf(
165: "arePropertiesChanged %s OLD=%d CUR=%d %b\n", item
166: .getFile().getName(), savedCrc, currentCrc,
167: (savedCrc != currentCrc));
168: return savedCrc != currentCrc;
169: }
170:
171: private long calculateCrc(NativeFileItem item) {
172: if (TRACE)
173: System.err.printf(">>> CRC %s\n", item.getFile().getName());
174: Checksum checksum = new Adler32();
175: updateCrc(checksum, item.getLanguage().toString());
176: updateCrc(checksum, item.getLanguageFlavor().toString());
177: updateCrc(checksum, item.getSystemIncludePaths());
178: updateCrc(checksum, item.getUserIncludePaths());
179: updateCrc(checksum, item.getSystemMacroDefinitions());
180: updateCrc(checksum, item.getUserMacroDefinitions());
181: if (TRACE)
182: System.err.printf("<<< CRC %s %d\n", item.getFile()
183: .getName(), checksum.getValue());
184: return checksum.getValue();
185: }
186:
187: private void updateCrc(Checksum checksum, String s) {
188: checksum.update(s.getBytes(), 0, s.length());
189: if (TRACE)
190: System.err.printf("\tupdateCrc %s -> %d\n", s, checksum
191: .getValue());
192: }
193:
194: private void updateCrc(Checksum checksum, List<String> strings) {
195: for (String s : strings) {
196: updateCrc(checksum, s);
197: }
198: }
199:
200: public static PersistentFactory getPersistentFactory() {
201: // it isn't worth caching factory since it's too rarely used
202: return new ValidatorPersistentFactory();
203: }
204:
205: private static class Data implements Persistent, SelfPersistent {
206:
207: private Map<String, Long> map;
208:
209: public Data() {
210: map = new HashMap<String, Long>();
211: }
212:
213: public long getCrc(String name) {
214: Long crc = map.get(name);
215: return crc == null ? 0 : crc.longValue();
216: }
217:
218: public boolean exists(String name) {
219: return map.containsKey(name);
220: }
221:
222: public void setCrc(String name, long crc) {
223: map.put(name, crc);
224: }
225:
226: public Data(DataInput stream) throws IOException {
227: map = new HashMap<String, Long>();
228: int cnt = stream.readInt();
229: for (int i = 0; i < cnt; i++) {
230: String name = stream.readUTF();
231: long crc = stream.readLong();
232: map.put(name, crc);
233: }
234: }
235:
236: public void write(DataOutput stream) throws IOException {
237: stream.writeInt(map.size());
238: for (Map.Entry<String, Long> entry : map.entrySet()) {
239: stream.writeUTF(entry.getKey());
240: stream.writeLong(entry.getValue().longValue());
241: }
242: }
243: }
244:
245: private static class ValidatorPersistentFactory implements
246: PersistentFactory {
247:
248: public boolean canWrite(Persistent obj) {
249: assert obj instanceof Data;
250: return true;
251: }
252:
253: public void write(DataOutput out, Persistent obj)
254: throws IOException {
255: assert obj instanceof Data;
256: ((Data) obj).write(out);
257: }
258:
259: public Persistent read(DataInput in) throws IOException {
260: return new Data(in);
261: }
262: }
263:
264: private ProjectBase csmProject;
265: private NativeProject nativeProject;
266: private Data data;
267: }
|