{
                    return ZoneId.of(id);
                }

package org.apache.wicket.examples.datetime;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.FormatStyle;
import java.time.format.TextStyle;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import org.apache.wicket.Session;
import org.apache.wicket.examples.WicketExamplePage;
import org.apache.wicket.examples.forminput.FormInputApplication;
import org.apache.wicket.extensions.markup.html.form.datetime.LocalDateTextField;
import org.apache.wicket.extensions.markup.html.form.datetime.LocalDateTimeField;
import org.apache.wicket.extensions.markup.html.form.datetime.LocalDateTimeTextField;
import org.apache.wicket.extensions.markup.html.form.datetime.TimeField;
import org.apache.wicket.extensions.markup.html.form.datetime.ZonedDateTimeField;
import org.apache.wicket.extensions.markup.html.form.datetime.ZonedToLocalDateTimeModel;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.FormComponentUpdatingBehavior;
import org.apache.wicket.markup.html.form.IChoiceRenderer;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.protocol.http.request.WebClientInfo;
import org.apache.wicket.request.http.WebRequest;

/**
 * DateTime example page.
 */
public class DateTimePage extends WicketExamplePage {

    private static final long serialVersionUID = 1L;

    private ZoneId clientZone;

    private ZoneId targetZone = ZoneId.of("UTC+8");

    @SuppressWarnings("unused")
    private LocalTime time1 = LocalTime.of(22, 15);

    @SuppressWarnings("unused")
    private LocalTime time2 = LocalTime.of(22, 15);

    @SuppressWarnings("unused")
    private LocalDate date = LocalDate.now();

    @SuppressWarnings("unused")
    private LocalDateTime dateTime0 = LocalDateTime.now();

    @SuppressWarnings("unused")
    private ZonedDateTime dateTime1 = LocalDateTime.now().atZone(targetZone);

    @SuppressWarnings("unused")
    private ZonedDateTime dateTime2 = LocalDateTime.now().atZone(targetZone);

    @SuppressWarnings("unused")
    private ZonedDateTime dateTime3 = ZonedDateTime.now();

    public DateTimePage() {
        Form<String> form = new Form<>("form");
        this.add(form);
        form.add(new ZoneDropDownChoice("zoneSelect"));
        // Dropdown for selecting locale
        form.add(new LocaleDropDownChoice("localeSelect"));
        // Link to return to default locale
        form.add(new Link<Void>("defaultLocaleLink") {

            private static final long serialVersionUID = 1L;

            public void onClick() {
                WebRequest request = (WebRequest) getRequest();
                getSession().setLocale(request.getLocale());
            }
        });
        form.add(new TimeField("time1", new PropertyModel<>(this, "time1")) {

            private static final long serialVersionUID = 1L;

            @Override
            protected boolean use12HourFormat() {
                return true;
            }
        });
        form.add(new TimeField("time2", new PropertyModel<>(this, "time2")) {

            private static final long serialVersionUID = 1L;

            @Override
            protected boolean use12HourFormat() {
                return false;
            }
        });
        final LocalDateTextField dateField = new LocalDateTextField("date", new PropertyModel<>(this, "date"), "dd-MM-yyyy", "d-M-yyyy");
        form.add(dateField);
        final LocalDateTimeField datetimeField0 = new LocalDateTimeField("datetime0", new PropertyModel<>(this, "dateTime0")) {

            private static final long serialVersionUID = 1L;

            @Override
            protected LocalTime getDefaultTime() {
                return LocalTime.of(0, 0);
            }
        };
        form.add(datetimeField0);
        IModel<ZonedDateTime> zonedDateTime1 = new PropertyModel<>(this, "dateTime1");
        final LocalDateTimeField datetimeField1 = new LocalDateTimeField("datetime1", new ZonedToLocalDateTimeModel(zonedDateTime1) {

            private static final long serialVersionUID = 1L;

            @Override
            protected ZoneId getClientTimeZone() {
                return clientZone;
            }

            @Override
            protected ZoneId getTargetTimeZone() {
                return targetZone;
            }
        });
        form.add(datetimeField1);
        form.add(new Label("datetime1-label", zonedDateTime1));
        IModel<ZonedDateTime> zonedDateTime2 = new PropertyModel<>(this, "dateTime2");
        LocalDateTimeTextField datetimeField2 = new LocalDateTimeTextField("datetime2", new ZonedToLocalDateTimeModel(zonedDateTime2) {

            private static final long serialVersionUID = 1L;

            @Override
            protected ZoneId getClientTimeZone() {
                return clientZone;
            }

            @Override
            protected ZoneId getTargetTimeZone() {
                return targetZone;
            }
        }, FormatStyle.SHORT, FormatStyle.SHORT);
        form.add(datetimeField2);
        form.add(new Label("datetime2-label", zonedDateTime2));
        final ZonedDateTimeField datetimeField3 = new ZonedDateTimeField("datetime3", new PropertyModel<>(this, "dateTime3"));
        form.add(datetimeField3);
        final FeedbackPanel feedback = new FeedbackPanel("feedback");
        form.add(feedback);
        form.add(new Button("submit"));
    }

    @Override
    protected void onInitialize() {
        super.onInitialize();
        clientZone = ((WebClientInfo) Session.get().getClientInfo()).getProperties().getTimeZone().toZoneId();
    }

    private final class LocaleChoiceRenderer implements IChoiceRenderer<Locale> {

        private static final long serialVersionUID = 1L;

        @Override
        public Object getDisplayValue(Locale locale) {
            return locale.getDisplayName(getLocale());
        }
    }

    /**
     * Dropdown with Locales.
     */
    private final class LocaleDropDownChoice extends DropDownChoice<Locale> {

        private static final long serialVersionUID = 1L;

        /**
         * Construct.
         *
         * @param id
         *            component id
         */
        public LocaleDropDownChoice(String id) {
            super(id, FormInputApplication.LOCALES, new LocaleChoiceRenderer());
            setModel(new PropertyModel<>(this, "session.locale"));
            add(new FormComponentUpdatingBehavior() {

                private static final long serialVersionUID = 1L;

                @Override
                protected void onUpdate() {
                    setResponsePage(getPage().getClass());
                }
            });
        }
    }

    private class ZoneDropDownChoice extends DropDownChoice<ZoneId> {

        private static final long serialVersionUID = 1L;

        public ZoneDropDownChoice(String id) {
            super(id, new IModel<List<ZoneId>>() {

                private static final long serialVersionUID = 1L;

                @Override
                public List<ZoneId> getObject() {
                    return ZoneId.getAvailableZoneIds().stream().map(id -> ZoneId.of(id)).collect(Collectors.toList());
                }
            });
            setModel(new PropertyModel<ZoneId>(DateTimePage.this, "clientZone"));
            setChoiceRenderer(new IChoiceRenderer<ZoneId>() {

                private static final long serialVersionUID = 1L;

                @Override
                public Object getDisplayValue(ZoneId object) {
                    String name = object.getDisplayName(TextStyle.FULL, getLocale());
                    ZoneOffset offset = LocalDateTime.now().atZone(object).getOffset();
                    return name + offset;
                }

                @Override
                public String getIdValue(ZoneId object, int index) {
                    return object.getId();
                }

                @Override
                public ZoneId getObject(String id, IModel<? extends List<? extends ZoneId>> choices)

            });
            add(new FormComponentUpdatingBehavior() {

                private static final long serialVersionUID = 1L;

                protected void onUpdate() {
                    // clear raw input of all inputs so that values are reformatted
                    getForm().clearInput();
                }
            });
        }
    }
}


package org.apache.wicket.examples.datetime;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.FormatStyle;
import java.time.format.TextStyle;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import org.apache.wicket.Session;
import org.apache.wicket.examples.WicketExamplePage;
import org.apache.wicket.examples.forminput.FormInputApplication;
import org.apache.wicket.extensions.markup.html.form.datetime.LocalDateTextField;
import org.apache.wicket.extensions.markup.html.form.datetime.LocalDateTimeField;
import org.apache.wicket.extensions.markup.html.form.datetime.LocalDateTimeTextField;
import org.apache.wicket.extensions.markup.html.form.datetime.TimeField;
import org.apache.wicket.extensions.markup.html.form.datetime.ZonedDateTimeField;
import org.apache.wicket.extensions.markup.html.form.datetime.ZonedToLocalDateTimeModel;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.FormComponentUpdatingBehavior;
import org.apache.wicket.markup.html.form.IChoiceRenderer;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.protocol.http.request.WebClientInfo;
import org.apache.wicket.request.http.WebRequest;

/**
 * DateTime example page.
 */
public class DateTimePage extends WicketExamplePage {

    private static final long serialVersionUID = 1L;

    private ZoneId clientZone;

    private ZoneId targetZone = ZoneId.of("UTC+8");

    @SuppressWarnings("unused")
    private LocalTime time1 = LocalTime.of(22, 15);

    @SuppressWarnings("unused")
    private LocalTime time2 = LocalTime.of(22, 15);

    @SuppressWarnings("unused")
    private LocalDate date = LocalDate.now();

    @SuppressWarnings("unused")
    private LocalDateTime dateTime0 = LocalDateTime.now();

    @SuppressWarnings("unused")
    private ZonedDateTime dateTime1 = LocalDateTime.now().atZone(targetZone);

    @SuppressWarnings("unused")
    private ZonedDateTime dateTime2 = LocalDateTime.now().atZone(targetZone);

    @SuppressWarnings("unused")
    private ZonedDateTime dateTime3 = ZonedDateTime.now();

    public DateTimePage() {
        Form<String> form = new Form<>("form");
        this.add(form);
        form.add(new ZoneDropDownChoice("zoneSelect"));
        // Dropdown for selecting locale
        form.add(new LocaleDropDownChoice("localeSelect"));
        // Link to return to default locale
        form.add(new Link<Void>("defaultLocaleLink") {

            private static final long serialVersionUID = 1L;

            public void onClick() {
                WebRequest request = (WebRequest) getRequest();
                getSession().setLocale(request.getLocale

            }
        });
        form.add(new TimeField("time1", new PropertyModel<>(this, "time1")) {

            private static final long serialVersionUID = 1L;

            @Override
            protected boolean use12HourFormat() {
                return true;
            }
        });
        form.add(new TimeField("time2", new PropertyModel<>(this, "time2")) {

            private static final long serialVersionUID = 1L;

            @Override
            protected boolean use12HourFormat() {
                return false;
            }
        });
        final LocalDateTextField dateField = new LocalDateTextField("date", new PropertyModel<>(this, "date"), "dd-MM-yyyy", "d-M-yyyy");
        form.add(dateField);
        final LocalDateTimeField datetimeField0 = new LocalDateTimeField("datetime0", new PropertyModel<>(this, "dateTime0")) {

            private static final long serialVersionUID = 1L;

            @Override
            protected LocalTime getDefaultTime() {
                return LocalTime.of(0, 0);
            }
        };
        form.add(datetimeField0);
        IModel<ZonedDateTime> zonedDateTime1 = new PropertyModel<>(this, "dateTime1");
        final LocalDateTimeField datetimeField1 = new LocalDateTimeField("datetime1", new ZonedToLocalDateTimeModel(zonedDateTime1) {

            private static final long serialVersionUID = 1L;

            @Override
            protected ZoneId getClientTimeZone() {
                return clientZone;
            }

            @Override
            protected ZoneId getTargetTimeZone() {
                return targetZone;
            }
        });
        form.add(datetimeField1);
        form.add(new Label("datetime1-label", zonedDateTime1));
        IModel<ZonedDateTime> zonedDateTime2 = new PropertyModel<>(this, "dateTime2");
        LocalDateTimeTextField datetimeField2 = new LocalDateTimeTextField("datetime2", new ZonedToLocalDateTimeModel(zonedDateTime2) {

            private static final long serialVersionUID = 1L;

            @Override
            protected ZoneId getClientTimeZone() {
                return clientZone;
            }

            @Override
            protected ZoneId getTargetTimeZone() {
                return targetZone;
            }
        }, FormatStyle.SHORT, FormatStyle.SHORT);
        form.add(datetimeField2);
        form.add(new Label("datetime2-label", zonedDateTime2));
        final ZonedDateTimeField datetimeField3 = new ZonedDateTimeField("datetime3", new PropertyModel<>(this, "dateTime3"));
        form.add(datetimeField3);
        final FeedbackPanel feedback = new FeedbackPanel("feedback");
        form.add(feedback);
        form.add(new Button("submit"));
    }

    @Override
    protected void onInitialize() {
        super.onInitialize();
        clientZone = ((WebClientInfo) Session.get().getClientInfo()).getProperties().getTimeZone().toZoneId();
    }

    private final class LocaleChoiceRenderer implements IChoiceRenderer<Locale> {

        private static final long serialVersionUID = 1L;

        @Override
        public Object getDisplayValue(Locale locale) {
            return locale.getDisplayName(getLocale());
        }
    }

    /**
     * Dropdown with Locales.
     */
    private final class LocaleDropDownChoice extends DropDownChoice<Locale> {

        private static final long serialVersionUID = 1L;

        /**
         * Construct.
         *
         * @param id
         *            component id
         */
        public LocaleDropDownChoice(String id) {
            super(id, FormInputApplication.LOCALES, new LocaleChoiceRenderer());
            setModel(new PropertyModel<>(this, "session.locale"));
            add(new FormComponentUpdatingBehavior() {

                private static final long serialVersionUID = 1L;

                @Override
                protected void onUpdate() {
                    setResponsePage(getPage().getClass());
                }
            });
        }
    }

    private class ZoneDropDownChoice extends DropDownChoice<ZoneId> {

        private static final long serialVersionUID = 1L;

        public ZoneDropDownChoice(String id) {
            super(id, new IModel<List<ZoneId>>() {

                private static final long serialVersionUID = 1L;

                @Override
                public List<ZoneId> getObject() {
                    return ZoneId.getAvailableZoneIds().stream().map(id -> ZoneId.of(id)).collect(Collectors.toList());
                }
            });
            setModel(new PropertyModel<ZoneId>(DateTimePage.this, "clientZone"));
            setChoiceRenderer(new IChoiceRenderer<ZoneId>() {

                private static final long serialVersionUID = 1L;

                @Override
                public Object getDisplayValue(ZoneId object) {
                    String name = object.getDisplayName(TextStyle.FULL, getLocale());
                    ZoneOffset offset = LocalDateTime.now().atZone(object).getOffset();
                    return name + offset;
                }

                @Override
                public String getIdValue(ZoneId object, int index) {
                    return object.getId();
                }

                @Override
                public ZoneId getObject(String id, IModel<? extends List<? extends ZoneId>> choices) {
                    return ZoneId.of(id);
                }
            });
            add(new FormComponentUpdatingBehavior() {

                private static final long serialVersionUID = 1L;

                protected void onUpdate() {
                    // clear raw input of all inputs so that values are reformatted
                    getForm().clearInput();
                }
            });
        }
    }
}


private PublicKey buildPublicKey(String pemContent) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException

/*
 * Tencent is pleased to support the open source community by making BK-JOB蓝鲸智云作业平台 available.
 *
 *
 *
 * License for BK-JOB蓝鲸智云作业平台:
 * --------------------------------------------------------------------
 */
package com.tencent.bk.job.gateway.service.impl;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.tencent.bk.job.gateway.model.esb.EsbJwtInfo;
import com.tencent.bk.job.gateway.service.EsbJwtPublicKeyService;
import com.tencent.bk.job.gateway.service.EsbJwtService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.io.StringReader;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.time.Instant;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class EsbJwtServiceImpl implements EsbJwtService {

    private final EsbJwtPublicKeyService esbJwtPublicKeyService;

    private PublicKey publicKey;

    private final Cache<String, EsbJwtInfo> tokenCache = CacheBuilder.newBuilder().maximumSize(99999).expireAfterWrite(30, TimeUnit.SECONDS).build();

    @Autowired
    public EsbJwtServiceImpl(EsbJwtPublicKeyService esbJwtPublicKeyService) {
        this.esbJwtPublicKeyService = esbJwtPublicKeyService;
        getAndCachePublicKey();
    }

    private void getAndCachePublicKey() {
        try {
            String esbJwtPublicKey = esbJwtPublicKeyService.getEsbJWTPublicKey();
            if (StringUtils.isEmpty(esbJwtPublicKey)) {
                log.error("Esb jwt public key is not configured!");
                return;
            }
            this.publicKey = buildPublicKey(esbJwtPublicKey);
        } catch (Throwable e) {
            // Catch all exception
            log.error("Build esb jwt public key caught error!", e);
        }
    }

{
        PemReader pemReader = new PemReader(new StringReader(pemContent));
        PemObject pemObject = pemReader.readPemObject();
        if (pemObject == null) {
            log.error("Esb public key pem is illegal!");
            return null;
        }
        java.security.Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(pemObject.getContent());
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(pubKeySpec);
    }

    @Override
    public EsbJwtInfo extractFromJwt(String token) {
        long start = System.currentTimeMillis();
        EsbJwtInfo cacheJwtInfo = tokenCache.getIfPresent(token);
        if (cacheJwtInfo != null) {
            Long tokenExpireAt = cacheJwtInfo.getTokenExpireAt();
            // 如果未超时
            if (tokenExpireAt > Instant.now().getEpochSecond()) {
                return cacheJwtInfo;
            }
        }
        EsbJwtInfo esbJwtInfo;
        try {
            Claims claims = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token).getBody();
            String appCode = "";
            if (claims.get("app") != null) {
                LinkedHashMap appProps = claims.get("app", LinkedHashMap.class);
                if (appProps == null) {
                    log.warn("Invalid JWT token, app is null!");
                    return null;
                }
                boolean isVerified = appProps.get("verified") != null && (boolean) appProps.get("verified");
                appCode = (String) appProps.get("app_code");
                if (StringUtils.isEmpty(appCode)) {
                    appCode = (String) appProps.get("bk_app_code");
                }
                if (!isVerified || StringUtils.isEmpty(appCode)) {
                    log.warn("App code not verified or empty, isVerified:{}, jwtAppCode:{}", isVerified, appCode);
                    return null;
                }
            }
            String username = "";
            if (claims.get("user") != null) {
                LinkedHashMap userProps = claims.get("user", LinkedHashMap.class);
                if (userProps == null) {
                    log.warn("Invalid JWT token, user is null!");
                    return null;
                }
                username = (String) userProps.get("username");
                if (StringUtils.isEmpty(username)) {
                    username = (String) userProps.get("bk_username");
                }
                if (StringUtils.isEmpty(username)) {
                    log.warn("Username is empty!");
                    return null;
                }
            }
            Date expireAt = claims.get("exp", Date.class);
            if (expireAt == null) {
                log.warn("Invalid JWT token, exp is null!");
                return null;
            }
            esbJwtInfo = new EsbJwtInfo(expireAt.getTime(), username, appCode);
            tokenCache.put(token, esbJwtInfo);
        } catch (Exception e) {
            log.warn("Verify jwt caught exception", e);
            return null;
        } finally {
            long cost = System.currentTimeMillis() - start;
            if (cost > 10) {
                log.warn("Verify jwt cost too much, cost:{}", cost);
            }
        }
        return esbJwtInfo;
    }
}


{
        try {
            String esbJwtPublicKey = esbJwtPublicKeyService.getEsbJWTPublicKey();
            if (StringUtils.isEmpty(esbJwtPublicKey)) {
                log.error("Esb jwt public key is not configured!");
                return;
            }
            this.publicKey = buildPublicKey(esbJwtPublicKey);
        } catch (Throwable e) {
            // Catch all exception
            log.error("Build esb jwt public key caught error!", e);
        }
    }

/*
 * Tencent is pleased to support the open source community by making BK-JOB蓝鲸智云作业平台 available.
 *
 *
 *
 * License for BK-JOB蓝鲸智云作业平台:
 * --------------------------------------------------------------------
 */
package com.tencent.bk.job.gateway.service.impl;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.tencent.bk.job.gateway.model.esb.EsbJwtInfo;
import com.tencent.bk.job.gateway.service.EsbJwtPublicKeyService;
import com.tencent.bk.job.gateway.service.EsbJwtService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.io.StringReader;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.time.Instant;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class EsbJwtServiceImpl implements EsbJwtService {

    private final EsbJwtPublicKeyService esbJwtPublicKeyService;

    private PublicKey publicKey;

    private final Cache<String, EsbJwtInfo> tokenCache = CacheBuilder.newBuilder().maximumSize(99999).expireAfterWrite(30, TimeUnit.SECONDS).build();

    @Autowired
    public EsbJwtServiceImpl(EsbJwtPublicKeyService esbJwtPublicKeyService) {
        this.esbJwtPublicKeyService = esbJwtPublicKeyService;
        getAndCachePublicKey();
    }

    private void getAndCachePublicKey()

    private PublicKey buildPublicKey(String pemContent) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
        PemReader pemReader = new PemReader(new StringReader(pemContent));
        PemObject pemObject = pemReader.readPemObject();
        if (pemObject == null) {
            log.error("Esb public key pem is illegal!");
            return null;
        }
        java.security.Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(pemObject.getContent());
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(pubKeySpec);
    }

    @Override
    public EsbJwtInfo extractFromJwt(String token) {
        long start = System.currentTimeMillis();
        EsbJwtInfo cacheJwtInfo = tokenCache.getIfPresent(token);
        if (cacheJwtInfo != null) {
            Long tokenExpireAt = cacheJwtInfo.getTokenExpireAt();
            // 如果未超时
            if (tokenExpireAt > Instant.now().getEpochSecond()) {
                return cacheJwtInfo;
            }
        }
        EsbJwtInfo esbJwtInfo;
        try {
            Claims claims = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token).getBody();
            String appCode = "";
            if (claims.get("app") != null) {
                LinkedHashMap appProps = claims.get("app", LinkedHashMap.class);
                if (appProps == null) {
                    log.warn("Invalid JWT token, app is null!");
                    return null;
                }
                boolean isVerified = appProps.get("verified") != null && (boolean) appProps.get("verified");
                appCode = (String) appProps.get("app_code");
                if (StringUtils.isEmpty(appCode)) {
                    appCode = (String) appProps.get("bk_app_code");
                }
                if (!isVerified || StringUtils.isEmpty(appCode)) {
                    log.warn("App code not verified or empty, isVerified:{}, jwtAppCode:{}", isVerified, appCode);
                    return null;
                }
            }
            String username = "";
            if (claims.get("user") != null) {
                LinkedHashMap userProps = claims.get("user", LinkedHashMap.class);
                if (userProps == null) {
                    log.warn("Invalid JWT token, user is null!");
                    return null;
                }
                username = (String) userProps.get("username");
                if (StringUtils.isEmpty(username)) {
                    username = (String) userProps.get("bk_username");
                }
                if (StringUtils.isEmpty(username)) {
                    log.warn("Username is empty!");
                    return null;
                }
            }
            Date expireAt = claims.get("exp", Date.class);
            if (expireAt == null) {
                log.warn("Invalid JWT token, exp is null!");
                return null;
            }
            esbJwtInfo = new EsbJwtInfo(expireAt.getTime(), username, appCode);
            tokenCache.put(token, esbJwtInfo);
        } catch (Exception e) {
            log.warn("Verify jwt caught exception", e);
            return null;
        } finally {
            long cost = System.currentTimeMillis() - start;
            if (cost > 10) {
                log.warn("Verify jwt cost too much, cost:{}", cost);
            }
        }
        return esbJwtInfo;
    }
}


/*
 * Tencent is pleased to support the open source community by making BK-JOB蓝鲸智云作业平台 available.
 *
 *
 *
 * License for BK-JOB蓝鲸智云作业平台:
 * --------------------------------------------------------------------
 */
package com.tencent.bk.job.gateway.service.impl;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.tencent.bk.job.gateway.model.esb.EsbJwtInfo;
import com.tencent.bk.job.gateway.service.EsbJwtPublicKeyService;
import com.tencent.bk.job.gateway.service.EsbJwtService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.io.StringReader;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.time.Instant;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class EsbJwtServiceImpl implements EsbJwtService {

    private final EsbJwtPublicKeyService esbJwtPublicKeyService;

    private PublicKey publicKey;

    private final Cache<String, EsbJwtInfo> tokenCache = CacheBuilder.newBuilder().maximumSize(99999).expireAfterWrite(30, TimeUnit.SECONDS).build();

    @Autowired
    public EsbJwtServiceImpl(EsbJwtPublicKeyService esbJwtPublicKeyService) {
        this.esbJwtPublicKeyService = esbJwtPublicKeyService;
        getAndCachePublicKey();
    }

    private void getAndCachePublicKey() {
        try {
            String esbJwtPublicKey = esbJwtPublicKeyService.getEsbJWTPublicKey();
            if (StringUtils.isEmpty(esbJwtPublicKey)) {
                log.error("Esb jwt public key is not configured!");
                return;
            }
            this.publicKey = buildPublicKey(esbJwtPublicKey);
        } catch (Throwable e) {
            // Catch all exception
            log.error("Build esb jwt public key caught error!", e);
        }
    }

    private PublicKey buildPublicKey(String pemContent) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
        PemReader pemReader = new PemReader(new StringReader(pemContent));
        PemObject pemObject = pemReader.readPemObject();
        if (pemObject == null) {
            log.error("Esb public key pem is illegal!");
            return null;
        }
        java.security.Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(pemObject.getContent());
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(pubKeySpec);
    }

    @Override
    public EsbJwtInfo extractFromJwt(String token) {
        long start = System.currentTimeMillis();
        EsbJwtInfo cacheJwtInfo = tokenCache.getIfPresent(token);
        if (cacheJwtInfo != null) {
            Long tokenExpireAt = cacheJwtInfo.getTokenExpireAt();
            // 如果未超时
            if (tokenExpireAt > Instant.now().getEpochSecond()) {
                return cacheJwtInfo;
            }
        }
        EsbJwtInfo esbJwtInfo;
        try {
            Claims claims = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token).getBody();
            String appCode = "";
            if (claims.get("app") != null) {
                LinkedHashMap appProps = claims.get("app", LinkedHashMap.class);
                if (appProps == null) {
                    log.warn("Invalid JWT token, app is null!");
                    return null;
                }
                boolean isVerified = appProps.get("verified") != null && (boolean) appProps.get("verified");
                appCode = (String) appProps.get("app_code");
                if (StringUtils.isEmpty(appCode)) {
                    appCode = (String) appProps.get("bk_app_code");
                }
                if (!isVerified || StringUtils.isEmpty(appCode)) {
                    log.warn("App code not verified or empty, isVerified:{}, jwtAppCode:{}", isVerified, appCode);
                    return null;
                }
            }
            String username = "";
            if (claims.get("user") != null) {
                LinkedHashMap userProps = claims.get("user", LinkedHashMap.class);
                if (userProps == null) {
                    log.warn("Invalid JWT token, user is null!");
                    return null;
                }
                username = (String) userProps.get("username");
                if (StringUtils.isEmpty(username)) {
                    username = (String) userProps.get("bk_username");
                }
                if (StringUtils.isEmpty(username)) {
                    log.warn("Username is empty!");
                    return null;
                }
            }
            Date expireAt = claims.get("exp", Date.class);
            if (expireAt == null) {
                log.warn("Invalid JWT token, exp is null!");
                return null;
            }
            esbJwtInfo = new EsbJwtInfo(expireAt.getTime(), username, appCode);
            tokenCache.put(token, esbJwtInfo);
        } catch (Exception e) {
            log.warn("Verify jwt caught exception", e);
            return null;
        } finally {
            long cost = System.currentTimeMillis() - start;
            if (cost > 10) {
                log.warn("Verify jwt cost too much, cost:{}", cost);
            }
        }


try {
            String esbJwtPublicKey = esbJwtPublicKeyService.getEsbJWTPublicKey();
            if (StringUtils.isEmpty(esbJwtPublicKey)) {
                log.error("Esb jwt public key is not configured!");
                return;
            }
            this.publicKey = buildPublicKey(esbJwtPublicKey);
        } catch (Throwable e) {
            // Catch all exception
            log.error("Build esb jwt public key caught error!", e);
        }

/*
 * Tencent is pleased to support the open source community by making BK-JOB蓝鲸智云作业平台 available.
 *
 *
 *
 * License for BK-JOB蓝鲸智云作业平台:
 * --------------------------------------------------------------------
 */
package com.tencent.bk.job.gateway.service.impl;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.tencent.bk.job.gateway.model.esb.EsbJwtInfo;
import com.tencent.bk.job.gateway.service.EsbJwtPublicKeyService;
import com.tencent.bk.job.gateway.service.EsbJwtService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.io.StringReader;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.time.Instant;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class EsbJwtServiceImpl implements EsbJwtService {

    private final EsbJwtPublicKeyService esbJwtPublicKeyService;

    private PublicKey publicKey;

    private final Cache<String, EsbJwtInfo> tokenCache = CacheBuilder.newBuilder().maximumSize(99999).expireAfterWrite(30, TimeUnit.SECONDS).build();

    @Autowired
    public EsbJwtServiceImpl(EsbJwtPublicKeyService esbJwtPublicKeyService) {
        this.esbJwtPublicKeyService = esbJwtPublicKeyService;
        getAndCachePublicKey();
    }

    private void getAndCachePublicKey() {

    }

    private PublicKey buildPublicKey(String pemContent) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
        PemReader pemReader = new PemReader(new StringReader(pemContent));
        PemObject pemObject = pemReader.readPemObject();
        if (pemObject == null) {
            log.error("Esb public key pem is illegal!");
            return null;
        }
        java.security.Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(pemObject.getContent());
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(pubKeySpec);
    }

    @Override
    public EsbJwtInfo extractFromJwt(String token) {
        long start = System.currentTimeMillis();
        EsbJwtInfo cacheJwtInfo = tokenCache.getIfPresent(token);
        if (cacheJwtInfo != null) {
            Long tokenExpireAt = cacheJwtInfo.getTokenExpireAt();
            // 如果未超时
            if (tokenExpireAt > Instant.now().getEpochSecond()) {
                return cacheJwtInfo;
            }
        }
        EsbJwtInfo esbJwtInfo;
        try {
            Claims claims = Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token).getBody();
            String appCode = "";
            if (claims.get("app") != null) {
                LinkedHashMap appProps = claims.get("app", LinkedHashMap.class);
                if (appProps == null) {
                    log.warn("Invalid JWT token, app is null!");
                    return null;
                }
                boolean isVerified = appProps.get("verified") != null && (boolean) appProps.get("verified");
                appCode = (String) appProps.get("app_code");
                if (StringUtils.isEmpty(appCode)) {
                    appCode = (String) appProps.get("bk_app_code");
                }
                if (!isVerified || StringUtils.isEmpty(appCode)) {
                    log.warn("App code not verified or empty, isVerified:{}, jwtAppCode:{}", isVerified, appCode);
                    return null;
                }
            }
            String username = "";
            if (claims.get("user") != null) {
                LinkedHashMap userProps = claims.get("user", LinkedHashMap.class);
                if (userProps == null) {
                    log.warn("Invalid JWT token, user is null!");
                    return null;
                }
                username = (String) userProps.get("username");
                if (StringUtils.isEmpty(username)) {
                    username = (String) userProps.get("bk_username");
                }
                if (StringUtils.isEmpty(username)) {
                    log.warn("Username is empty!");
                    return null;
                }
            }
            Date expireAt = claims.get("exp", Date.class);
            if (expireAt == null) {
                log.warn("Invalid JWT token, exp is null!");
                return null;
            }
            esbJwtInfo = new EsbJwtInfo(expireAt.getTime(), username, appCode);
            tokenCache.put(token, esbJwtInfo);
        } catch (Exception e) {
            log.warn("Verify jwt caught exception", e);
            return null;
        } finally {
            long cost = System.currentTimeMillis() - start;
            if (cost > 10) {
                log.warn("Verify jwt cost too much, cost:{}", cost);
            }
        }
        return esbJwtInfo;
    }
}


private void storeOpenAPISchema(OpenAPIBuilder openAPIBuilder, String fileName)

package it.at7.gemini.api.openapi;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import it.at7.gemini.conf.State;
import it.at7.gemini.core.*;
import it.at7.gemini.exceptions.GeminiException;
import it.at7.gemini.exceptions.GeminiRuntimeException;
import it.at7.gemini.schema.Entity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

@Service
public class OpenApiServiceImpl implements OpenApiService, StateListener {

    private static final String SERVICE_INFO_DEFAULT_RESOURCE = "classpath:/service/default-info.yml";

    private final GeminiConfigurationService configurationService;

    private final StateManager stateManager;

    private final SchemaManager schemaManager;

    private final Environment environment;

    private final ApplicationContext context;

    private List<Runnable> API_INITIALIZER_LISTENER = new ArrayList<>();

    private Map<String, OpenAPIFile> builders = new HashMap<>();

    @Autowired
    public OpenApiServiceImpl(GeminiConfigurationService configurationService, StateManager stateManager, SchemaManager schemaManager, Environment environment, ApplicationContext context) {
        this.configurationService = configurationService;
        this.stateManager = stateManager;
        this.schemaManager = schemaManager;
        this.environment = environment;
        this.context = context;
        if (configurationService.isOpenapiSchema()) {
            this.stateManager.register(this);
            // openapi spec withRecord all entities
            builders.put("ALL", OpenAPIFile.from(new OpenAPIBuilder(), "ALL", "all.json"));
            // entities by module... in each dedicated file
            schemaManager.getAllModules().forEach(m -> {
                String moduleName = m.getName().toUpperCase();
                builders.put(moduleName, OpenAPIFile.from(new OpenAPIBuilder(false), moduleName, moduleName.toLowerCase() + ".json"));
            });
        }
    }

    private void createDefaultServiceInfoResource(File serviceInfoResource) throws IOException {
        Resource defaultInfoService = context.getResource(SERVICE_INFO_DEFAULT_RESOURCE);
        serviceInfoResource.getParentFile().mkdirs();
        Files.copy(defaultInfoService.getInputStream(), serviceInfoResource.toPath(), StandardCopyOption.REPLACE_EXISTING);
    }

    @Override
    public void onChange(State previous, State actual, Optional<Transaction> transaction) throws GeminiException {
        if (configurationService.isOpenapiSchema()) {
            switch(actual) {
                case API_INITIALIZATION:
                    loadServiceInfo();
                    makeOpenAPISchema();
                    break;
                case API_INITIALIZED:
                    API_INITIALIZER_LISTENER.forEach(Runnable::run);
                    String localPort = environment.getProperty("local.server.port");
                    iterateOverBuilders(b -> b.builder.addServer("http://127.0.0.1:" + localPort + "/api", "Local Server"));
                    iterateOverBuilders(b -> storeOpenAPISchema(b.builder, b.fileName));
                    break;
                default:
                    break;
            }
        }
    }

    private void loadServiceInfo() {
        try {
            File serviceInfoFile = new File(configurationService.getServiceInfoResource());
            if (!serviceInfoFile.exists()) {
                createDefaultServiceInfoResource(serviceInfoFile);
            }
            ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
            GeminiServiceInfoWrapper geminiService = mapper.readValue(serviceInfoFile, GeminiServiceInfoWrapper.class);
            iterateOverBuilders(b -> b.builder.addInfo(geminiService.info));
        } catch (IOException e) {
            throw new GeminiRuntimeException(e);
        }
    }

    private void makeOpenAPISchema() {
        Collection<Entity> allEntities = this.schemaManager.getAllEntities();
        Map<ModuleBase, List<Entity>> entitiesByModule = allEntities.stream().collect(Collectors.groupingBy(Entity::getModule));
        List<ModuleBase> orderedModules = entitiesByModule.keySet().stream().sorted(Comparator.comparingInt(ModuleBase::order)).collect(Collectors.toList());
        OpenAPIBuilder allEntityBuilder = this.builders.get("ALL").builder;
        allEntityBuilder.addModulesToTags(orderedModules);
        for (ModuleBase module : orderedModules) {
            List<Entity> entities = entitiesByModule.get(module);
            entities.forEach(allEntityBuilder::handleEntity);
            String moduleName = module.getName().toUpperCase();
            OpenAPIFile openAPIFile = this.builders.get(moduleName);
            assert openAPIFile != null;
            List<OpenAPIFile> otherOpenApiFiles = this.builders.values().stream().filter(f -> !f.key.equals(openAPIFile.key) && !f.key.equals("ALL")).collect(Collectors.toList());
            entities.forEach(e -> {
                openAPIFile.builder.handleEntity(e);
                otherOpenApiFiles.forEach(b -> b.builder.addComponentSchema(e, OpenAPIBuilder.SchemaType.ENTITY));
                if (!e.isEmbedable()) {
                    otherOpenApiFiles.forEach(b -> b.builder.addComponentSchema(e, OpenAPIBuilder.SchemaType.ENTITY_LK));
                }
            });
        }
    }

{
        String json = openAPIBuilder.toJsonString();
        try {
            String openApiDir = configurationService.getOpenApiDir();
            Path allPath = Paths.get(openApiDir, fileName);
            File file = new File(allPath.toString());
            file.getParentFile().mkdirs();
            Files.write(allPath, json.getBytes());
        } catch (IOException e) {
            throw new GeminiRuntimeException(e);
        }
    }

    @Override
    public void addOAuth2PasswordFlow(String name, Map<String, Object> flowParameters) {
        if (configurationService.isOpenapiSchema()) {
            String tokenUrl = (String) flowParameters.get("tokenUrl");
            if (tokenUrl == null || tokenUrl.equals("")) {
                throw new GeminiRuntimeException("Unable to initializeSmartModules OAuth2 Password Flow - No tokenUrl Provided");
            }
            OpenAPIBuilder.SecuritySchema securitySchema = new OpenAPIBuilder.SecuritySchema();
            securitySchema.type = "oauth2";
            securitySchema.description = (String) flowParameters.getOrDefault("description", "See http://example.com");
            securitySchema.flows = Map.of("password", Map.of("tokenUrl", tokenUrl));
            iterateOverBuilders(b -> b.builder.addSecurityComponent(name, securitySchema));
        }
    }

    @Override
    public void secureAllEntities(String securitySchemaName) {
        if (configurationService.isOpenapiSchema()) {
            API_INITIALIZER_LISTENER.add(() -> {
                iterateOverBuilders(b -> b.builder.secureAllEntityPaths(securitySchemaName));
            });
        }
    }

    private void iterateOverBuilders(Consumer<OpenAPIFile> c) {
        this.builders.values().forEach(c);
    }

    static class GeminiServiceInfoWrapper {

        public OpenAPIBuilder.Info info;
    }

    static class OpenAPIFile {

        OpenAPIBuilder builder;

        String key;

        String fileName;

        public OpenAPIFile(OpenAPIBuilder builder, String key, String fileName) {
            this.builder = builder;
            this.key = key;
            this.fileName = fileName;
        }

        static OpenAPIFile from(OpenAPIBuilder builder, String key, String fileName) {
            return new OpenAPIFile(builder, key, fileName);
        }
    }
}


{
        Resource defaultInfoService = context.getResource(SERVICE_INFO_DEFAULT_RESOURCE);
        serviceInfoResource.getParentFile().mkdirs();
        Files.copy(defaultInfoService.getInputStream(), serviceInfoResource.toPath(), StandardCopyOption.REPLACE_EXISTING);
    }

package it.at7.gemini.api.openapi;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import it.at7.gemini.conf.State;
import it.at7.gemini.core.*;
import it.at7.gemini.exceptions.GeminiException;
import it.at7.gemini.exceptions.GeminiRuntimeException;
import it.at7.gemini.schema.Entity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

@Service
public class OpenApiServiceImpl implements OpenApiService, StateListener {

    private static final String SERVICE_INFO_DEFAULT_RESOURCE = "classpath:/service/default-info.yml";

    private final GeminiConfigurationService configurationService;

    private final StateManager stateManager;

    private final SchemaManager schemaManager;

    private final Environment environment;

    private final ApplicationContext context;

    private List<Runnable> API_INITIALIZER_LISTENER = new ArrayList<>();

    private Map<String, OpenAPIFile> builders = new HashMap<>();

    @Autowired
    public OpenApiServiceImpl(GeminiConfigurationService configurationService, StateManager stateManager, SchemaManager schemaManager, Environment environment, ApplicationContext context) {
        this.configurationService = configurationService;
        this.stateManager = stateManager;
        this.schemaManager = schemaManager;
        this.environment = environment;
        this.context = context;
        if (configurationService.isOpenapiSchema()) {
            this.stateManager.register(this);
            // openapi spec withRecord all entities
            builders.put("ALL", OpenAPIFile.from(new OpenAPIBuilder(), "ALL", "all.json"));
            // entities by module... in each dedicated file
            schemaManager.getAllModules().forEach(m -> {
                String moduleName = m.getName().toUpperCase();
                builders.put(moduleName, OpenAPIFile.from(new OpenAPIBuilder(false), moduleName, moduleName.toLowerCase() + ".json"));
            });
        }
    }

    private void createDefaultServiceInfoResource(File serviceInfoResource) throws IOException

    @Override
    public void onChange(State previous, State actual, Optional<Transaction> transaction) throws GeminiException {
        if (configurationService.isOpenapiSchema()) {
            switch(actual) {
                case API_INITIALIZATION:
                    loadServiceInfo();
                    makeOpenAPISchema();
                    break;
                case API_INITIALIZED:
                    API_INITIALIZER_LISTENER.forEach(Runnable::run);
                    String localPort = environment.getProperty("local.server.port");
                    iterateOverBuilders(b -> b.builder.addServer("http://127.0.0.1:" + localPort + "/api", "Local Server"));
                    iterateOverBuilders(b -> storeOpenAPISchema(b.builder, b.fileName));
                    break;
                default:
                    break;
            }
        }
    }

    private void loadServiceInfo() {
        try {
            File serviceInfoFile = new File(configurationService.getServiceInfoResource());
            if (!serviceInfoFile.exists()) {
                createDefaultServiceInfoResource(serviceInfoFile);
            }
            ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
            GeminiServiceInfoWrapper geminiService = mapper.readValue(serviceInfoFile, GeminiServiceInfoWrapper.class);
            iterateOverBuilders(b -> b.builder.addInfo(geminiService.info));
        } catch (IOException e) {
            throw new GeminiRuntimeException(e);
        }
    }

    private void makeOpenAPISchema() {
        Collection<Entity> allEntities = this.schemaManager.getAllEntities();
        Map<ModuleBase, List<Entity>> entitiesByModule = allEntities.stream().collect(Collectors.groupingBy(Entity::getModule));
        List<ModuleBase> orderedModules = entitiesByModule.keySet().stream().sorted(Comparator.comparingInt(ModuleBase::order)).collect(Collectors.toList());
        OpenAPIBuilder allEntityBuilder = this.builders.get("ALL").builder;
        allEntityBuilder.addModulesToTags(orderedModules);
        for (ModuleBase module : orderedModules) {
            List<Entity> entities = entitiesByModule.get(module);
            entities.forEach(allEntityBuilder::handleEntity);
            String moduleName = module.getName().toUpperCase();
            OpenAPIFile openAPIFile = this.builders.get(moduleName);
            assert openAPIFile != null;
            List<OpenAPIFile> otherOpenApiFiles = this.builders.values().stream().filter(f -> !f.key.equals(openAPIFile.key) && !f.key.equals("ALL")).collect(Collectors.toList());
            entities.forEach(e -> {
                openAPIFile.builder.handleEntity(e);
                otherOpenApiFiles.forEach(b -> b.builder.addComponentSchema(e, OpenAPIBuilder.SchemaType.ENTITY));
                if (!e.isEmbedable()) {
                    otherOpenApiFiles.forEach(b -> b.builder.addComponentSchema(e, OpenAPIBuilder.SchemaType.ENTITY_LK));
                }
            });
        }
    }

    private void storeOpenAPISchema(OpenAPIBuilder openAPIBuilder, String fileName) {
        String json = openAPIBuilder.toJsonString();
        try {
            String openApiDir = configurationService.getOpenApiDir();
            Path allPath = Paths.get(openApiDir, fileName);
            File file = new File(allPath.toString());
            file.getParentFile().mkdirs();
            Files.write(allPath, json.getBytes());
        } catch (IOException e) {
            throw new GeminiRuntimeException(e);
        }
    }

    @Override
    public void addOAuth2PasswordFlow(String name, Map<String, Object> flowParameters) {
        if (configurationService.isOpenapiSchema()) {
            String tokenUrl = (String) flowParameters.get("tokenUrl");
            if (tokenUrl == null || tokenUrl.equals("")) {
                throw new GeminiRuntimeException("Unable to initializeSmartModules OAuth2 Password Flow - No tokenUrl Provided");
            }
            OpenAPIBuilder.SecuritySchema securitySchema = new OpenAPIBuilder.SecuritySchema();
            securitySchema.type = "oauth2";
            securitySchema.description = (String) flowParameters.getOrDefault("description", "See http://example.com");
            securitySchema.flows = Map.of("password", Map.of("tokenUrl", tokenUrl));
            iterateOverBuilders(b -> b.builder.addSecurityComponent(name, securitySchema));
        }
    }

    @Override
    public void secureAllEntities(String securitySchemaName) {
        if (configurationService.isOpenapiSchema()) {
            API_INITIALIZER_LISTENER.add(() -> {
                iterateOverBuilders(b -> b.builder.secureAllEntityPaths(securitySchemaName));
            });
        }
    }

    private void iterateOverBuilders(Consumer<OpenAPIFile> c) {
        this.builders.values().forEach(c);
    }

    static class GeminiServiceInfoWrapper {

        public OpenAPIBuilder.Info info;
    }

    static class OpenAPIFile {

        OpenAPIBuilder builder;

        String key;

        String fileName;

        public OpenAPIFile(OpenAPIBuilder builder, String key, String fileName) {
            this.builder = builder;
            this.key = key;
            this.fileName = fileName;
        }

        static OpenAPIFile from(OpenAPIBuilder builder, String key, String fileName) {
            return new OpenAPIFile(builder, key, fileName);
        }
    }
}


package it.at7.gemini.api.openapi;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import it.at7.gemini.conf.State;
import it.at7.gemini.core.*;
import it.at7.gemini.exceptions.GeminiException;
import it.at7.gemini.exceptions.GeminiRuntimeException;
import it.at7.gemini.schema.Entity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

@Service
public class OpenApiServiceImpl implements OpenApiService, StateListener {

    private static final String SERVICE_INFO_DEFAULT_RESOURCE = "classpath:/service/default-info.yml";

    private final GeminiConfigurationService configurationService;

    private final StateManager stateManager;

    private final SchemaManager schemaManager;

    private final Environment environment;

    private final ApplicationContext context;

    private List<Runnable> API_INITIALIZER_LISTENER = new ArrayList<>();

    private Map<String, OpenAPIFile> builders = new HashMap<>();

    @Autowired
    public OpenApiServiceImpl(GeminiConfigurationService configurationService, StateManager stateManager, SchemaManager schemaManager, Environment environment, ApplicationContext context) {
        this.configurationService = configurationService;
        this.stateManager = stateManager;
        this.schemaManager = schemaManager;
        this.environment = environment;
        this.context = context;
        if (configurationService.isOpenapiSchema()) {
            this.stateManager.register(this);
            // openapi spec withRecord all entities
            builders.put("ALL", OpenAPIFile.from(new OpenAPIBuilder(), "ALL", "all.json"));
            // entities by module... in each dedicated file
            schemaManager.getAllModules().forEach(m -> {
                String moduleName = m.getName().toUpperCase();
                builders.put(moduleName, OpenAPIFile.from(new OpenAPIBuilder(false), moduleName, moduleName.toLowerCase() + ".json"));
            });
        }
    }

    private void createDefaultServiceInfoResource(File serviceInfoResource) throws IOException {
        Resource defaul

        serviceInfoResource.getParentFile().mkdirs();
        Files.copy(defaultInfoService.getInputStream(), serviceInfoResource.toPath(), StandardCopyOption.REPLACE_EXISTING);
    }

    @Override
    public void onChange(State previous, State actual, Optional<Transaction> transaction) throws GeminiException {
        if (configurationService.isOpenapiSchema()) {
            switch(actual) {
                case API_INITIALIZATION:
                    loadServiceInfo();
                    makeOpenAPISchema();
                    break;
                case API_INITIALIZED:
                    API_INITIALIZER_LISTENER.forEach(Runnable::run);
                    String localPort = environment.getProperty("local.server.port");
                    iterateOverBuilders(b -> b.builder.addServer("http://127.0.0.1:" + localPort + "/api", "Local Server"));
                    iterateOverBuilders(b -> storeOpenAPISchema(b.builder, b.fileName));
                    break;
                default:
                    break;
            }
        }
    }

    private void loadServiceInfo() {
        try {
            File serviceInfoFile = new File(configurationService.getServiceInfoResource());
            if (!serviceInfoFile.exists()) {
                createDefaultServiceInfoResource(serviceInfoFile);
            }
            ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
            GeminiServiceInfoWrapper geminiService = mapper.readValue(serviceInfoFile, GeminiServiceInfoWrapper.class);
            iterateOverBuilders(b -> b.builder.addInfo(geminiService.info));
        } catch (IOException e) {
            throw new GeminiRuntimeException(e);
        }
    }

    private void makeOpenAPISchema() {
        Collection<Entity> allEntities = this.schemaManager.getAllEntities();
        Map<ModuleBase, List<Entity>> entitiesByModule = allEntities.stream().collect(Collectors.groupingBy(Entity::getModule));
        List<ModuleBase> orderedModules = entitiesByModule.keySet().stream().sorted(Comparator.comparingInt(ModuleBase::order)).collect(Collectors.toList());
        OpenAPIBuilder allEntityBuilder = this.builders.get("ALL").builder;
        allEntityBuilder.addModulesToTags(orderedModules);
        for (ModuleBase module : orderedModules) {
            List<Entity> entities = entitiesByModule.get(module);
            entities.forEach(allEntityBuilder::handleEntity);
            String moduleName = module.getName().toUpperCase();
            OpenAPIFile openAPIFile = this.builders.get(moduleName);
            assert openAPIFile != null;
            List<OpenAPIFile> otherOpenApiFiles = this.builders.values().stream().filter(f -> !f.key.equals(openAPIFile.key) && !f.key.equals("ALL")).collect(Collectors.toList());
            entities.forEach(e -> {
                openAPIFile.builder.handleEntity(e);
                otherOpenApiFiles.forEach(b -> b.builder.addComponentSchema(e, OpenAPIBuilder.SchemaType.ENTITY));
                if (!e.isEmbedable()) {
                    otherOpenApiFiles.forEach(b -> b.builder.addComponentSchema(e, OpenAPIBuilder.SchemaType.ENTITY_LK));
                }
            });
        }
    }

    private void storeOpenAPISchema(OpenAPIBuilder openAPIBuilder, String fileName) {
        String json = openAPIBuilder.toJsonString();
        try {
            String openApiDir = configurationService.getOpenApiDir();
            Path allPath = Paths.get(openApiDir, fileName);
            File file = new File(allPath.toString());
            file.getParentFile().mkdirs();
            Files.write(allPath, json.getBytes());
        } catch (IOException e) {
            throw new GeminiRuntimeException(e);
        }
    }

    @Override
    public void addOAuth2PasswordFlow(String name, Map<String, Object> flowParameters) {
        if (configurationService.isOpenapiSchema()) {
            String tokenUrl = (String) flowParameters.get("tokenUrl");
            if (tokenUrl == null || tokenUrl.equals("")) {
                throw new GeminiRuntimeException("Unable to initializeSmartModules OAuth2 Password Flow - No tokenUrl Provided");
            }
            OpenAPIBuilder.SecuritySchema securitySchema = new OpenAPIBuilder.SecuritySchema();
            securitySchema.type = "oauth2";
            securitySchema.description = (String) flowParameters.getOrDefault("description", "See http://example.com");
            securitySchema.flows = Map.of("password", Map.of("tokenUrl", tokenUrl));
            iterateOverBuilders(b -> b.builder.addSecurityComponent(name, securitySchema));
        }
    }

    @Override
    public void secureAllEntities(String securitySchemaName) {
        if (configurationService.isOpenapiSchema()) {
            API_INITIALIZER_LISTENER.add(() -> {
                iterateOverBuilders(b -> b.builder.secureAllEntityPaths(securitySchemaName));
            });
        }
    }

    private void iterateOverBuilders(Consumer<OpenAPIFile> c) {
        this.builders.values().forEach(c);
    }

    static class GeminiServiceInfoWrapper {

        public OpenAPIBuilder.Info info;
    }

    static class OpenAPIFile {

        OpenAPIBuilder builder;

        String key;

        String fileName;

        public OpenAPIFile(OpenAPIBuilder builder, String key, String fileName) {
            this.builder = builder;
            this.key = key;
            this.fileName = fileName;
        }

        static OpenAPIFile from(OpenAPIBuilder builder, String key, String fileName) {
            return new OpenAPIFile(builder, key, fileName);
        }
    }
}


try {
            String openApiDir = configurationService.getOpenApiDir();
            Path allPath = Paths.get(openApiDir, fileName);
            File file = new File(allPath.toString());
            file.getParentFile().mkdirs();
            Files.write(allPath, json.getBytes());
        } catch (IOException e) {
            throw new GeminiRuntimeException(e);
        }

package it.at7.gemini.api.openapi;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import it.at7.gemini.conf.State;
import it.at7.gemini.core.*;
import it.at7.gemini.exceptions.GeminiException;
import it.at7.gemini.exceptions.GeminiRuntimeException;
import it.at7.gemini.schema.Entity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

@Service
public class OpenApiServiceImpl implements OpenApiService, StateListener {

    private static final String SERVICE_INFO_DEFAULT_RESOURCE = "classpath:/service/default-info.yml";

    private final GeminiConfigurationService configurationService;

    private final StateManager stateManager;

    private final SchemaManager schemaManager;

    private final Environment environment;

    private final ApplicationContext context;

    private List<Runnable> API_INITIALIZER_LISTENER = new ArrayList<>();

    private Map<String, OpenAPIFile> builders = new HashMap<>();

    @Autowired
    public OpenApiServiceImpl(GeminiConfigurationService configurationService, StateManager stateManager, SchemaManager schemaManager, Environment environment, ApplicationContext context) {
        this.configurationService = configurationService;
        this.stateManager = stateManager;
        this.schemaManager = schemaManager;
        this.environment = environment;
        this.context = context;
        if (configurationService.isOpenapiSchema()) {
            this.stateManager.register(this);
            // openapi spec withRecord all entities
            builders.put("ALL", OpenAPIFile.from(new OpenAPIBuilder(), "ALL", "all.json"));
            // entities by module... in each dedicated file
            schemaManager.getAllModules().forEach(m -> {
                String moduleName = m.getName().toUpperCase();
                builders.put(moduleName, OpenAPIFile.from(new OpenAPIBuilder(false), moduleName, moduleName.toLowerCase() + ".json"));
            });
        }
    }

    private void createDefaultServiceInfoResource(File serviceInfoResource) throws IOException {
        Resource defaultInfoService = context.getResource(SERVICE_INFO_DEFAULT_RESOURCE);
        serviceInfoResource.getParentFile().mkdirs();
        Files.copy(defaultInfoService.getInputStream(), serviceInfoResource.toPath(), StandardCopyOption.REPLACE_EXISTING);
    }

    @Override
    public void onChange(State previous, State actual, Optional<Transaction> transaction) throws GeminiException {
        if (configurationService.isOpenapiSchema()) {
            switch(actual) {
                case API_INITIALIZATION:
                    loadServiceInfo();
                    makeOpenAPISchema();
                    break;
                case API_INITIALIZED:
                    API_INITIALIZER_LISTENER.forEach(Runnable::run);
                    String localPort = environment.getProperty("local.server.port");
                    iterateOverBuilders(b -> b.builder.addServer("http://127.0.0.1:" + localPort + "/api", "Local Server"));
                    iterateOverBuilders(b -> storeOpenAPISchema(b.builder, b.fileName));
                    break;
                default:
                    break;
            }
        }
    }

    private void loadServiceInfo() {
        try {
            File serviceInfoFile = new File(configurationService.getServiceInfoResource());
            if (!serviceInfoFile.exists()) {
                createDefaultServiceInfoResource(serviceInfoFile);
            }
            ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
            GeminiServiceInfoWrapper geminiService = mapper.readValue(serviceInfoFile, GeminiServiceInfoWrapper.class);
            iterateOverBuilders(b -> b.builder.addInfo(geminiService.info));
        } catch (IOException e) {
            throw new GeminiRuntimeException(e);
        }
    }

    private void makeOpenAPISchema() {
        Collection<Entity> allEntities = this.schemaManager.getAllEntities();
        Map<ModuleBase, List<Entity>> entitiesByModule = allEntities.stream().collect(Collectors.groupingBy(Entity::getModule));
        List<ModuleBase> orderedModules = entitiesByModule.keySet().stream().sorted(Comparator.comparingInt(ModuleBase::order)).collect(Collectors.toList());
        OpenAPIBuilder allEntityBuilder = this.builders.get("ALL").builder;
        allEntityBuilder.addModulesToTags(orderedModules);
        for (ModuleBase module : orderedModules) {
            List<Entity> entities = entitiesByModule.get(module);
            entities.forEach(allEntityBuilder::handleEntity);
            String moduleName = module.getName().toUpperCase();
            OpenAPIFile openAPIFile = this.builders.get(moduleName);
            assert openAPIFile != null;
            List<OpenAPIFile> otherOpenApiFiles = this.builders.values().stream().filter(f -> !f.key.equals(openAPIFile.key) && !f.key.equals("ALL")).collect(Collectors.toList());
            entities.forEach(e -> {
                openAPIFile.builder.handleEntity(e);
                otherOpenApiFiles.forEach(b -> b.builder.addComponentSchema(e, OpenAPIBuilder.SchemaType.ENTITY));
                if (!e.isEmbedable()) {
                    otherOpenApiFiles.forEach(b -> b.builder.addComponentSchema(e, OpenAPIBuilder.SchemaType.ENTITY_LK));
                }
            });
        }
    }

    private void storeOpenAPISchema(OpenAPIBuilder openAPIBuilder, String fileName) {
        String json = openAPIBuilder.toJsonString();

    }

    @Override
    public void addOAuth2PasswordFlow(String name, Map<String, Object> flowParameters) {
        if (configurationService.isOpenapiSchema()) {
            String tokenUrl = (String) flowParameters.get("tokenUrl");
            if (tokenUrl == null || tokenUrl.equals("")) {
                throw new GeminiRuntimeException("Unable to initializeSmartModules OAuth2 Password Flow - No tokenUrl Provided");
            }
            OpenAPIBuilder.SecuritySchema securitySchema = new OpenAPIBuilder.SecuritySchema();
            securitySchema.type = "oauth2";
            securitySchema.description = (String) flowParameters.getOrDefault("description", "See http://example.com");
            securitySchema.flows = Map.of("password", Map.of("tokenUrl", tokenUrl));
            iterateOverBuilders(b -> b.builder.addSecurityComponent(name, securitySchema));
        }
    }

    @Override
    public void secureAllEntities(String securitySchemaName) {
        if (configurationService.isOpenapiSchema()) {
            API_INITIALIZER_LISTENER.add(() -> {
                iterateOverBuilders(b -> b.builder.secureAllEntityPaths(securitySchemaName));
            });
        }
    }

    private void iterateOverBuilders(Consumer<OpenAPIFile> c) {
        this.builders.values().forEach(c);
    }

    static class GeminiServiceInfoWrapper {

        public OpenAPIBuilder.Info info;
    }

    static class OpenAPIFile {

        OpenAPIBuilder builder;

        String key;

        String fileName;

        public OpenAPIFile(OpenAPIBuilder builder, String key, String fileName) {
            this.builder = builder;
            this.key = key;
            this.fileName = fileName;
        }

        static OpenAPIFile from(OpenAPIBuilder builder, String key, String fileName) {
            return new OpenAPIFile(builder, key, fileName);
        }
    }
}


@Override
    public Class mapType(Object object)

/**
 * ****************************************************************************
 *
 *  Contributors:
 *      IBM Corporation - initial API and implementation
 * *****************************************************************************
 */
package org.eclipse.ui.views.properties.tabbed;

/**
 * Default implementation of a type mapper.
 *
 * @author Anthony Hunter
 */
public class AbstractTypeMapper implements ITypeMapper {

{
        return object.getClass();
    }
}


{
        return object.getClass();
    }

/**
 * ****************************************************************************
 *
 *  Contributors:
 *      IBM Corporation - initial API and implementation
 * *****************************************************************************
 */
package org.eclipse.ui.views.properties.tabbed;

/**
 * Default implementation of a type mapper.
 *
 * @author Anthony Hunter
 */
public class AbstractTypeMapper implements ITypeMapper {

    @Override
    public Class mapType(Object object)


/**
 * ****************************************************************************
 *
 *  Contributors:
 *      IBM Corporation - initial API and implementation
 * *****************************************************************************
 */
package org.eclipse.ui.views.properties.tabbed;

/**
 * Default implementation of a type mapper.
 *
 * @author Anthony Hunter
 */
public class AbstractTypeMapper implements ITypeMapper {

    @Override
    public Class mapType(Object object) {
        return object.getCla


@Query("select ep from ExternalPaper ep where ep.vote.id = :vid")
    ExternalPaper findByVid(int vid);

package com.softeng.dingtalk.repository;

import com.softeng.dingtalk.entity.ExternalPaper;
import com.softeng.dingtalk.entity.Vote;
import org.springframework.data.jpa.repository.Query;

public interface ExternalPaperRepository extends CustomizedRepository<ExternalPaper, Integer> {

    /**
     * 查询对应指定投票id的外部论文
     * @param vid
     * @return
     */

    /**
     * 查询指定论文的投票
     * @param id
     * @return
     */
    @Query("select ep.vote from ExternalPaper ep where ep.id = :id")
    Vote findVoteById(int id);
}


package com.coderbd.ex70.logicalproblems.ex2;

/**
 * @author J2EE-33
 */
public class Complexloop {

{
        System.out.print(c);
        return true;
    }

    public static void main(String[] argv) {
        int i = 0;
        for (foo('A'); foo('B') && (i < 2); foo('C')) {
            i++;
            foo('D');
        }
    }
}


package com.coderbd.ex70.logicalproblems.ex2;

/**
 * @author J2EE-33
 */
public class Complexloop {

    static boolean foo(char c) {
        System.out.print(c);
        return true;
    }

    public static void main(String[] argv)


package com.coderbd.ex70.logicalproblems.ex2;

/**
 * @author J2EE-33
 */
public class Complexloop {

    static boolean foo(char c) {
        System.

        return true;
    }

    public static void main(String[] argv) {
        int i = 0;
        for (foo('A'); foo('B') && (i < 2); foo('C')) {
            i++;
            foo('D');
        }
    }
}


package com.coderbd.ex70.logicalproblems.ex2;

/**
 * @author J2EE-33
 */
public class Complexloop {

    static boolean foo(char c) {
        System.out.print(c);
        return true;
    }

    public static void main(String[] argv) {
        int i = 0;


private static URI genMemFileUri(String fileName, String pkg)

/**
 * ****************************************************************************
 *
 *  Contributors:
 *      pf-miles - initial API and implementation
 * ****************************************************************************
 */
package com.github.pfmiles.kanjava;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.net.URI;
import javax.tools.SimpleJavaFileObject;
import com.github.pfmiles.kanjava.compile.DynaCompileUtil;

/**
 * 用作编译时以string形式传入java源文件
 *
 * @author pf_miles
 */
public class JavaSourceFile extends SimpleJavaFileObject {

    private String fileName;

    private String code;

    /**
     * 创建内存java源码文件
     *
     * @param fileName
     *            文件名, 如:Test.java
     * @param pkg
     *            类所属包名, 如:com.test
     * @param code
     *            代码
     */
    public JavaSourceFile(String fileName, String pkg, String code) {
        super(genMemFileUri(fileName, pkg), Kind.SOURCE);
        this.fileName = fileName;
        this.code = code;
    }

{
        String pkgPath = "";
        if (DynaCompileUtil.isNotBlank(pkg))
            pkgPath = pkg.replaceAll("\\.", "/") + "/";
        return URI.create("mem:///src/" + pkgPath + fileName);
    }

    public String getName() {
        return this.fileName;
    }

    public InputStream openInputStream() throws IOException {
        return new ByteArrayInputStream(this.code.getBytes("UTF-8"));
    }

    public OutputStream openOutputStream() throws IOException {
        throw new UnsupportedOperationException();
    }

    public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
        return new BufferedReader(new InputStreamReader(this.openInputStream()));
    }

    public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
        return this.code;
    }

    public Writer openWriter() throws IOException {
        throw new UnsupportedOperationException();
    }

    public boolean delete() {
        throw new UnsupportedOperationException();
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String toString() {
        return uri.toString();
    }

    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((uri == null) ? 0 : uri.hashCode());
        return result;
    }

    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        JavaSourceFile other = (JavaSourceFile) obj;
        if (uri == null) {
            if (other.toUri() != null)
                return false;
        } else if (!uri.equals(other.toUri()))
            return false;
        return true;
    }
}


/**
 * ****************************************************************************
 *
 *  Contributors:
 *      pf-miles - initial API and implementation
 * ****************************************************************************
 */
package com.github.pfmiles.kanjava;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.net.URI;
import javax.tools.SimpleJavaFileObject;
import com.github.pfmiles.kanjava.compile.DynaCompileUtil;

/**
 * 用作编译时以string形式传入java源文件
 *
 * @author pf_miles
 */
public class JavaSourceFile extends SimpleJavaFileObject {

    private String fileName;

    private String code;

    /**
     * 创建内存java源码文件
     *
     * @param fileName
     *            文件名, 如:Test.java
     * @param pkg
     *            类所属包名, 如:com.test
     * @param code
     *            代码
     */
    public JavaSourceFile(String fileName, String pkg, String code) {
        super(genMemFileUri(fileName, pkg), Kind.SOURCE);
        this.fileName = fileName;
        this.code = code;
    }

    private static URI genMemFileUri(String fileName, String pkg) {
        String pkgPath = "";
        if (DynaCompileUtil.isNotBlank(pkg))
            pkgPath = pkg.replaceAll("\\.", "/") + "/";
        return URI.create("mem:///src/" + pkgPath + fileName);
    }

    public String getName() {
        return this.fileName;
    }

    public InputStream openInputStream() throws IOException {
        return new ByteArrayInputStream(this.code.getBytes("UTF-8"));
    }

    public OutputStream openOutputStream() throws IOException {
        throw new UnsupportedOperationException();
    }

    public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
        return new BufferedReader(new InputStreamReader(this.openInputStream()));
    }

    public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
        return this.code;
    }

    public Writer openWriter() throws IOException {
        throw new UnsupportedOperationException();
    }

    public boolean delete()

    public void setCode(String code) {
        this.code = code;
    }

    public String toString() {
        return uri.toString();
    }

    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((uri == null) ? 0 : uri.hashCode());
        return result;
    }

    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        JavaSourceFile other = (JavaSourceFile) obj;
        if (uri == null) {
            if (other.toUri() != null)
                return false;
        } else if (!uri.equals(other.toUri()))
            return false;
        return true;
    }
}


/**
 * ****************************************************************************
 *
 *  Contributors:
 *      pf-miles - initial API and implementation
 * ****************************************************************************
 */
package com.github.pfmiles.kanjava;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.net.URI;
import javax.tools.SimpleJavaFileObject;
import com.github.pfmiles.kanjava.compile.DynaCompileUtil;

/**
 * 用作编译时以string形式传入java源文件
 *
 * @author pf_miles
 */
public class JavaSourceFile extends SimpleJavaFileObject {

    private String fileName;

    private String code;

    /**
     * 创建内存java源码文件
     *
     * @param fileName
     *            文件名, 如:Test.java
     * @param pkg
     *            类所属包名, 如:com.test
     * @param code
     *            代码
     */
    public JavaSourceFile(String fileName, String pkg, String code) {
        super(genMemFileUri(fileName, pkg), Kind.SOURCE);
        this.fileName = fileName;
        this.code = code;
    }

    private static URI genMemFileUri(String fileName, String pkg) {
        String pkgPa

        if (DynaCompileUtil.isNotBlank(pkg))
            pkgPath = pkg.replaceAll("\\.", "/") + "/";
        return URI.create("mem:///src/" + pkgPath + fileName);
    }

    public String getName() {
        return this.fileName;
    }

    public InputStream openInputStream() throws IOException {
        return new ByteArrayInputStream(this.code.getBytes("UTF-8"));
    }

    public OutputStream openOutputStream() throws IOException {
        throw new UnsupportedOperationException();
    }

    public Reader openReader(boolean ignoreEncodingErrors) throws IOException {
        return new BufferedReader(new InputStreamReader(this.openInputStream()));
    }

    public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
        return this.code;
    }

    public Writer openWriter() throws IOException {
        throw new UnsupportedOperationException();
    }

    public boolean delete() {
        throw new UnsupportedOperationException();
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String toString() {
        return uri.toString();
    }

    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((uri == null) ? 0 : uri.hashCode());
        return result;
    }

    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        JavaSourceFile other = (JavaSourceFile) obj;
        if (uri == null) {
            if (other.toUri() != null)
                return false;
        } else if (!uri.equals(other.toUri()))
            return false;
        return true;
    }
}


@Internal
    public JdiModelTargetModule libraryLoaded(String name)

package ghidra.dbg.jdi.model;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import com.sun.jdi.ModuleReference;
import ghidra.async.AsyncFence;
import ghidra.async.AsyncUtils;
import ghidra.dbg.error.DebuggerUserException;
import ghidra.dbg.target.TargetModule;
import ghidra.dbg.target.TargetModuleContainer;
import ghidra.dbg.target.schema.*;
import ghidra.dbg.target.schema.TargetObjectSchema.ResyncMode;
import ghidra.lifecycle.Internal;
import ghidra.util.Msg;

@TargetObjectSchemaInfo(name = "TargetModuleContainer", elements = { @TargetElementType(type = JdiModelTargetModule.class) }, elementResync = ResyncMode.ONCE, attributes = { @TargetAttributeType(type = Void.class) }, canonicalContainer = true)
public class JdiModelTargetModuleContainer extends JdiModelTargetObjectImpl implements TargetModuleContainer {

    protected final JdiModelTargetVM vm;

    // TODO: Is it possible to load the same object twice?
    protected final Map<String, JdiModelTargetModule> modulesByName = new HashMap<>();

    public JdiModelTargetModuleContainer(JdiModelTargetVM vm) {
        super(vm, "Modules");
        this.vm = vm;
    }

{
        List<ModuleReference> allModules = vm.vm.allModules();
        for (ModuleReference ref : allModules) {
            if (JdiModelTargetModule.getUniqueId(ref).equals(name)) {
                JdiModelTargetModule module = getTargetModule(ref);
                changeElements(List.of(), List.of(module), Map.of(), "Loaded");
                return module;
            }
        }
        return null;
    }

    @Internal
    public void libraryUnloaded(String name) {
        synchronized (this) {
            modulesByName.remove(name);
        }
        changeElements(List.of(name), List.of(), Map.of(), "Unloaded");
    }

    @Override
    public boolean supportsSyntheticModules() {
        return false;
    }

    @Override
    public CompletableFuture<? extends TargetModule> addSyntheticModule(String name) {
        throw new DebuggerUserException("GDB Does not support synthetic modules");
    }

    protected CompletableFuture<Void> updateUsingModules(Map<String, ModuleReference> byName) {
        List<JdiModelTargetModule> modules;
        synchronized (this) {
            modules = byName.values().stream().map(this::getTargetModule).collect(Collectors.toList());
        }
        AsyncFence fence = new AsyncFence();
        for (JdiModelTargetModule mod : modules) {
            fence.include(mod.init());
        }
        return fence.ready().thenAccept(__ -> {
            changeElements(List.of(), modules, Map.of(), "Refreshed");
        });
    }

    @Override
    protected CompletableFuture<Void> requestElements(boolean refresh) {
        return doRefresh();
    }

    protected CompletableFuture<Void> doRefresh() {
        Map<String, ModuleReference> map = new HashMap<>();
        List<ModuleReference> allModules = vm.vm.allModules();
        for (ModuleReference ref : allModules) {
            map.put(JdiModelTargetModule.getUniqueId(ref), ref);
        }
        modulesByName.keySet().retainAll(map.keySet());
        return updateUsingModules(map);
    }

    protected synchronized JdiModelTargetModule getTargetModule(ModuleReference module) {
        return modulesByName.computeIfAbsent(JdiModelTargetModule.getUniqueId(module), n -> new JdiModelTargetModule(this, module, true));
    }

    public synchronized JdiModelTargetModule getTargetModuleIfPresent(String name) {
        return modulesByName.get(name);
    }

    public CompletableFuture<?> refreshInternal() {
        if (!isObserved()) {
            return AsyncUtils.NIL;
        }
        return doRefresh().exceptionally(ex -> {
            Msg.error(this, "Problem refreshing inferior's modules", ex);
            return null;
        });
    }
}


{
        synchronized (this) {
            modulesByName.remove(name);
        }
        changeElements(List.of(name), List.of(), Map.of(), "Unloaded");
    }

package ghidra.dbg.jdi.model;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import com.sun.jdi.ModuleReference;
import ghidra.async.AsyncFence;
import ghidra.async.AsyncUtils;
import ghidra.dbg.error.DebuggerUserException;
import ghidra.dbg.target.TargetModule;
import ghidra.dbg.target.TargetModuleContainer;
import ghidra.dbg.target.schema.*;
import ghidra.dbg.target.schema.TargetObjectSchema.ResyncMode;
import ghidra.lifecycle.Internal;
import ghidra.util.Msg;

@TargetObjectSchemaInfo(name = "TargetModuleContainer", elements = { @TargetElementType(type = JdiModelTargetModule.class) }, elementResync = ResyncMode.ONCE, attributes = { @TargetAttributeType(type = Void.class) }, canonicalContainer = true)
public class JdiModelTargetModuleContainer extends JdiModelTargetObjectImpl implements TargetModuleContainer {

    protected final JdiModelTargetVM vm;

    // TODO: Is it possible to load the same object twice?
    protected final Map<String, JdiModelTargetModule> modulesByName = new HashMap<>();

    public JdiModelTargetModuleContainer(JdiModelTargetVM vm) {
        super(vm, "Modules");
        this.vm = vm;
    }

    @Internal
    public JdiModelTargetModule libraryLoaded(String name) {
        List<ModuleReference> allModules = vm.vm.allModules();
        for (ModuleReference ref : allModules) {
            if (JdiModelTargetModule.getUniqueId(ref).equals(name)) {
                JdiModelTargetModule module = getTargetModule(ref);
                changeElements(List.of(), List.of(module), Map.of(), "Loaded");
                return module;
            }
        }
        return null;
    }

    @Internal
    public void libraryUnloaded(String name)

    @Override
    public boolean supportsSyntheticModules() {
        return false;
    }

    @Override
    public CompletableFuture<? extends TargetModule> addSyntheticModule(String name) {
        throw new DebuggerUserException("GDB Does not support synthetic modules");
    }

    protected CompletableFuture<Void> updateUsingModules(Map<String, ModuleReference> byName) {
        List<JdiModelTargetModule> modules;
        synchronized (this) {
            modules = byName.values().stream().map(this::getTargetModule).collect(Collectors.toList());
        }
        AsyncFence fence = new AsyncFence();
        for (JdiModelTargetModule mod : modules) {
            fence.include(mod.init());
        }
        return fence.ready().thenAccept(__ -> {
            changeElements(List.of(), modules, Map.of(), "Refreshed");
        });
    }

    @Override
    protected CompletableFuture<Void> requestElements(boolean refresh) {
        return doRefresh();
    }

    protected CompletableFuture<Void> doRefresh() {
        Map<String, ModuleReference> map = new HashMap<>();
        List<ModuleReference> allModules = vm.vm.allModules();
        for (ModuleReference ref : allModules) {
            map.put(JdiModelTargetModule.getUniqueId(ref), ref);
        }
        modulesByName.keySet().retainAll(map.keySet());
        return updateUsingModules(map);
    }

    protected synchronized JdiModelTargetModule getTargetModule(ModuleReference module) {
        return modulesByName.computeIfAbsent(JdiModelTargetModule.getUniqueId(module), n -> new JdiModelTargetModule(this, module, true));
    }

    public synchronized JdiModelTargetModule getTargetModuleIfPresent(String name) {
        return modulesByName.get(name);
    }

    public CompletableFuture<?> refreshInternal() {
        if (!isObserved()) {
            return AsyncUtils.NIL;
        }
        return doRefresh().exceptionally(ex -> {
            Msg.error(this, "Problem refreshing inferior's modules", ex);
            return null;
        });
    }
}


package ghidra.dbg.jdi.model;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import com.sun.jdi.ModuleReference;
import ghidra.async.AsyncFence;
import ghidra.async.AsyncUtils;
import ghidra.dbg.error.DebuggerUserException;
import ghidra.dbg.target.TargetModule;
import ghidra.dbg.target.TargetModuleContainer;
import ghidra.dbg.target.schema.*;
import ghidra.dbg.target.schema.TargetObjectSchema.ResyncMode;
import ghidra.lifecycle.Internal;
import ghidra.util.Msg;

@TargetObjectSchemaInfo(name = "TargetModuleContainer", elements = { @TargetElementType(type = JdiModelTargetModule.class) }, elementResync = ResyncMode.ONCE, attributes = { @TargetAttributeType(type = Void.class) }, canonicalContainer = true)
public class JdiModelTargetModuleContainer extends JdiModelTargetObjectImpl implements TargetModuleContainer {

    protected final JdiModelTargetVM vm;

    // TODO: Is it possible to load the same object twice?
    protected final Map<String, JdiModelTargetModule> modulesByName = new HashMap<>();

    public JdiModelTargetModuleContainer(JdiModelTargetVM vm) {
        super(vm, "Modules");
        this.vm = vm;
    }

    @Internal
    public JdiModelTargetModule libraryLoaded(String name) {
        List<ModuleReference> allModules = vm.vm.allModules();
        for (ModuleReference ref : allModules) {
            if (JdiModelTargetModule.getUniqueId(ref).equals(name)) {
                JdiModelTargetModule module = getTargetModule(ref);
                changeElements(List.of(), List.of(module), Map.of(), "Loaded");
                return module;
            }
        }
        return null;
    }

    @Internal
    public void libraryUnloaded(String name) {
        synchronized (this) {
            modulesByName.remove(name);
        }
        changeElements(List.of(name), List.of(), Map.of(), "Unloaded");
    }

    @Override
    public boolean supportsSyntheticModules() {
        return f

    }

    @Override
    public CompletableFuture<? extends TargetModule> addSyntheticModule(String name) {
        throw new DebuggerUserException("GDB Does not support synthetic modules");
    }

    protected CompletableFuture<Void> updateUsingModules(Map<String, ModuleReference> byName) {
        List<JdiModelTargetModule> modules;
        synchronized (this) {
            modules = byName.values().stream().map(this::getTargetModule).collect(Collectors.toList());
        }
        AsyncFence fence = new AsyncFence();
        for (JdiModelTargetModule mod : modules) {
            fence.include(mod.init());
        }
        return fence.ready().thenAccept(__ -> {
            changeElements(List.of(), modules, Map.of(), "Refreshed");
        });
    }

    @Override
    protected CompletableFuture<Void> requestElements(boolean refresh) {
        return doRefresh();
    }

    protected CompletableFuture<Void> doRefresh() {
        Map<String, ModuleReference> map = new HashMap<>();
        List<ModuleReference> allModules = vm.vm.allModules();
        for (ModuleReference ref : allModules) {
            map.put(JdiModelTargetModule.getUniqueId(ref), ref);
        }
        modulesByName.keySet().retainAll(map.keySet());
        return updateUsingModules(map);
    }

    protected synchronized JdiModelTargetModule getTargetModule(ModuleReference module) {
        return modulesByName.computeIfAbsent(JdiModelTargetModule.getUniqueId(module), n -> new JdiModelTargetModule(this, module, true));
    }

    public synchronized JdiModelTargetModule getTargetModuleIfPresent(String name) {
        return modulesByName.get(name);
    }

    public CompletableFuture<?> refreshInternal() {
        if (!isObserved()) {
            return AsyncUtils.NIL;
        }
        return doRefresh().exceptionally(ex -> {
            Msg.error(this, "Problem refreshing inferior's modules", ex);
            return null;
        });
    }
}