public synchronized void updateType()

in incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/ShapefileStore.java [647:791]


        public synchronized void updateType(DefaultFeatureType newType) throws DataStoreException {

            if (!isDefaultView()) throw new DataStoreException("Resource not writable in current filter state");
            if (Files.exists(shpPath)) {
                throw new DataStoreException("Update type is possible only when files do not exist. It can be used to create a new shapefile but not to update one.");
            }

            final Class<?>[] supportedDateTypes;    // All types other than the one at index 0 will lost information.
            if (timezone == null) {
                supportedDateTypes = new Class<?>[] {
                    LocalDate.class, LocalDateTime.class
                };
            } else {
                supportedDateTypes = new Class<?>[] {
                    LocalDate.class, LocalDateTime.class, OffsetDateTime.class, ZonedDateTime.class, Instant.class
                };
            }

            lock.writeLock().lock();
            try {
                final ShapeHeader shpHeader = new ShapeHeader();
                shpHeader.bbox = new ImmutableEnvelope(new GeneralEnvelope(4));
                final DBFHeader dbfHeader = new DBFHeader();
                dbfHeader.lastUpdate = LocalDate.now();
                dbfHeader.fields = new DBFField[0];
                final Charset charset = userDefinedCharSet == null ? StandardCharsets.UTF_8 : userDefinedCharSet;
                CoordinateReferenceSystem crs = CommonCRS.WGS84.normalizedGeographic();

                for (AbstractIdentifiedType pt : newType.getProperties(true)) {
                    if (pt instanceof DefaultAttributeType) {
                        final DefaultAttributeType at = (DefaultAttributeType) pt;
                        final Class valueClass = at.getValueClass();
                        final String attName = at.getName().tip().toString();

                        Integer length = AttributeConvention.getMaximalLengthCharacteristic(newType, pt);
                        if (length == null || length == 0) length = 255;

                        if (Geometry.class.isAssignableFrom(valueClass)) {
                            if (shpHeader.shapeType != null) {
                                throw new DataStoreException("Shapefile format can only contain one geometry");
                            }
                            if (Point.class.isAssignableFrom(valueClass)) shpHeader.shapeType = ShapeType.POINT;
                            else if (MultiPoint.class.isAssignableFrom(valueClass))
                                shpHeader.shapeType = ShapeType.MULTIPOINT;
                            else if (LineString.class.isAssignableFrom(valueClass) || MultiLineString.class.isAssignableFrom(valueClass))
                                shpHeader.shapeType = ShapeType.POLYLINE;
                            else if (Polygon.class.isAssignableFrom(valueClass) || MultiPolygon.class.isAssignableFrom(valueClass))
                                shpHeader.shapeType = ShapeType.POLYGON;
                            else throw new DataStoreException("Unsupported geometry type " + valueClass);

                            Object cdt = at.characteristics().get(AttributeConvention.CRS);
                            if (cdt instanceof DefaultAttributeType) {
                                Object defaultValue = ((DefaultAttributeType) cdt).getDefaultValue();
                                if (defaultValue instanceof CoordinateReferenceSystem) {
                                    crs = (CoordinateReferenceSystem) defaultValue;
                                }
                            }

                        } else if (String.class.isAssignableFrom(valueClass)) {
                            dbfHeader.fields = ArraysExt.append(dbfHeader.fields, new DBFField(attName, DBFField.TYPE_CHAR, 0, length, 0, charset, null));
                        } else if (Byte.class.isAssignableFrom(valueClass)) {
                            dbfHeader.fields = ArraysExt.append(dbfHeader.fields, new DBFField(attName, DBFField.TYPE_NUMBER, 0, 4, 0, null, null));
                        } else if (Short.class.isAssignableFrom(valueClass)) {
                            dbfHeader.fields = ArraysExt.append(dbfHeader.fields, new DBFField(attName, DBFField.TYPE_NUMBER, 0, 6, 0, null, null));
                        } else if (Integer.class.isAssignableFrom(valueClass)) {
                            dbfHeader.fields = ArraysExt.append(dbfHeader.fields, new DBFField(attName, DBFField.TYPE_NUMBER, 0, 9, 0, null, null));
                        } else if (Long.class.isAssignableFrom(valueClass)) {
                            dbfHeader.fields = ArraysExt.append(dbfHeader.fields, new DBFField(attName, DBFField.TYPE_NUMBER, 0, 19, 0, null, null));
                        } else if (Float.class.isAssignableFrom(valueClass)) {
                            dbfHeader.fields = ArraysExt.append(dbfHeader.fields, new DBFField(attName, DBFField.TYPE_NUMBER, 0, 11, 6, null, null));
                        } else if (Double.class.isAssignableFrom(valueClass)) {
                            dbfHeader.fields = ArraysExt.append(dbfHeader.fields, new DBFField(attName, DBFField.TYPE_NUMBER, 0, 33, 18, null, null));
                        } else if (Classes.isAssignableToAny(valueClass, supportedDateTypes)) {
                            dbfHeader.fields = ArraysExt.append(dbfHeader.fields, new DBFField(attName, DBFField.TYPE_DATE, 0, 20, 0, null, timezone));
                            if (!(LocalDate.class.isAssignableFrom(valueClass))) {  // TODO: use `index != 0` instead.
                                LOGGER.log(Level.WARNING, "Shapefile writing, field {0} will lost the time component of the date", pt.getName());
                            }
                        } else {
                            LOGGER.log(Level.WARNING, "Shapefile writing, field {0} is not supported", pt.getName());
                        }
                    } else {
                        LOGGER.log(Level.WARNING, "Shapefile writing, field {0} is not supported", pt.getName());
                    }
                }

                //write shapefile
                try (ShapeWriter writer = new ShapeWriter(ShpFiles.openWriteChannel(files.shpFile, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING))) {
                    writer.writeHeader(shpHeader);
                } catch (IOException ex) {
                    throw new DataStoreException("Failed to create shapefile (shp).", ex);
                }

                //write shx
                try (IndexWriter writer = new IndexWriter(ShpFiles.openWriteChannel(files.getShx(true), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING))) {
                    writer.writeHeader(shpHeader);
                } catch (IOException ex) {
                    throw new DataStoreException("Failed to create shapefile (shx).", ex);
                }

                //write dbf
                try (DBFWriter writer = new DBFWriter(ShpFiles.openWriteChannel(files.getDbf(true), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING))) {
                    writer.writeHeader(dbfHeader);
                } catch (IOException ex) {
                    throw new DataStoreException("Failed to create shapefile (dbf).", ex);
                }

                //write cpg
                try {
                    CpgFiles.write(charset, files.getCpg(true));
                } catch (IOException ex) {
                    throw new DataStoreException("Failed to create shapefile (cpg).", ex);
                }

                //write prj
                try {
                    final String wkt;

                    if (Utilities.equalsApproximately(crs, CommonCRS.WGS84.normalizedGeographic())) {
                        /*
                         * TODO until we manage to understand the expected ESRI writing for CRS:84
                         * we replace it by hand.
                         * There is an odd recursive information that shapefiles are longitude first whatever the CRS.
                         * But the ESRI specification do not say anything about it.
                         * Generate WKT by tools like ogr,qgis do not declare the axes so we are clueless.
                         */
                        wkt = "GEOGCS[\"GCS_WGS_84_CRS84\",DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_1984\",6378137.0,298.257223563]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]]";
                    } else {
                        final WKTFormat format = new WKTFormat();
                        format.setConvention(Convention.WKT1_COMMON_UNITS);
                        format.setNameAuthority(Citations.ESRI);
                        format.setIndentation(WKTFormat.SINGLE_LINE);
                        wkt = format.format(crs);
                    }
                    Files.writeString(files.getPrj(true), wkt, StandardCharsets.ISO_8859_1, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE);

                } catch (IOException ex) {
                    throw new DataStoreException("Failed to create shapefile (prj).", ex);
                }

                //update file list
                files.scan();
            } finally {
                lock.writeLock().unlock();
            }
        }